pact_broker 2.107.1 → 2.108.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/Gemfile +5 -4
  4. data/README.md +1 -0
  5. data/db/migrations/20230615_add_integrations_contract_data_updated_at.rb +13 -0
  6. data/db/migrations/20230616_set_integrations_contract_data_updated_at.rb +11 -0
  7. data/db/migrations/20231002_add_version_id_index_to_released_version.rb +21 -0
  8. data/db/migrations/20231003_add_version_id_index_to_deployed_version.rb +21 -0
  9. data/docs/CONFIGURATION.md +10 -0
  10. data/lib/pact_broker/api/contracts/base_contract.rb +2 -1
  11. data/lib/pact_broker/api/contracts/dry_validation_errors_formatter.rb +2 -0
  12. data/lib/pact_broker/api/contracts/pagination_query_params_schema.rb +19 -0
  13. data/lib/pact_broker/api/contracts/publish_contracts_contract_contract.rb +29 -18
  14. data/lib/pact_broker/api/decorators/base_decorator.rb +40 -1
  15. data/lib/pact_broker/api/decorators/branch_decorator.rb +35 -0
  16. data/lib/pact_broker/api/decorators/branch_version_decorator.rb +16 -0
  17. data/lib/pact_broker/api/decorators/configuration.rb +19 -0
  18. data/lib/pact_broker/api/decorators/custom_error_problem_json_decorator.rb +1 -1
  19. data/lib/pact_broker/api/decorators/decorator_context_creator.rb +47 -2
  20. data/lib/pact_broker/api/decorators/deployed_version_decorator.rb +2 -1
  21. data/lib/pact_broker/api/decorators/deployed_versions_decorator.rb +2 -2
  22. data/lib/pact_broker/api/decorators/dry_validation_errors_decorator.rb +32 -0
  23. data/lib/pact_broker/api/decorators/dry_validation_errors_problem_json_decorator.rb +24 -0
  24. data/lib/pact_broker/api/decorators/embedded_branch_version_decorator.rb +2 -2
  25. data/lib/pact_broker/api/decorators/embedded_deployed_version_decorator.rb +30 -0
  26. data/lib/pact_broker/api/decorators/embedded_error_problem_json_decorator.rb +84 -0
  27. data/lib/pact_broker/api/decorators/embedded_released_version_decorator.rb +27 -0
  28. data/lib/pact_broker/api/decorators/embedded_version_decorator.rb +0 -3
  29. data/lib/pact_broker/api/decorators/error_decorator.rb +30 -0
  30. data/lib/pact_broker/api/decorators/extended_pact_decorator.rb +6 -1
  31. data/lib/pact_broker/api/decorators/integration_decorator.rb +3 -2
  32. data/lib/pact_broker/api/decorators/integrations_decorator.rb +3 -0
  33. data/lib/pact_broker/api/decorators/notices_decorator.rb +11 -0
  34. data/lib/pact_broker/api/decorators/pact_pacticipant_decorator.rb +1 -5
  35. data/lib/pact_broker/api/decorators/pact_versions_decorator.rb +0 -1
  36. data/lib/pact_broker/api/decorators/pact_webhooks_status_decorator.rb +0 -1
  37. data/lib/pact_broker/api/decorators/pacticipant_branches_decorator.rb +32 -0
  38. data/lib/pact_broker/api/decorators/pacticipant_decorator.rb +11 -1
  39. data/lib/pact_broker/api/decorators/{pacticipant_collection_decorator.rb → pacticipants_decorator.rb} +8 -4
  40. data/lib/pact_broker/api/decorators/pagination_links.rb +2 -2
  41. data/lib/pact_broker/api/decorators/released_versions_decorator.rb +2 -2
  42. data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +2 -2
  43. data/lib/pact_broker/api/decorators/validation_errors_decorator.rb +30 -0
  44. data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +4 -6
  45. data/lib/pact_broker/api/decorators/version_decorator.rb +5 -3
  46. data/lib/pact_broker/api/decorators/versions_decorator.rb +24 -14
  47. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +2 -0
  48. data/lib/pact_broker/api/middleware/configuration.rb +2 -0
  49. data/lib/pact_broker/api/pact_broker_urls.rb +18 -2
  50. data/lib/pact_broker/api/resources/after_reply.rb +15 -0
  51. data/lib/pact_broker/api/resources/all_webhooks.rb +3 -3
  52. data/lib/pact_broker/api/resources/badge_methods.rb +2 -1
  53. data/lib/pact_broker/api/resources/base_resource.rb +6 -4
  54. data/lib/pact_broker/api/resources/branch.rb +40 -0
  55. data/lib/pact_broker/api/resources/branch_versions.rb +59 -0
  56. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment_badge.rb +1 -1
  57. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +1 -1
  58. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +1 -1
  59. data/lib/pact_broker/api/resources/dashboard.rb +10 -0
  60. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +1 -1
  61. data/lib/pact_broker/api/resources/environments.rb +1 -1
  62. data/lib/pact_broker/api/resources/error_handler.rb +18 -52
  63. data/lib/pact_broker/api/resources/error_handling_methods.rb +40 -14
  64. data/lib/pact_broker/api/resources/error_response_generator.rb +23 -6
  65. data/lib/pact_broker/api/resources/event_methods.rb +15 -0
  66. data/lib/pact_broker/api/resources/filter_methods.rb +15 -0
  67. data/lib/pact_broker/api/resources/group.rb +11 -2
  68. data/lib/pact_broker/api/resources/index.rb +6 -0
  69. data/lib/pact_broker/api/resources/integrations.rb +18 -4
  70. data/lib/pact_broker/api/resources/latest_version.rb +2 -0
  71. data/lib/pact_broker/api/resources/pact.rb +11 -6
  72. data/lib/pact_broker/api/resources/pacticipant_branches.rb +67 -0
  73. data/lib/pact_broker/api/resources/pacticipants.rb +26 -7
  74. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +2 -2
  75. data/lib/pact_broker/api/resources/pagination_methods.rb +11 -1
  76. data/lib/pact_broker/api/resources/verifications.rb +9 -4
  77. data/lib/pact_broker/api/resources/versions.rb +12 -0
  78. data/lib/pact_broker/api.rb +5 -0
  79. data/lib/pact_broker/app.rb +10 -4
  80. data/lib/pact_broker/application_context.rb +29 -25
  81. data/lib/pact_broker/async/after_reply.rb +30 -0
  82. data/lib/pact_broker/config/runtime_configuration.rb +9 -21
  83. data/lib/pact_broker/config/runtime_configuration_coercion_methods.rb +32 -2
  84. data/lib/pact_broker/config/runtime_configuration_database_methods.rb +1 -1
  85. data/lib/pact_broker/config/runtime_configuration_logging_methods.rb +15 -5
  86. data/lib/pact_broker/configuration.rb +29 -12
  87. data/lib/pact_broker/contracts/contracts_to_publish.rb +8 -0
  88. data/lib/pact_broker/contracts/service.rb +7 -1
  89. data/lib/pact_broker/dataset/page.rb +22 -0
  90. data/lib/pact_broker/dataset.rb +122 -0
  91. data/lib/pact_broker/db/data_migrations/set_contract_data_updated_at_for_integrations.rb +47 -0
  92. data/lib/pact_broker/db/migrate_data.rb +1 -0
  93. data/lib/pact_broker/db/models.rb +1 -1
  94. data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -5
  95. data/lib/pact_broker/deployments/deployed_version.rb +3 -3
  96. data/lib/pact_broker/deployments/environment.rb +0 -2
  97. data/lib/pact_broker/deployments/released_version.rb +4 -5
  98. data/lib/pact_broker/doc/views/index/pacticipant-branch.markdown +25 -0
  99. data/lib/pact_broker/domain/label.rb +6 -3
  100. data/lib/pact_broker/domain/pact.rb +10 -5
  101. data/lib/pact_broker/domain/pacticipant.rb +4 -34
  102. data/lib/pact_broker/domain/tag.rb +4 -5
  103. data/lib/pact_broker/domain/verification.rb +2 -4
  104. data/lib/pact_broker/domain/version.rb +12 -19
  105. data/lib/pact_broker/errors/error_reporter.rb +30 -0
  106. data/lib/pact_broker/errors.rb +2 -15
  107. data/lib/pact_broker/events/subscriber.rb +12 -4
  108. data/lib/pact_broker/feature_toggle.rb +1 -1
  109. data/lib/pact_broker/groups/service.rb +38 -5
  110. data/lib/pact_broker/index/service.rb +1 -2
  111. data/lib/pact_broker/integrations/event_listener.rb +23 -0
  112. data/lib/pact_broker/integrations/integration.rb +24 -2
  113. data/lib/pact_broker/integrations/repository.rb +34 -1
  114. data/lib/pact_broker/integrations/service.rb +17 -18
  115. data/lib/pact_broker/labels/repository.rb +4 -8
  116. data/lib/pact_broker/locale/en.yml +5 -0
  117. data/lib/pact_broker/matrix/every_row.rb +58 -40
  118. data/lib/pact_broker/matrix/integration_row.rb +95 -0
  119. data/lib/pact_broker/matrix/integrations_repository.rb +133 -0
  120. data/lib/pact_broker/matrix/matrix_row.rb +88 -0
  121. data/lib/pact_broker/matrix/matrix_row_dataset_module.rb +185 -0
  122. data/lib/pact_broker/matrix/matrix_row_instance_methods.rb +150 -0
  123. data/lib/pact_broker/matrix/matrix_row_verification_dataset_module.rb +83 -0
  124. data/lib/pact_broker/matrix/parse_query.rb +1 -0
  125. data/lib/pact_broker/matrix/repository.rb +62 -285
  126. data/lib/pact_broker/matrix/resolved_selector.rb +13 -4
  127. data/lib/pact_broker/matrix/resolved_selector_builder.rb +84 -0
  128. data/lib/pact_broker/matrix/resolved_selectors_builder.rb +39 -0
  129. data/lib/pact_broker/matrix/row_ignorer.rb +36 -0
  130. data/lib/pact_broker/matrix/selector_ignorer.rb +59 -0
  131. data/lib/pact_broker/matrix/selector_resolver.rb +130 -0
  132. data/lib/pact_broker/metrics/service.rb +4 -9
  133. data/lib/pact_broker/pacticipants/latest_version_for_pacticipant_eager_loader.rb +33 -0
  134. data/lib/pact_broker/pacticipants/repository.rb +7 -9
  135. data/lib/pact_broker/pacticipants/service.rb +2 -2
  136. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +2 -4
  137. data/lib/pact_broker/pacts/metadata.rb +3 -1
  138. data/lib/pact_broker/pacts/pact_publication.rb +23 -5
  139. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +5 -1
  140. data/lib/pact_broker/pacts/pact_version.rb +2 -3
  141. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +2 -5
  142. data/lib/pact_broker/pacts/placeholder_pact.rb +3 -1
  143. data/lib/pact_broker/pacts/repository.rb +12 -12
  144. data/lib/pact_broker/pacts/service.rb +1 -1
  145. data/lib/pact_broker/repositories.rb +9 -1
  146. data/lib/pact_broker/string_refinements.rb +4 -0
  147. data/lib/pact_broker/tags/head_pact_tags.rb +2 -5
  148. data/lib/pact_broker/tags/repository.rb +3 -7
  149. data/lib/pact_broker/test/test_data_builder.rb +50 -1
  150. data/lib/pact_broker/ui/controllers/groups.rb +2 -1
  151. data/lib/pact_broker/ui/view_models/matrix_line.rb +4 -4
  152. data/lib/pact_broker/ui/views/groups/show.html.erb +2 -1
  153. data/lib/pact_broker/verifications/latest_verification_for_consumer_and_provider.rb +0 -3
  154. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +2 -4
  155. data/lib/pact_broker/verifications/repository.rb +2 -5
  156. data/lib/pact_broker/verifications/sequence.rb +1 -4
  157. data/lib/pact_broker/verifications/service.rb +4 -0
  158. data/lib/pact_broker/version.rb +1 -1
  159. data/lib/pact_broker/versions/branch.rb +2 -5
  160. data/lib/pact_broker/versions/branch_head.rb +0 -3
  161. data/lib/pact_broker/versions/branch_repository.rb +76 -0
  162. data/lib/pact_broker/versions/branch_service.rb +13 -25
  163. data/lib/pact_broker/versions/branch_version.rb +0 -3
  164. data/lib/pact_broker/versions/branch_version_repository.rb +17 -0
  165. data/lib/pact_broker/versions/repository.rb +19 -2
  166. data/lib/pact_broker/versions/sequence.rb +1 -3
  167. data/lib/pact_broker/versions/service.rb +4 -0
  168. data/lib/pact_broker/webhooks/execution.rb +3 -7
  169. data/lib/pact_broker/webhooks/job.rb +16 -7
  170. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +2 -2
  171. data/lib/pact_broker/webhooks/repository.rb +0 -1
  172. data/lib/pact_broker/webhooks/trigger_service.rb +11 -12
  173. data/lib/pact_broker/webhooks/triggered_webhook.rb +3 -4
  174. data/lib/pact_broker/webhooks/webhook.rb +2 -2
  175. data/lib/pact_broker/webhooks/webhook_event.rb +2 -5
  176. data/lib/rack/pact_broker/add_cache_header.rb +14 -0
  177. data/lib/rack/pact_broker/application_context.rb +16 -0
  178. data/lib/rack/pact_broker/configurable_make_it_later.rb +1 -1
  179. data/lib/rack/pact_broker/invalid_uri_protection.rb +19 -3
  180. data/lib/webmachine/describe_routes.rb +55 -39
  181. data/lib/webmachine/render_error_monkey_patch.rb +13 -4
  182. data/pact_broker.gemspec +4 -4
  183. metadata +52 -29
  184. data/lib/pact_broker/api/decorators/decorator_context.rb +0 -22
  185. data/lib/pact_broker/matrix/query_builder.rb +0 -90
  186. data/lib/pact_broker/matrix/query_ids.rb +0 -40
  187. data/lib/pact_broker/matrix/quick_row.rb +0 -458
  188. data/lib/pact_broker/relationships/groupify.rb +0 -45
  189. data/lib/pact_broker/repositories/helpers.rb +0 -96
  190. data/lib/pact_broker/repositories/page.rb +0 -24
  191. data/lib/pact_broker/tags/tag_with_latest_flag.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 847d116937c44be25268cb31141093ab8c90e587d6e7bb304357116c6792ba23
4
- data.tar.gz: 12d14a0de3a15cd7efbbd035add102c338ee4347a0cf6490778a4644f69f2c44
3
+ metadata.gz: 79ce9d64a823a800533d3312f75b9e008d621833683e1f1424827fdf146ae855
4
+ data.tar.gz: 46c802480921553348daf0f3db5af2cbd94dd0a3b40de7db29f7137846768b93
5
5
  SHA512:
6
- metadata.gz: 34d62e70671d6ac6e4e26bb967c9e76279358a8e75db804c0ef0fd16790f82ee8b1095de841cdf730ff6b222faf01ade5993cf693631802628e9da2791ea7a1f
7
- data.tar.gz: 014ee6deb6bdd2ad204e3ac8dd401e0cf2de755b12006b8fdd5bd33fb4e4ede5386b18a21d99b03d39c8f3552c40a55c709ba1ab7a7d0e6977bd922c827957f8
6
+ metadata.gz: 2fc7c186cd8b1174668c97724e9065bf417768ec854726d3651a1ad1c13908adaa6ad36979f17be05483208fab304dad25f19dc8e31c085c685fc73c9539192e
7
+ data.tar.gz: bbb31b5fde13172358084bd35e3d52161a4440f91c2363ed337f7aa5512e8669cc39a323ae7f970016924a669de4eedb35d891a3ce95cadea850032a97c995dd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,58 @@
1
+ <a name="v2.108.0"></a>
2
+ ### v2.108.0 (2024-01-05)
3
+
4
+ #### Features
5
+
6
+ * bulk delete branches (#652) ([14ac33c8](/../../commit/14ac33c8))
7
+ * add latest version for branch endpoint (#644) ([c216bec8](/../../commit/c216bec8))
8
+ * add no-cache header ([9a637327](/../../commit/9a637327))
9
+ * suppport `page` + `size` as pagination params (#642) ([c71089fe](/../../commit/c71089fe))
10
+ * do not include pb:record-deployment or pb:record-release relations for versions embedded in resources ([2f43590c](/../../commit/2f43590c))
11
+ * remove status from individual error in problem+error response ([a4b3ec58](/../../commit/a4b3ec58))
12
+ * add version_id indexes to deployed_versions and released_versions ([00fc7d10](/../../commit/00fc7d10))
13
+ * add endpoint to list branches for a pacticipant (#638) ([ff7e3a53](/../../commit/ff7e3a53))
14
+ * stop running tests for ruby 2.7 ([034aba3b](/../../commit/034aba3b))
15
+ * update sinatra and rack-protection to ~> 3.0 ([92ebbdd3](/../../commit/92ebbdd3))
16
+ * add branch endpoint supporting GET and DELETE (#635) ([1bb6088d](/../../commit/1bb6088d))
17
+ * optimise matrix by applying specified limit to pact publications before joining to verifications ([c61c324e](/../../commit/c61c324e))
18
+ * optimise matrix query when selectors with pacticipant names only are used ([b98f5d1a](/../../commit/b98f5d1a))
19
+ * include environment name in pact metadata ([e120c4e7](/../../commit/e120c4e7))
20
+ * improve wording of 'no version exits' messaging in can-i-deploy response ([9529c679](/../../commit/9529c679))
21
+ * improve performance of matrix when multiple selectors are specified (#631) ([58a28604](/../../commit/58a28604))
22
+ * add pagination parameter validation for paginated endpoints. (#626) ([abb0a1c6](/../../commit/abb0a1c6))
23
+ * add endpoint to list pacticipant versions by branch ([9b4e3f61](/../../commit/9b4e3f61))
24
+ * add endpoint to return latest pact for consumer, provider and consumer branch ([f77086ef](/../../commit/f77086ef))
25
+ * update required ruby version from 2.2 to 2.7 ([f1b1e906](/../../commit/f1b1e906))
26
+ * add pagination and filtering for integrations endpoint ([68d7cf30](/../../commit/68d7cf30))
27
+ * add contract_data_updated_at to integrations table to speed up dashboard query (#617) ([e43c10f2](/../../commit/e43c10f2))
28
+ * support setting feature toggles via individual environment variables (#609) ([be7d9d52](/../../commit/be7d9d52))
29
+
30
+ * **metrics**
31
+ * hardcode matrix count to -1 as calculating it causes performance issues and it has no meaning ([62e121b8](/../../commit/62e121b8))
32
+
33
+ * **matrix**
34
+ * optimise identification of the 'latest tag' ([824c516a](/../../commit/824c516a))
35
+
36
+ #### Bug Fixes
37
+
38
+ * **metrics**
39
+ * correct the query for pactRevisionsPerConsumerVersion ([f76b9935](/../../commit/f76b9935))
40
+
41
+ * fix performance issues due to contention in the integrations table when publishing a large number of contracts (> 20) per request, in parallel (#654) ([321a2291](/../../commit/321a2291))
42
+ * raise 404 on paths with missing path segments (#648) ([930b45cd](/../../commit/930b45cd))
43
+ * do not error when no environment is found by name ([d1501618](/../../commit/d1501618))
44
+ * ensure pact associations are eager loaded when finding a single pact ([c98abda6](/../../commit/c98abda6))
45
+ * gracefully handle validating an array when a hash is expected ([b26ddb46](/../../commit/b26ddb46))
46
+ * fix error occuring when can-i-deploy badge is requested and no version is found ([db7dee3a](/../../commit/db7dee3a))
47
+ * fix bug in error handling for 'can-i-deploy branch to environment' badge ([c23beb6b](/../../commit/c23beb6b))
48
+ * improve performance of network diagram (#614) ([ffd3ec4b](/../../commit/ffd3ec4b))
49
+ * fix error raised when attempting to log warning when webhook_redact_sensitive_data is set to false ([9b66270e](/../../commit/9b66270e))
50
+ * gracefully handle execution of webhooks that are deleted between execution attempts (#613) ([1127b41f](/../../commit/1127b41f))
51
+ * add extra validation to ensure parsed content is a hash when publishing pacts ([913e0a52](/../../commit/913e0a52))
52
+
53
+ * **matrix**
54
+ * return only most recent row missing verification when latestby=cp ([b7550e53](/../../commit/b7550e53))
55
+
1
56
  <a name="v2.107.1"></a>
2
57
  ### v2.107.1 (2023-05-02)
3
58
 
data/Gemfile CHANGED
@@ -34,14 +34,15 @@ group :test do
34
34
  gem "approvals", ">=0.0.24", "<1.0.0"
35
35
  gem "tzinfo", "~>2.0"
36
36
  gem "faraday-retry", "~>2.0"
37
+ gem "openapi_first", "~>0.20"
37
38
  end
38
39
 
39
- if ENV["INSTALL_MYSQL"] == "true"
40
- gem "mysql2", "~>0.5"
40
+ group :pg, optional: true do
41
+ gem "pg", "~>1.2"
41
42
  end
42
43
 
43
- if ENV["INSTALL_PG"] == "true"
44
- gem "pg", "~>1.2"
44
+ group :mysql, optional: true do
45
+ gem "mysql2", "~>0.5"
45
46
  end
46
47
 
47
48
  if ENV["X_PACT_DEVELOPMENT"] == "true"
data/README.md CHANGED
@@ -188,3 +188,4 @@ The Pact Broker follows the [semantic versioning](https://semver.org/) scheme.
188
188
  [cli]: https://github.com/pact-foundation/pact-ruby-standalone/releases
189
189
  [travisyml]: https://github.com/pact-foundation/pact_broker/blob/master/.travis.yml
190
190
  [overview]: https://github.com/pact-foundation/pact_broker/wiki/Overview
191
+
@@ -0,0 +1,13 @@
1
+ Sequel.migration do
2
+ up do
3
+ alter_table(:integrations) do
4
+ add_column(:contract_data_updated_at, DateTime)
5
+ end
6
+ end
7
+
8
+ down do
9
+ alter_table(:integrations) do
10
+ drop_column(:contract_data_updated_at)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require "pact_broker/db/data_migrations/set_contract_data_updated_at_for_integrations"
2
+
3
+ Sequel.migration do
4
+ up do
5
+ PactBroker::DB::DataMigrations::SetContractDataUpdatedAtForIntegrations.call(self)
6
+ end
7
+
8
+ down do
9
+
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "migration_helper"
2
+
3
+ include PactBroker::MigrationHelper
4
+
5
+ Sequel.migration do
6
+ up do
7
+ if !mysql?
8
+ alter_table(:released_versions) do
9
+ add_index(:version_id, name: "released_versions_version_id_ndx")
10
+ end
11
+ end
12
+ end
13
+
14
+ down do
15
+ if !mysql?
16
+ alter_table(:released_versions) do
17
+ drop_index(:version_id, name: "released_versions_version_id_ndx")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "migration_helper"
2
+
3
+ include PactBroker::MigrationHelper
4
+
5
+ Sequel.migration do
6
+ up do
7
+ if !mysql?
8
+ alter_table(:deployed_versions) do
9
+ add_index(:version_id, name: "deployed_versions_version_id_ndx")
10
+ end
11
+ end
12
+ end
13
+
14
+ down do
15
+ if !mysql?
16
+ alter_table(:deployed_versions) do
17
+ drop_index(:version_id, name: "deployed_versions_version_id_ndx")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -666,6 +666,16 @@ The maximum amount of time in seconds to attempt to generate the diff between tw
666
666
  **YAML configuration key name:** `pact_content_diff_timeout`<br/>
667
667
  **Default:** `15`<br/>
668
668
 
669
+ ### network_diagram_max_pacticipants
670
+
671
+ The maximum number of pacticipants to include in the network diagram. When too many pacticipants are included, the diagram becomes unreadable,
672
+ and at large numbers, the graph will not render due to browser performance issues.
673
+
674
+ **Environment variable name:** `PACT_BROKER_NETWORK_DIAGRAM_MAX_PACTICIPANTS`<br/>
675
+ **YAML configuration key name:** `network_diagram_max_pacticipants`<br/>
676
+ **Default:** `150`<br/>
677
+ **Allowed values:** A positive integer<br/>
678
+
669
679
  <br/>
670
680
 
671
681
  ## Miscellaneous
@@ -22,7 +22,8 @@ module PactBroker
22
22
  # @param [Hash] the parameters to validate
23
23
  # @return [Hash] the validation errors to display to the user
24
24
  def self.call(params)
25
- format_errors(new.call(params&.symbolize_keys).errors)
25
+ params_to_validate = params.respond_to?(:symbolize_keys) ? params.symbolize_keys : params
26
+ new.call(params_to_validate)
26
27
  end
27
28
  end
28
29
  end
@@ -5,6 +5,8 @@ module PactBroker
5
5
  module Contracts
6
6
  module DryValidationErrorsFormatter
7
7
 
8
+ extend self
9
+
8
10
  # Formats the dry validation errors in the expected PactBroker error format of { :key => ["errors"] }
9
11
  # where there are no nested hashes.
10
12
  # @param [Dry::Validation::MessageSet] errors
@@ -0,0 +1,19 @@
1
+ require "pact_broker/api/contracts/base_contract"
2
+
3
+ module PactBroker
4
+ module Api
5
+ module Contracts
6
+ class PaginationQueryParamsSchema < BaseContract
7
+ params do
8
+ # legacy format
9
+ optional(:pageNumber).maybe(:integer).value(gteq?: 1)
10
+ optional(:pageSize).maybe(:integer).value(gteq?: 1)
11
+
12
+ # desired format
13
+ optional(:page).maybe(:integer).value(gteq?: 1)
14
+ optional(:size).maybe(:integer).value(gteq?: 1)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -20,23 +20,7 @@ module PactBroker
20
20
  rule(:consumerName).validate(:not_blank_if_present)
21
21
  rule(:providerName).validate(:not_blank_if_present)
22
22
 
23
- # validate_consumer_name_in_content
24
- rule(:decodedParsedContent, :consumerName, :specification) do
25
- consumer_name_in_content = values.dig(:decodedParsedContent, :consumer, :name)
26
- if consumer_name_in_content && consumer_name_in_content != values[:consumerName]
27
- base.failure(validation_message("consumer_name_in_content_mismatch", { consumer_name_in_content: consumer_name_in_content, consumer_name: values[:consumerName] }))
28
- end
29
- end
30
-
31
- # validate_provider_name_in_content
32
- rule(:decodedParsedContent, :providerName) do
33
- provider_name_in_content = values.dig(:decodedParsedContent, :provider, :name)
34
- if provider_name_in_content && provider_name_in_content != values[:providerName]
35
- base.failure(validation_message("provider_name_in_content_mismatch", { provider_name_in_content: provider_name_in_content, provider_name: values[:providerName] }))
36
- end
37
- end
38
-
39
- # validate_encoding
23
+ # validate_encoding (ensure all UTF-8 chars)
40
24
  rule(:decodedContent) do
41
25
  if value.nil?
42
26
  base.failure(validation_message("base64"))
@@ -50,12 +34,39 @@ module PactBroker
50
34
  end
51
35
  end
52
36
 
53
- # validate_content_matches_content_type
37
+ # validate content could be parsed according to its content type
54
38
  rule(:decodedParsedContent, :contentType) do
55
39
  if values[:decodedParsedContent].nil? && values[:contentType]
56
40
  base.failure(validation_message("invalid_content_for_content_type", { content_type: values[:contentType] }))
57
41
  end
58
42
  end
43
+
44
+ # validate parsed contract is a hash
45
+ rule(:decodedParsedContent, :contentType) do
46
+ if !base_rule_error? && !values[:decodedParsedContent].is_a?(Hash)
47
+ base.failure(validation_message("invalid_parsed_contract_class", { actual_class: values[:decodedParsedContent].class }))
48
+ end
49
+ end
50
+
51
+ # validate consumer name in content matches the details higher in the JSON document
52
+ rule(:decodedParsedContent, :consumerName, :specification) do
53
+ if !base_rule_error?
54
+ consumer_name_in_content = values.dig(:decodedParsedContent, :consumer, :name)
55
+ if consumer_name_in_content && consumer_name_in_content != values[:consumerName]
56
+ base.failure(validation_message("consumer_name_in_content_mismatch", { consumer_name_in_content: consumer_name_in_content, consumer_name: values[:consumerName] }))
57
+ end
58
+ end
59
+ end
60
+
61
+ # validate provider name in content matches the details higher in the JSON document
62
+ rule(:decodedParsedContent, :providerName) do
63
+ if !base_rule_error?
64
+ provider_name_in_content = values.dig(:decodedParsedContent, :provider, :name)
65
+ if provider_name_in_content && provider_name_in_content != values[:providerName]
66
+ base.failure(validation_message("provider_name_in_content_mismatch", { provider_name_in_content: provider_name_in_content, provider_name: values[:providerName] }))
67
+ end
68
+ end
69
+ end
59
70
  end
60
71
  end
61
72
  end
@@ -1,9 +1,9 @@
1
1
  require "roar/decorator"
2
2
  require "roar/json/hal"
3
3
  require "pact_broker/api/pact_broker_urls"
4
- require "pact_broker/api/decorators/decorator_context"
5
4
  require "pact_broker/api/decorators/format_date_time"
6
5
  require "pact_broker/string_refinements"
6
+ require "pact_broker/hash_refinements"
7
7
 
8
8
  module PactBroker
9
9
  module Api
@@ -14,11 +14,17 @@ module PactBroker
14
14
  include PactBroker::Api::PactBrokerUrls
15
15
  include FormatDateTime
16
16
  using PactBroker::StringRefinements
17
+ using PactBroker::HashRefinements
17
18
 
19
+ # Call this method to automatically camelize property names without
20
+ # having to define an :as each time.
18
21
  def self.camelize_property_names
19
22
  @camelize = true
20
23
  end
21
24
 
25
+ # Overrides the default property method to add a camelised :as option
26
+ # when camelize_property_names has been called for this decorator.
27
+ # @override
22
28
  def self.property(name, options={}, &block)
23
29
  if options.delete(:camelize) || @camelize
24
30
  camelized_name = name.to_s.camelcase(false).to_sym
@@ -27,6 +33,39 @@ module PactBroker
27
33
  super
28
34
  end
29
35
  end
36
+
37
+ # Returns the names of the model associations to eager load for use with this decorator
38
+ # @return [Array<Symbol>]
39
+ def self.eager_load_associations
40
+ if is_collection_resource?
41
+ collection_item_decorator_class.eager_load_associations
42
+ else
43
+ embedded_and_collection_attribute_names
44
+ end
45
+ end
46
+
47
+ # Returns true if this class is a decorator for a collection
48
+ # @return [true, false]
49
+ def self.is_collection_resource?
50
+ representable_attrs_without_links = representable_attrs.to_h.without("links", "page")
51
+ representable_attrs_without_links.size == 1 &&
52
+ representable_attrs_without_links.values.first[:collection] &&
53
+ representable_attrs_without_links.values.first[:extend]
54
+ end
55
+ private_class_method :is_collection_resource?
56
+
57
+ # Returns the names of the model attributes that are collections, embedded or nested items
58
+ # @return [Array<Symbol>]
59
+ def self.embedded_and_collection_attribute_names
60
+ representable_attrs.values.select{ | attr| attr[:collection] || attr[:embedded] || attr[:nested] }.collect{ |attr| attr[:name].to_sym }
61
+ end
62
+ private_class_method :embedded_and_collection_attribute_names
63
+
64
+ # @return [Class] The decorator class used to decorate the items in the collection
65
+ def self.collection_item_decorator_class
66
+ representable_attrs.to_h.without("links", "page").values.first[:extend].call
67
+ end
68
+ private_class_method :collection_item_decorator_class
30
69
  end
31
70
  end
32
71
  end
@@ -0,0 +1,35 @@
1
+ require "pact_broker/api/decorators/base_decorator"
2
+ require "pact_broker/api/decorators/timestamps"
3
+
4
+ module PactBroker
5
+ module Api
6
+ module Decorators
7
+ class BranchDecorator < BaseDecorator
8
+
9
+ property :name
10
+
11
+ link :self do | user_options |
12
+ {
13
+ title: "Branch",
14
+ href: branch_url(represented, user_options.fetch(:base_url))
15
+ }
16
+ end
17
+
18
+ link "pb:latest-version" do | user_options |
19
+ {
20
+ title: "Latest version for branch",
21
+ href: latest_version_for_branch_url(represented, user_options.fetch(:base_url))
22
+ }
23
+ end
24
+
25
+ include Timestamps
26
+
27
+ # When this decorator is embedded in the PacticipantBranchesDecorator,
28
+ # we need to eager load the pacticipants for generating the URL
29
+ def self.eager_load_associations
30
+ super + [:pacticipant]
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -13,6 +13,22 @@ module PactBroker
13
13
  }
14
14
  end
15
15
 
16
+ link :"pb:branch" do | user_options |
17
+ {
18
+ title: "Branch",
19
+ name: represented.branch.name,
20
+ href: branch_url(represented.branch, user_options.fetch(:base_url))
21
+ }
22
+ end
23
+
24
+ link :"pb:version" do | user_options |
25
+ {
26
+ title: "Version",
27
+ name: represented.version.number,
28
+ href: version_url(user_options.fetch(:base_url), represented.version)
29
+ }
30
+ end
31
+
16
32
  include Timestamps
17
33
  end
18
34
  end
@@ -20,6 +20,25 @@ module PactBroker
20
20
  end
21
21
  end
22
22
 
23
+ # @param [Class] errors_class will be a Hash class or Dry::Validation::MessageSet class
24
+ # @param [String] accept_header if this includes application/problem+json we render a application/problem+json response
25
+ # @return [Class] the decorator class
26
+ def validation_error_decorator_class_for(errors_class, accept_header)
27
+ if accept_header&.include?("application/problem+json")
28
+ if errors_class == Dry::Validation::MessageSet
29
+ PactBroker::Api::Decorators::DryValidationErrorsProblemJsonDecorator
30
+ else
31
+ PactBroker::Api::Decorators::ValidationErrorsProblemJsonDecorator
32
+ end
33
+ else
34
+ if errors_class == Dry::Validation::MessageSet
35
+ PactBroker::Api::Decorators::DryValidationErrorsDecorator
36
+ else
37
+ PactBroker::Api::Decorators::ValidationErrorsDecorator
38
+ end
39
+ end
40
+ end
41
+
23
42
  def self.default_configuration
24
43
  Configuration.new
25
44
  end
@@ -3,7 +3,7 @@
3
3
  module PactBroker
4
4
  module Api
5
5
  module Decorators
6
- class CustomErrorProblemJSONDecorator
6
+ class CustomErrorProblemJsonDecorator
7
7
 
8
8
  # @option title [String]
9
9
  # @option type [String]
@@ -1,11 +1,56 @@
1
- require "pact_broker/api/decorators/decorator_context"
1
+ # Builds the Hash that is passed into the Decorator as the `user_options`. It contains the request details, rack env, the (optional) title
2
+ # and anything else that is required by the decorator to render the resource (eg. the pacticipant that the versions belong to)
2
3
 
3
4
  module PactBroker
4
5
  module Api
5
6
  module Decorators
6
7
  class DecoratorContextCreator
8
+
9
+ # @param [PactBroker::BaseResource] the Pact Broker webmachine resource
10
+ # @param [Hash] options any extra options that need to be passed through to the decorator.
11
+ # @return [Hash] decorator_context
12
+
13
+ # decorator_context [String] :base_url
14
+ # The location where the Pact Broker is hosted.
15
+ # eg. http://some.host:9292/pact_broker
16
+ # Always present
17
+
18
+ # decorator_context [String] :resource_url
19
+ # The resource URL without any query string.
20
+ # eg. http://some.host:9292/pact_broker/pacticipants/Foo/versions
21
+ # Always present
22
+
23
+ # decorator_context [String] :query_string
24
+ # The query string.
25
+ # "page=1&size=50"
26
+ # May be empty
27
+
28
+ # decorator_context [String] :request_url
29
+ # The full request URL.
30
+ # eg. http://some.host:9292/pact_broker/pacticipants/Foo/versions?page=1&size=50
31
+ # Always present
32
+
33
+ # decorator_context [Hash] :env
34
+ # The rack env.
35
+ # Always present
36
+
37
+ # decorator_context [Hash] :resource_title
38
+ # eg. "Pacticipant versions for Foo"
39
+ # Optional
40
+ # Used when a single decorator is being used for multiple resources and the title needs to be
41
+ # set from the resource.
42
+
7
43
  def self.call(resource, options)
8
- Decorators::DecoratorContext.new(resource.base_url, resource.resource_url, resource.request.env, options)
44
+ env = resource.request.env
45
+ decorator_context = {}
46
+ decorator_context[:base_url] = resource.base_url
47
+ decorator_context[:resource_url] = resource.resource_url
48
+ decorator_context[:query_string] = query_string = (env["QUERY_STRING"] && !env["QUERY_STRING"].empty? ? env["QUERY_STRING"] : nil)
49
+ decorator_context[:request_url] = query_string ? resource.resource_url + "?" + query_string : resource.resource_url
50
+ decorator_context[:env] = env
51
+ decorator_context[:resource_title] = options[:resource_title]
52
+ decorator_context.merge!(options)
53
+ decorator_context
9
54
  end
10
55
  end
11
56
  end
@@ -11,13 +11,14 @@ module PactBroker
11
11
  property :currently_deployed, camelize: true
12
12
  property :target, camelize: true # deprecated
13
13
  property :applicationInstance, getter: lambda { |_| target }
14
- include Timestamps
15
14
  property :undeployedAt, getter: lambda { |_| undeployed_at ? FormatDateTime.call(undeployed_at) : nil }, writeable: false
16
15
 
17
16
  property :pacticipant, :extend => EmbeddedPacticipantDecorator, writeable: false, embedded: true
18
17
  property :version, :extend => EmbeddedVersionDecorator, writeable: false, embedded: true
19
18
  property :environment, :extend => EnvironmentDecorator, writeable: false, embedded: true
20
19
 
20
+ include Timestamps
21
+
21
22
  link :self do | user_options |
22
23
  {
23
24
  href: deployed_version_url(represented, user_options.fetch(:base_url))
@@ -1,11 +1,11 @@
1
1
  require "pact_broker/api/decorators/base_decorator"
2
- require "pact_broker/api/decorators/deployed_version_decorator"
2
+ require "pact_broker/api/decorators/embedded_deployed_version_decorator"
3
3
 
4
4
  module PactBroker
5
5
  module Api
6
6
  module Decorators
7
7
  class DeployedVersionsDecorator < BaseDecorator
8
- collection :entries, as: :deployedVersions, embedded: true, :extend => PactBroker::Api::Decorators::DeployedVersionDecorator
8
+ collection :entries, as: :deployedVersions, embedded: true, :extend => PactBroker::Api::Decorators::EmbeddedDeployedVersionDecorator
9
9
 
10
10
  link :self do | context |
11
11
  href = append_query_if_present(context[:resource_url], context[:query_string])
@@ -0,0 +1,32 @@
1
+ # Formats Dry::Validation::MessageSet errors into the "old" Pact Broker errors format
2
+ # TODO: delete this in favour of problem+json in the next major version
3
+
4
+ require "pact_broker/api/contracts/dry_validation_errors_formatter"
5
+
6
+ module PactBroker
7
+ module Api
8
+ module Decorators
9
+ class DryValidationErrorsDecorator
10
+
11
+ # @param errors [Hash]
12
+ def initialize(errors)
13
+ @errors = errors
14
+ end
15
+
16
+ # @return [Hash]
17
+ def to_hash(*_args, **_kwargs)
18
+ { errors: PactBroker::Api::Contracts::DryValidationErrorsFormatter.format_errors(errors) }
19
+ end
20
+
21
+ # @return [String] JSON
22
+ def to_json(*args, **kwargs)
23
+ to_hash(*args, **kwargs).to_json
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :errors
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ require "pact_broker/api/decorators/base_decorator"
2
+ require "pact_broker/api/decorators/embedded_error_problem_json_decorator"
3
+ # Formats a Dry::Validation::MessageSet into application/problem+json format.
4
+ # according to the spec at https://www.rfc-editor.org/rfc/rfc9457.html
5
+
6
+ # Decorates Dry::Validation::MessageSet
7
+ # Defaults to displaying validation errors, but the top level
8
+ # details may be overridden to display error responses for other HTTP statuses (eg. 409)
9
+ module PactBroker
10
+ module Api
11
+ module Decorators
12
+ class DryValidationErrorsProblemJsonDecorator < BaseDecorator
13
+
14
+ property :title, getter: -> (user_options:, **) { user_options[:title] || "Validation errors" }
15
+ property :type, getter: -> (user_options:, **) { user_options[:type] || "#{user_options[:base_url]}/problems/validation-error" }
16
+ property :detail, getter: -> (user_options:, **) { user_options[:detail] || nil }
17
+ property :status, getter: -> (user_options:, **) { user_options[:status] || 400 }
18
+ property :instance, getter: -> (user_options:, **) { user_options[:instance] || "/" }
19
+
20
+ collection :entries, as: :errors, extend: PactBroker::Api::Decorators::EmbeddedErrorProblemJsonDecorator
21
+ end
22
+ end
23
+ end
24
+ end
@@ -5,12 +5,12 @@ module PactBroker
5
5
  module Api
6
6
  module Decorators
7
7
  class EmbeddedBranchVersionDecorator < BaseDecorator
8
- property :branch_name, as: :name
8
+ property :branch_name, as: :name # TODO rename this to branchName in next major version
9
9
  property :latest?, as: :latest
10
10
 
11
11
  link :self do | options |
12
12
  {
13
- title: "Version branch",
13
+ title: "Branch version",
14
14
  name: represented.branch_name,
15
15
  href: branch_version_url(represented, options[:base_url])
16
16
  }