pact_broker 2.107.1 → 2.108.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }