pact_broker 2.107.1 → 2.109.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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/Gemfile +5 -6
  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/publish_contract_decorator.rb +6 -1
  42. data/lib/pact_broker/api/decorators/released_versions_decorator.rb +2 -2
  43. data/lib/pact_broker/api/decorators/runtime_error_problem_json_decorator.rb +2 -2
  44. data/lib/pact_broker/api/decorators/validation_errors_decorator.rb +30 -0
  45. data/lib/pact_broker/api/decorators/validation_errors_problem_json_decorator.rb +4 -6
  46. data/lib/pact_broker/api/decorators/version_decorator.rb +5 -3
  47. data/lib/pact_broker/api/decorators/versions_decorator.rb +24 -14
  48. data/lib/pact_broker/api/decorators/webhook_decorator.rb +1 -1
  49. data/lib/pact_broker/api/decorators/webhook_execution_result_decorator.rb +2 -0
  50. data/lib/pact_broker/api/middleware/configuration.rb +2 -0
  51. data/lib/pact_broker/api/pact_broker_urls.rb +18 -2
  52. data/lib/pact_broker/api/resources/after_reply.rb +15 -0
  53. data/lib/pact_broker/api/resources/all_webhooks.rb +3 -3
  54. data/lib/pact_broker/api/resources/badge_methods.rb +2 -1
  55. data/lib/pact_broker/api/resources/base_resource.rb +6 -4
  56. data/lib/pact_broker/api/resources/branch.rb +40 -0
  57. data/lib/pact_broker/api/resources/branch_versions.rb +59 -0
  58. data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment_badge.rb +1 -1
  59. data/lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb +1 -1
  60. data/lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb +1 -1
  61. data/lib/pact_broker/api/resources/dashboard.rb +10 -0
  62. data/lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb +1 -1
  63. data/lib/pact_broker/api/resources/environment.rb +4 -0
  64. data/lib/pact_broker/api/resources/environments.rb +1 -1
  65. data/lib/pact_broker/api/resources/error_handler.rb +18 -52
  66. data/lib/pact_broker/api/resources/error_handling_methods.rb +40 -14
  67. data/lib/pact_broker/api/resources/error_response_generator.rb +23 -6
  68. data/lib/pact_broker/api/resources/event_methods.rb +15 -0
  69. data/lib/pact_broker/api/resources/filter_methods.rb +15 -0
  70. data/lib/pact_broker/api/resources/group.rb +11 -2
  71. data/lib/pact_broker/api/resources/index.rb +6 -0
  72. data/lib/pact_broker/api/resources/integrations.rb +18 -4
  73. data/lib/pact_broker/api/resources/latest_version.rb +2 -0
  74. data/lib/pact_broker/api/resources/pact.rb +16 -7
  75. data/lib/pact_broker/api/resources/pacticipant_branches.rb +67 -0
  76. data/lib/pact_broker/api/resources/pacticipants.rb +26 -7
  77. data/lib/pact_broker/api/resources/pacticipants_for_label.rb +2 -2
  78. data/lib/pact_broker/api/resources/pagination_methods.rb +11 -1
  79. data/lib/pact_broker/api/resources/publish_contracts.rb +1 -1
  80. data/lib/pact_broker/api/resources/verifications.rb +9 -4
  81. data/lib/pact_broker/api/resources/versions.rb +12 -0
  82. data/lib/pact_broker/api.rb +5 -0
  83. data/lib/pact_broker/app.rb +10 -9
  84. data/lib/pact_broker/application_context.rb +29 -25
  85. data/lib/pact_broker/async/after_reply.rb +30 -0
  86. data/lib/pact_broker/config/runtime_configuration.rb +9 -21
  87. data/lib/pact_broker/config/runtime_configuration_coercion_methods.rb +32 -2
  88. data/lib/pact_broker/config/runtime_configuration_database_methods.rb +1 -1
  89. data/lib/pact_broker/config/runtime_configuration_logging_methods.rb +15 -5
  90. data/lib/pact_broker/configuration.rb +29 -12
  91. data/lib/pact_broker/contracts/contract_to_publish.rb +4 -5
  92. data/lib/pact_broker/contracts/contracts_to_publish.rb +8 -0
  93. data/lib/pact_broker/contracts/service.rb +9 -3
  94. data/lib/pact_broker/dataset/page.rb +22 -0
  95. data/lib/pact_broker/dataset.rb +122 -0
  96. data/lib/pact_broker/db/data_migrations/set_contract_data_updated_at_for_integrations.rb +47 -0
  97. data/lib/pact_broker/db/migrate_data.rb +1 -0
  98. data/lib/pact_broker/db/models.rb +1 -1
  99. data/lib/pact_broker/deployments/currently_deployed_version_id.rb +2 -5
  100. data/lib/pact_broker/deployments/deployed_version.rb +3 -3
  101. data/lib/pact_broker/deployments/environment.rb +0 -2
  102. data/lib/pact_broker/deployments/released_version.rb +4 -5
  103. data/lib/pact_broker/doc/views/index/pacticipant-branch.markdown +25 -0
  104. data/lib/pact_broker/domain/label.rb +6 -3
  105. data/lib/pact_broker/domain/pact.rb +10 -5
  106. data/lib/pact_broker/domain/pacticipant.rb +4 -34
  107. data/lib/pact_broker/domain/tag.rb +4 -5
  108. data/lib/pact_broker/domain/verification.rb +2 -4
  109. data/lib/pact_broker/domain/version.rb +12 -19
  110. data/lib/pact_broker/errors/error_reporter.rb +30 -0
  111. data/lib/pact_broker/errors.rb +2 -15
  112. data/lib/pact_broker/events/subscriber.rb +12 -4
  113. data/lib/pact_broker/feature_toggle.rb +1 -1
  114. data/lib/pact_broker/groups/service.rb +38 -5
  115. data/lib/pact_broker/index/service.rb +1 -2
  116. data/lib/pact_broker/integrations/event_listener.rb +23 -0
  117. data/lib/pact_broker/integrations/integration.rb +24 -2
  118. data/lib/pact_broker/integrations/repository.rb +34 -1
  119. data/lib/pact_broker/integrations/service.rb +17 -18
  120. data/lib/pact_broker/labels/repository.rb +4 -8
  121. data/lib/pact_broker/locale/en.yml +5 -0
  122. data/lib/pact_broker/logging.rb +10 -0
  123. data/lib/pact_broker/matrix/every_row.rb +58 -40
  124. data/lib/pact_broker/matrix/integration_row.rb +95 -0
  125. data/lib/pact_broker/matrix/integrations_repository.rb +133 -0
  126. data/lib/pact_broker/matrix/matrix_row.rb +88 -0
  127. data/lib/pact_broker/matrix/matrix_row_dataset_module.rb +185 -0
  128. data/lib/pact_broker/matrix/matrix_row_instance_methods.rb +150 -0
  129. data/lib/pact_broker/matrix/matrix_row_verification_dataset_module.rb +83 -0
  130. data/lib/pact_broker/matrix/parse_query.rb +1 -0
  131. data/lib/pact_broker/matrix/repository.rb +62 -285
  132. data/lib/pact_broker/matrix/resolved_selector.rb +13 -4
  133. data/lib/pact_broker/matrix/resolved_selector_builder.rb +84 -0
  134. data/lib/pact_broker/matrix/resolved_selectors_builder.rb +39 -0
  135. data/lib/pact_broker/matrix/row_ignorer.rb +36 -0
  136. data/lib/pact_broker/matrix/selector_ignorer.rb +59 -0
  137. data/lib/pact_broker/matrix/selector_resolver.rb +130 -0
  138. data/lib/pact_broker/metrics/service.rb +4 -9
  139. data/lib/pact_broker/pacticipants/latest_version_for_pacticipant_eager_loader.rb +33 -0
  140. data/lib/pact_broker/pacticipants/repository.rb +7 -9
  141. data/lib/pact_broker/pacticipants/service.rb +2 -2
  142. data/lib/pact_broker/pacts/generate_sha.rb +9 -4
  143. data/lib/pact_broker/pacts/latest_pact_publication_id_for_consumer_version.rb +2 -4
  144. data/lib/pact_broker/pacts/metadata.rb +3 -1
  145. data/lib/pact_broker/pacts/pact_params.rb +1 -1
  146. data/lib/pact_broker/pacts/pact_publication.rb +23 -5
  147. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +5 -1
  148. data/lib/pact_broker/pacts/pact_version.rb +2 -3
  149. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +2 -5
  150. data/lib/pact_broker/pacts/placeholder_pact.rb +3 -1
  151. data/lib/pact_broker/pacts/repository.rb +12 -12
  152. data/lib/pact_broker/pacts/service.rb +12 -13
  153. data/lib/pact_broker/repositories.rb +9 -1
  154. data/lib/pact_broker/string_refinements.rb +4 -0
  155. data/lib/pact_broker/tags/head_pact_tags.rb +2 -5
  156. data/lib/pact_broker/tags/repository.rb +3 -7
  157. data/lib/pact_broker/test/test_data_builder.rb +57 -2
  158. data/lib/pact_broker/ui/controllers/base_controller.rb +4 -2
  159. data/lib/pact_broker/ui/controllers/groups.rb +2 -1
  160. data/lib/pact_broker/ui/view_models/matrix_line.rb +4 -4
  161. data/lib/pact_broker/ui/views/groups/show.html.erb +2 -1
  162. data/lib/pact_broker/ui.rb +20 -9
  163. data/lib/pact_broker/verifications/latest_verification_for_consumer_and_provider.rb +0 -3
  164. data/lib/pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version.rb +2 -4
  165. data/lib/pact_broker/verifications/repository.rb +2 -5
  166. data/lib/pact_broker/verifications/sequence.rb +1 -4
  167. data/lib/pact_broker/verifications/service.rb +4 -0
  168. data/lib/pact_broker/version.rb +1 -1
  169. data/lib/pact_broker/versions/branch.rb +2 -5
  170. data/lib/pact_broker/versions/branch_head.rb +0 -3
  171. data/lib/pact_broker/versions/branch_repository.rb +76 -0
  172. data/lib/pact_broker/versions/branch_service.rb +13 -25
  173. data/lib/pact_broker/versions/branch_version.rb +0 -3
  174. data/lib/pact_broker/versions/branch_version_repository.rb +17 -0
  175. data/lib/pact_broker/versions/repository.rb +19 -2
  176. data/lib/pact_broker/versions/sequence.rb +1 -3
  177. data/lib/pact_broker/versions/service.rb +4 -0
  178. data/lib/pact_broker/webhooks/execution.rb +3 -7
  179. data/lib/pact_broker/webhooks/job.rb +16 -7
  180. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +2 -2
  181. data/lib/pact_broker/webhooks/repository.rb +0 -1
  182. data/lib/pact_broker/webhooks/trigger_service.rb +11 -12
  183. data/lib/pact_broker/webhooks/triggered_webhook.rb +3 -4
  184. data/lib/pact_broker/webhooks/webhook.rb +2 -2
  185. data/lib/pact_broker/webhooks/webhook_event.rb +2 -5
  186. data/lib/rack/pact_broker/add_cache_header.rb +14 -0
  187. data/lib/rack/pact_broker/application_context.rb +16 -0
  188. data/lib/rack/pact_broker/configurable_make_it_later.rb +1 -1
  189. data/lib/rack/pact_broker/invalid_uri_protection.rb +19 -3
  190. data/lib/webmachine/describe_routes.rb +55 -39
  191. data/lib/webmachine/render_error_monkey_patch.rb +13 -4
  192. data/pact_broker.gemspec +5 -5
  193. metadata +54 -31
  194. data/lib/pact_broker/api/decorators/decorator_context.rb +0 -22
  195. data/lib/pact_broker/matrix/query_builder.rb +0 -90
  196. data/lib/pact_broker/matrix/query_ids.rb +0 -40
  197. data/lib/pact_broker/matrix/quick_row.rb +0 -458
  198. data/lib/pact_broker/relationships/groupify.rb +0 -45
  199. data/lib/pact_broker/repositories/helpers.rb +0 -96
  200. data/lib/pact_broker/repositories/page.rb +0 -24
  201. data/lib/pact_broker/tags/tag_with_latest_flag.rb +0 -28
@@ -1,13 +1,45 @@
1
- require "pact_broker/matrix/quick_row"
1
+ require "pact_broker/matrix/matrix_row"
2
+ require "pact_broker/matrix/matrix_row_dataset_module"
3
+ require "pact_broker/matrix/matrix_row_instance_methods"
4
+ require "pact_broker/matrix/matrix_row_verification_dataset_module"
2
5
 
6
+ # Same as PactBroker::Matrix::MatrixRow
7
+ # except the data is sourced from the pact_publications table, and contains
8
+ # every pact publication, not just the latest publication for the consumer version.
9
+ # This is used when there is no "latestby" in the matrix query.
3
10
  module PactBroker
4
11
  module Matrix
5
- class EveryRow < PactBroker::Matrix::QuickRow
6
- set_dataset(Sequel.as(:pact_publications, :p))
12
+ class EveryRow < Sequel::Model(Sequel.as(:pact_publications, :p))
7
13
 
8
- P_V_JOIN = { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }
14
+ # Same as PactBroker::Matrix::MatrixRow::Verification
15
+ # except the data is sourced from the verifications table, and contains
16
+ # every verification, not just the latest verification for the pact version and the provider version.
17
+ # This is used when there is no "latestby" in the matrix query.
18
+ class Verification < Sequel::Model(:verifications)
19
+ dataset_module do
20
+ select(:select_verification_columns_with_aliases,
21
+ Sequel[:verifications][:id].as(:verification_id),
22
+ Sequel[:verifications][:provider_version_id],
23
+ Sequel[:verifications][:created_at].as(:provider_version_created_at),
24
+ Sequel[:verifications][:pact_version_id]
25
+ )
9
26
 
10
- PACT_COLUMNS = [
27
+ include PactBroker::Matrix::MatrixRowVerificationDatasetModule
28
+ end
29
+ end
30
+
31
+ # Must be kept in sync with PactBroker::Matrix::MatrixRow
32
+ associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
33
+ associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
34
+ associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
35
+ associate(:many_to_one, :consumer_version, :class => "PactBroker::Domain::Version", :key => :consumer_version_id, :primary_key => :id)
36
+ associate(:many_to_one, :provider_version, :class => "PactBroker::Domain::Version", :key => :provider_version_id, :primary_key => :id)
37
+ associate(:many_to_one, :pact_version, class: "PactBroker::Pacts::PactVersion", :key => :pact_version_id, :primary_key => :id)
38
+ associate(:many_to_one, :verification, class: "PactBroker::Domain::Verification", :key => :verification_id, :primary_key => :id)
39
+ associate(:one_to_many, :consumer_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :consumer_version_id, key: :version_id)
40
+ associate(:one_to_many, :provider_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :provider_version_id, key: :version_id)
41
+
42
+ PACT_COLUMNS_WITH_ALIASES = [
11
43
  Sequel[:p][:consumer_id],
12
44
  Sequel[:p][:provider_id],
13
45
  Sequel[:p][:consumer_version_id],
@@ -18,50 +50,36 @@ module PactBroker
18
50
  Sequel[:p][:id].as(:pact_order)
19
51
  ]
20
52
 
21
- VERIFICATION_COLUMNS = [
22
- Sequel[:v][:id].as(:verification_id),
53
+ ALL_COLUMNS_AFTER_JOIN = [
54
+ Sequel[:p][:consumer_id],
55
+ Sequel[:p][:provider_id],
56
+ Sequel[:p][:consumer_version_id],
57
+ Sequel[:p][:pact_publication_id],
58
+ Sequel[:p][:pact_version_id],
59
+ Sequel[:p][:pact_revision_number],
60
+ Sequel[:p][:consumer_version_created_at],
61
+ Sequel[:p][:pact_order],
62
+ Sequel[:v][:verification_id],
23
63
  Sequel[:v][:provider_version_id],
24
- Sequel[:v][:created_at].as(:provider_version_created_at)
64
+ Sequel[:v][:provider_version_created_at]
25
65
  ]
26
66
 
27
- JOINED_VERIFICATION_COLUMNS = [:id, :pact_version_id, :provider_id, :provider_version_id, :created_at]
28
-
29
- ALL_COLUMNS = PACT_COLUMNS + VERIFICATION_COLUMNS
30
-
31
- SELECT_ALL_COLUMN_ARGS = [:select_all_columns] + ALL_COLUMNS
32
-
33
67
  dataset_module do
34
- select(*SELECT_ALL_COLUMN_ARGS)
68
+ include PactBroker::Matrix::MatrixRowDatasetModule
35
69
 
36
- def join_verifications
37
- left_outer_join(:verifications, P_V_JOIN, { table_alias: :v } )
38
- end
70
+ select(:select_pact_columns_with_aliases, *PACT_COLUMNS_WITH_ALIASES)
71
+ select(:select_all_columns_after_join, *ALL_COLUMNS_AFTER_JOIN)
39
72
 
40
- def inner_join_verifications
41
- join(:verifications, P_V_JOIN, { table_alias: :v } )
42
- end
43
-
44
- def inner_join_verifications_matching_one_selector_provider_or_provider_version(query_ids)
45
- verifications = db[:verifications]
46
- .select(*JOINED_VERIFICATION_COLUMNS)
47
- .where {
48
- QueryBuilder.provider_or_provider_version_matches(query_ids)
49
- }
50
-
51
- join(verifications, P_V_JOIN, { table_alias: :v } )
73
+ def verification_dataset
74
+ EveryRow::Verification
52
75
  end
76
+ end
53
77
 
54
- def verifications_for(query_ids)
55
- db[:verifications]
56
- .select(*JOINED_VERIFICATION_COLUMNS)
57
- .where {
58
- Sequel.&(
59
- QueryBuilder.consumer_in_pacticipant_ids(query_ids),
60
- QueryBuilder.provider_or_provider_version_matches(query_ids)
61
- )
62
- }
63
- end
78
+ def pact_publication_id
79
+ return_or_raise_if_not_set(:pact_publication_id)
64
80
  end
81
+
82
+ include PactBroker::Matrix::MatrixRowInstanceMethods
65
83
  end
66
84
  end
67
85
  end
@@ -0,0 +1,95 @@
1
+ # A Sequel model used for identifying potential and required integrations
2
+ # between the versions described by the specified selectors
3
+ # and other applications.
4
+ # It is only meant to be used via the public dataset methods.
5
+
6
+ module PactBroker
7
+ module Matrix
8
+ class IntegrationRow < Sequel::Model(Sequel.as(:latest_pact_publication_ids_for_consumer_versions, :p))
9
+ dataset_module do
10
+ select(:select_pacticipant_ids, Sequel[:p][:consumer_id], Sequel[:p][:provider_id])
11
+
12
+ # Return the distinct consumer/provider ids and names for the integrations which involve the given resolved selector
13
+ # in the role of consumer. The resolved selector must have a pacticipant_id, and may or may not have a pacticipant_version_id.
14
+ # @public
15
+ # @param [PactBroker::Matrix::ResolvedSelector] resolved_selector
16
+ # @return [Sequel::Dataset] for rows with consumer_id, consumer_name, provider_id and provider_name
17
+ def integrations_for_selector_as_consumer(resolved_selector)
18
+ select(:consumer_id, :provider_id)
19
+ .distinct
20
+ .where({ consumer_id: resolved_selector.pacticipant_id, consumer_version_id: resolved_selector.pacticipant_version_id }.compact)
21
+ .from_self(alias: :integrations)
22
+ .select(:consumer_id, :provider_id, Sequel[:consumers][:name].as(:consumer_name), Sequel[:providers][:name].as(:provider_name))
23
+ .join_consumers(:integrations, :consumers)
24
+ .join_providers(:integrations, :providers)
25
+ end
26
+
27
+ # Find all the integrations (consumer/provider pairs) that involve ONLY the given selectors.
28
+ # @public
29
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
30
+ # @return [Sequel::Dataset] for rows with consumer_id, consumer_name, provider_id and provider_name
31
+ def distinct_integrations_between_given_selectors(resolved_selectors)
32
+ if resolved_selectors.size == 1
33
+ raise ArgumentError.new("Expected multiple selectors to be provided, but only received one #{selectors}")
34
+ end
35
+ query = pact_publications_matching_selectors_as_consumer(resolved_selectors)
36
+ .select_pacticipant_ids
37
+ .distinct
38
+
39
+ query.from_self(alias: :pacticipant_ids)
40
+ .select(
41
+ :consumer_id,
42
+ Sequel[:c][:name].as(:consumer_name),
43
+ :provider_id,
44
+ Sequel[:p][:name].as(:provider_name)
45
+ )
46
+ .join_consumers(:pacticipant_ids, :c)
47
+ .join_providers(:pacticipant_ids, :p)
48
+ end
49
+
50
+ # @public
51
+ def join_consumers qualifier = :p, table_alias = :consumers
52
+ join(
53
+ :pacticipants,
54
+ { Sequel[qualifier][:consumer_id] => Sequel[table_alias][:id] },
55
+ { table_alias: table_alias }
56
+ )
57
+ end
58
+
59
+ # @public
60
+ def join_providers qualifier = :p, table_alias = :providers
61
+ join(
62
+ :pacticipants,
63
+ { Sequel[qualifier][:provider_id] => Sequel[table_alias][:id] },
64
+ { table_alias: table_alias }
65
+ )
66
+ end
67
+
68
+ # @private
69
+ def pact_publications_matching_selectors_as_consumer(resolved_selectors)
70
+ pacticipant_ids = resolved_selectors.collect(&:pacticipant_id).uniq
71
+
72
+ self
73
+ .select_pacticipant_ids
74
+ .distinct
75
+ .inner_join_versions_for_selectors_as_consumer(resolved_selectors)
76
+ .where(provider_id: pacticipant_ids)
77
+ end
78
+
79
+ # @private
80
+ def inner_join_versions_for_selectors_as_consumer(resolved_selectors)
81
+ # get the UnresolvedSelector objects back out of the resolved_selectors because the Version.for_selector() method uses the UnresolvedSelector
82
+ unresolved_selectors = resolved_selectors.collect(&:original_selector).uniq
83
+ versions = PactBroker::Domain::Version.ids_for_selectors(unresolved_selectors)
84
+ inner_join_versions_dataset(versions)
85
+ end
86
+
87
+ # @private
88
+ def inner_join_versions_dataset(versions)
89
+ versions_join = { Sequel[:p][:consumer_version_id] => Sequel[:versions][:id] }
90
+ join(versions, versions_join, table_alias: :versions)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,133 @@
1
+ require "pact_broker/matrix/integration_row"
2
+ # A "find only" repository for the PactBroker::Matrix::Integration object.
3
+ # The PactBroker::Matrix::Integration object is not a Sequel Model like the PactBroker::Integrations::Integration - it is built from the
4
+ # matrix data specifically for a given matrix query, and as well as the consumer/provider attributes, it also
5
+ # knows whether or not that particular depdency is required in the context of the specific matrix query.
6
+ # eg. a HTTP consumer will always require that a provider is deployed, but a provider can be deployed if the consumer does not exist
7
+ # in the given environment yet.
8
+ # The "integrations for selectors" query is used to work out what what integrations are involved for a can-i-deploy query.
9
+
10
+ module PactBroker
11
+ module Matrix
12
+ class IntegrationsRepository
13
+ # Find all the Integrations required for this query, using the options to determine whether to find
14
+ # the inferred integrations or not.
15
+ # The infer_selectors_for_integrations only makes a difference when there are multiple selectors.
16
+ # When it is false, then only integrations are returned that exist *between* the versions of
17
+ # the selectors. When it is true, then all integrations that involve any of the versions of the selectors
18
+ # are returned.
19
+ #
20
+ # eg.
21
+ # Foo v1 has verified contract with Bar v2
22
+ # Waffle v3 has verified contract with Bar v2
23
+ # Foo v1 has unverified contract with Frog
24
+ #
25
+ # With selectors Foo v1 and Bar v2, and infer_selectors_for_integrations false, the returned integrations are Foo/Bar
26
+ # With the same selectors and infer_selectors_for_integrations true, the returned integrations are Foo/Bar, Waffle/Bar and Foo/Frog.
27
+ #
28
+ # When there is a single selector, the result is exactly the same whether infer_selectors_for_integrations is true or false.
29
+ #
30
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_specified_selectors
31
+ # @param [Boolean] infer_selectors_for_integrations
32
+ # @return [Array<PactBroker::Matrix::Integration>]
33
+ def find_integrations_for_specified_selectors(resolved_specified_selectors, infer_selectors_for_integrations)
34
+ if infer_selectors_for_integrations || resolved_specified_selectors.size == 1
35
+ find_integrations_involving_any_specfied_selectors(resolved_specified_selectors).sort_by(&:pacticipant_names)
36
+ else
37
+ find_integrations_between_specified_selectors(resolved_specified_selectors).sort_by(&:pacticipant_names)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Find the Integrations that only involve the versions from the selectors specifed in the query.
44
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_specified_selectors
45
+ # @return [Array<PactBroker::Matrix::Integration>]
46
+ def find_integrations_between_specified_selectors(resolved_specified_selectors)
47
+ specified_pacticipant_names = resolved_specified_selectors.collect(&:pacticipant_name)
48
+ IntegrationRow
49
+ .distinct_integrations_between_given_selectors(resolved_specified_selectors)
50
+ .all
51
+ .collect(&:to_hash)
52
+ .collect do | integration_hash |
53
+ required = is_a_row_for_this_integration_required?(specified_pacticipant_names, integration_hash[:consumer_name])
54
+ Integration.from_hash(integration_hash.merge(required: required))
55
+ end
56
+ end
57
+
58
+ # Find all Integrations where any of the specified selectors are involved.
59
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_specified_selectors
60
+ # @return [Array<PactBroker::Matrix::Integration>]
61
+ def find_integrations_involving_any_specfied_selectors(resolved_specified_selectors)
62
+ integrations = integrations_where_specified_selector_is_consumer(resolved_specified_selectors) +
63
+ integrations_where_specified_selector_is_provider(resolved_specified_selectors)
64
+ deduplicate_integrations(integrations)
65
+ end
66
+
67
+ # Find all the providers for the consumer versions specified in the query.
68
+ # We must identify the providers for the consumer *versions*, not just the *consumers* (via the integrations table)
69
+ # because the providers may change over time, as integrations get added and removed.
70
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] the resolved selectors that were specified in the query
71
+ # @return [Array<PactBroker::Matrix::Integration>]
72
+ def integrations_where_specified_selector_is_consumer(resolved_specified_selectors)
73
+ resolved_specified_selectors.flat_map do | selector |
74
+ # Could optimise this to all in one query, but it's a small gain
75
+ IntegrationRow
76
+ .integrations_for_selector_as_consumer(selector)
77
+ .all
78
+ .collect do | integration |
79
+ Integration.from_hash(
80
+ consumer_id: integration[:consumer_id],
81
+ consumer_name: integration[:consumer_name],
82
+ provider_id: integration[:provider_id],
83
+ provider_name: integration[:provider_name],
84
+ required: true # consumer requires the provider to be present
85
+ )
86
+ end
87
+ end
88
+ end
89
+
90
+ # Returns a list of *potential* integrations for the pacticipants in the selectors, where the pacticipant is a provider.
91
+ # Can't tell from the verifications table if a particular provider version has a consumer, as that is determined
92
+ # by what is deployed to the environment, not what is verified. By looking in the integration table, we can identify
93
+ # what consumers *may* be present in the target environment.
94
+ # Find all the consumers for the providers specified in the query. Does not take into consideration the provider version (not sure why).
95
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] the resolved selectors that were specified in the query
96
+ # @return [Array<PactBroker::Matrix::Integration>]
97
+ def integrations_where_specified_selector_is_provider(resolved_specified_selectors)
98
+ integrations_involving_specified_providers = PactBroker::Integrations::Integration
99
+ .where(provider_id: resolved_specified_selectors.collect(&:pacticipant_id))
100
+ .eager(:consumer, :provider)
101
+ .all
102
+
103
+ integrations_involving_specified_providers.collect do | integration |
104
+ Integration.from_hash(
105
+ consumer_id: integration.consumer.id,
106
+ consumer_name: integration.consumer.name,
107
+ provider_id: integration.provider.id,
108
+ provider_name: integration.provider.name,
109
+ required: false # provider does not require the consumer to be present
110
+ )
111
+ end
112
+ end
113
+
114
+ # Deduplicate a list of Integrations
115
+ # @param [Array<PactBroker::Matrix::Integration>] integrations
116
+ # @return [Array<PactBroker::Matrix::Integration>]
117
+ def deduplicate_integrations(integrations)
118
+ integrations
119
+ .group_by{ | integration| [integration.consumer_id, integration.provider_id] }
120
+ .values
121
+ .collect { | duplicate_integrations | duplicate_integrations.find(&:required?) || duplicate_integrations.first }
122
+ end
123
+
124
+ # If a specified pacticipant is a consumer, then its provider is required to be deployed
125
+ # to the same environment before the consumer can be deployed.
126
+ # If a specified pacticipant is a provider only, then it may be deployed
127
+ # without the consumer being present, but cannot break an existing consumer.
128
+ def is_a_row_for_this_integration_required?(specified_pacticipant_names, consumer_name)
129
+ specified_pacticipant_names.include?(consumer_name)
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,88 @@
1
+ require "pact_broker/dataset"
2
+ require "pact_broker/logging"
3
+ require "pact_broker/pacts/pact_version"
4
+ require "pact_broker/domain/pacticipant"
5
+ require "pact_broker/domain/version"
6
+ require "pact_broker/domain/verification"
7
+ require "pact_broker/domain/tag"
8
+ require "pact_broker/pacts/pact_publication"
9
+ require "pact_broker/matrix/matrix_row_dataset_module"
10
+ require "pact_broker/matrix/matrix_row_instance_methods"
11
+ require "pact_broker/matrix/matrix_row_verification_dataset_module"
12
+
13
+ # The PactBroker::Matrix::MatrixRow represents a row in the table that is created when
14
+ # the consumer versions are joined to the provider versions via the pacts and verifications tables,
15
+ # aka "The Matrix". The difference between this class and the EveryRow class is that
16
+ # the EveryRow class includes results for overridden pact verisons and verifications (used only when there is no latestby
17
+ # set in the matrix query), where as the MatrixRow class only includes the latest pact for each consumer version,
18
+ # and the latest verification for each provider version.
19
+
20
+ module PactBroker
21
+ module Matrix
22
+ class MatrixRow < Sequel::Model(Sequel.as(:latest_pact_publication_ids_for_consumer_versions, :p))
23
+
24
+ class Verification < Sequel::Model(Sequel.as(:latest_verification_id_for_pact_version_and_provider_version, :v))
25
+ dataset_module do
26
+ select(:select_verification_columns_with_aliases,
27
+ Sequel[:v][:provider_version_id],
28
+ Sequel[:v][:verification_id],
29
+ Sequel[:v][:created_at].as(:provider_version_created_at),
30
+ Sequel[:v][:pact_version_id]
31
+ )
32
+
33
+ include PactBroker::Matrix::MatrixRowVerificationDatasetModule
34
+ end
35
+ end
36
+
37
+ PACT_COLUMNS_WITH_ALIASES = [
38
+ Sequel[:p][:consumer_id],
39
+ Sequel[:p][:provider_id],
40
+ Sequel[:p][:consumer_version_id],
41
+ Sequel[:p][:pact_publication_id],
42
+ Sequel[:p][:pact_version_id],
43
+ Sequel[:p][:created_at].as(:consumer_version_created_at),
44
+ Sequel[:p][:pact_publication_id].as(:pact_order)
45
+ ]
46
+
47
+ ALL_COLUMNS_AFTER_JOIN = [
48
+ Sequel[:p][:consumer_id],
49
+ Sequel[:p][:provider_id],
50
+ Sequel[:p][:consumer_version_id],
51
+ Sequel[:p][:pact_publication_id],
52
+ Sequel[:p][:pact_version_id],
53
+ Sequel[:p][:consumer_version_created_at],
54
+ Sequel[:p][:pact_order],
55
+ Sequel[:v][:verification_id],
56
+ Sequel[:v][:provider_version_id],
57
+ Sequel[:v][:provider_version_created_at]
58
+
59
+ ]
60
+
61
+ # Must be kept in sync with PactBroker::Matrix::EveryRow
62
+ associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
63
+ associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
64
+ associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
65
+ associate(:many_to_one, :consumer_version, :class => "PactBroker::Domain::Version", :key => :consumer_version_id, :primary_key => :id)
66
+ associate(:many_to_one, :provider_version, :class => "PactBroker::Domain::Version", :key => :provider_version_id, :primary_key => :id)
67
+ associate(:many_to_one, :pact_version, class: "PactBroker::Pacts::PactVersion", :key => :pact_version_id, :primary_key => :id)
68
+ associate(:many_to_one, :verification, class: "PactBroker::Domain::Verification", :key => :verification_id, :primary_key => :id)
69
+ associate(:one_to_many, :consumer_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :consumer_version_id, key: :version_id)
70
+ associate(:one_to_many, :provider_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :provider_version_id, key: :version_id)
71
+
72
+ dataset_module do
73
+ include PactBroker::Dataset
74
+ include PactBroker::Matrix::MatrixRowDatasetModule
75
+
76
+ select(:select_pact_columns_with_aliases, *PACT_COLUMNS_WITH_ALIASES)
77
+ select(:select_all_columns_after_join, *ALL_COLUMNS_AFTER_JOIN)
78
+
79
+ # @private
80
+ def verification_dataset
81
+ MatrixRow::Verification
82
+ end
83
+ end
84
+
85
+ include PactBroker::Matrix::MatrixRowInstanceMethods
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,185 @@
1
+ # The dataset methods used by both the MatrixRow and the EveryRow classes
2
+ # Requires the following methods to be defined on the model
3
+ # - verification_dataset
4
+ # - select_pact_columns_with_aliases
5
+ # - select_all_columns_after_join
6
+
7
+ module PactBroker
8
+ module Matrix
9
+ module MatrixRowDatasetModule
10
+ EAGER_LOADED_RELATIONSHIPS_FOR_VERSION = { current_deployed_versions: :environment, current_supported_released_versions: :environment, branch_versions: [:branch_head, :version, branch: :pacticipant] }
11
+ LAST_ACTION_DATE = Sequel.lit("CASE WHEN (provider_version_created_at IS NOT NULL AND provider_version_created_at > consumer_version_created_at) THEN provider_version_created_at ELSE consumer_version_created_at END").as(:last_action_date)
12
+
13
+ # The matrix query used to determine the final dataset
14
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
15
+ def matching_selectors(resolved_selectors, limit:)
16
+ if resolved_selectors.size == 1
17
+ matching_one_selector_for_either_consumer_or_provider(resolved_selectors, limit: limit)
18
+ else
19
+ matching_only_selectors_joining_verifications(resolved_selectors, limit: limit)
20
+ end
21
+ end
22
+
23
+ # @public
24
+ def order_by_last_action_date
25
+ from_self(alias: :unordered_rows).select(LAST_ACTION_DATE, Sequel[:unordered_rows].* ).order(Sequel.desc(:last_action_date), Sequel.desc(:pact_order), Sequel.desc(:verification_id))
26
+ end
27
+
28
+ # eager load tags?
29
+ # @public
30
+ def eager_all_the_things
31
+ eager(
32
+ :consumer,
33
+ :provider,
34
+ :verification,
35
+ :pact_publication,
36
+ :pact_version,
37
+ consumer_version: EAGER_LOADED_RELATIONSHIPS_FOR_VERSION,
38
+ provider_version: EAGER_LOADED_RELATIONSHIPS_FOR_VERSION,
39
+ consumer_version_tags: [:head_tag, { version: :pacticipant }],
40
+ provider_version_tags: [:head_tag, { version: :pacticipant }]
41
+ )
42
+ end
43
+
44
+ # Just for testing purposes
45
+ def default_scope
46
+ select_pact_columns_with_aliases
47
+ .from_self(alias: :p)
48
+ .left_outer_join_verifications
49
+ .select_all_columns_after_join
50
+ end
51
+
52
+ # PRIVATE METHODS
53
+
54
+ # Final matrix query with one selector (not the normal use case)
55
+ # When we have one selector, we need to join ALL the verifications to find out
56
+ # what integrations exist
57
+ # @private
58
+ def matching_one_selector_for_either_consumer_or_provider(resolved_selectors, limit: )
59
+ if resolved_selectors.size != 1
60
+ raise ArgumentError.new("Expected one selector to be provided, but received #{resolved_selectors.size}: #{resolved_selectors}")
61
+ end
62
+
63
+ # consumer
64
+ pact_publication_matching_consumer = select_pact_columns_with_aliases.most_recent(limit).from_self(alias: :p).inner_join_versions_for_selectors_as_consumer(resolved_selectors)
65
+ rows_where_selector_matches_consumer = pact_publication_matching_consumer.left_outer_join_verifications.select_all_columns_after_join
66
+
67
+ # provider
68
+ verifications_matching_provider = verification_dataset.matching_selectors_as_provider_for_any_consumer(resolved_selectors)
69
+ rows_where_selector_matches_provider = select_pact_columns_with_aliases.most_recent(limit).from_self(alias: :p).inner_join_verifications_dataset(verifications_matching_provider).select_all_columns_after_join
70
+
71
+ # union
72
+ rows_where_selector_matches_consumer.union(rows_where_selector_matches_provider)
73
+ end
74
+
75
+ # Find the matrix rows
76
+ # When the user has specified multiple selectors, we only want to join the verifications for
77
+ # the specified selectors. This is because of the behaviour of the left outer join.
78
+ # Imagine a pact has been verified by a provider version that was NOT specified in the selectors.
79
+ # If we join all the verifications and THEN filter the rows to only show the versions specified
80
+ # in the selectors, we won't get a row for that pact, and hence, we won't
81
+ # know that it hasn't been verified by the provider version we're interested in.
82
+ # Instead, we need to filter the verifications dataset down to only the ones specified in the selectors first,
83
+ # and THEN join them to the pacts, so that we get a row for the pact with null provider version
84
+ # and verification fields.
85
+ # IDEA FOR OPTIMISATION - would it work to limit the pact_publications query and the verifications query to the limit of the overall query?
86
+ # @private
87
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
88
+ # @return [Sequel::Dataset<MatrixRow>]
89
+ def matching_only_selectors_joining_verifications(resolved_selectors, limit: )
90
+ pact_publications = matching_only_selectors_as_consumer(resolved_selectors, limit: limit)
91
+ verifications = verification_dataset.matching_only_selectors_as_provider(resolved_selectors)
92
+
93
+ specified_pacticipant_ids = resolved_selectors.select(&:specified?).collect(&:pacticipant_id).uniq
94
+
95
+ pact_publications
96
+ .from_self(alias: :p)
97
+ .select_all_columns_after_join
98
+ .left_outer_join_verifications_dataset(verifications)
99
+ .where(consumer_id: specified_pacticipant_ids).or(provider_id: specified_pacticipant_ids)
100
+ end
101
+
102
+ # Return pact publications where the consumer/consumer version is described by any of the resolved_selectors, AND the provider is described by any of the resolved selectors.
103
+ # @private
104
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
105
+ # @return [Sequel::Dataset<MatrixRow>]
106
+ def matching_only_selectors_as_consumer(resolved_selectors, limit: )
107
+ [
108
+ matching_only_selectors_as_consumer_where_only_pacticipant_name_in_selector(resolved_selectors, limit: limit),
109
+ matching_only_selectors_as_consumer_where_not_only_pacticipant_name_in_selector(resolved_selectors, limit: limit),
110
+ ].compact.reduce(&:union)
111
+ end
112
+
113
+
114
+ # Return pact publications where the consumer is described by any of the resolved_selectors *that only specify the pacticipant NAME*, AND the provider is described by any of the resolved selectors.
115
+ # If the original selector only specified the pacticipant name, we don't need to join to the versions table to identify the required pact_publications.
116
+ # Return nil if there are no resolved selectors where only the pacticipant name is specified.
117
+ # @private
118
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
119
+ # @return [Sequel::Dataset<MatrixRow>, nil]
120
+ def matching_only_selectors_as_consumer_where_only_pacticipant_name_in_selector(resolved_selectors, limit:)
121
+ all_pacticipant_ids = resolved_selectors.collect(&:pacticipant_id).uniq
122
+ pacticipant_ids_for_pacticipant_only_selectors = resolved_selectors.select(&:only_pacticipant_name_specified?).collect(&:pacticipant_id).uniq
123
+
124
+ if pacticipant_ids_for_pacticipant_only_selectors.any?
125
+ select_pact_columns_with_aliases
126
+ .where(consumer_id: pacticipant_ids_for_pacticipant_only_selectors)
127
+ .where(provider_id: all_pacticipant_ids)
128
+ .most_recent(limit)
129
+ end
130
+ end
131
+
132
+ # Return pact publications where the consumer *version* is described by any of the resolved_selectors
133
+ # *that specify more than just the pacticipant name*,
134
+ # AND the provider is described by any of the resolved selectors.
135
+ # If the selector uses any of the tag/branch/environment/latest attributes, we need to join to the versions table to identify the required pact_publications.
136
+ # Return nil if there are no resolved selectors where anything other than the pacticipant name is specified.
137
+ # @private
138
+ # @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
139
+ # @return [Sequel::Dataset<MatrixRow>, nil]
140
+ def matching_only_selectors_as_consumer_where_not_only_pacticipant_name_in_selector(resolved_selectors, limit:)
141
+ all_pacticipant_ids = resolved_selectors.collect(&:pacticipant_id).uniq
142
+ resolved_selectors_with_versions_specified = resolved_selectors.reject(&:only_pacticipant_name_specified?)
143
+
144
+ if resolved_selectors_with_versions_specified.any?
145
+ select_pact_columns_with_aliases
146
+ .inner_join_versions_for_selectors_as_consumer(resolved_selectors_with_versions_specified)
147
+ .where(provider_id: all_pacticipant_ids)
148
+ .most_recent(limit)
149
+ end
150
+ end
151
+
152
+ # @private
153
+ def inner_join_versions_for_selectors_as_consumer(resolved_selectors)
154
+ # get the UnresolvedSelector objects back out of the resolved_selectors because the Version.for_selector() method uses the UnresolvedSelector
155
+ unresolved_selectors = resolved_selectors.collect(&:original_selector).uniq
156
+ versions = PactBroker::Domain::Version.ids_for_selectors(unresolved_selectors)
157
+ inner_join_versions_dataset(versions)
158
+ end
159
+
160
+ # @private
161
+ def inner_join_versions_dataset(versions)
162
+ versions_join = { Sequel[:p][:consumer_version_id] => Sequel[:versions][:id] }
163
+ join(versions, versions_join, table_alias: :versions)
164
+ end
165
+
166
+ # @private
167
+ def left_outer_join_verifications
168
+ left_outer_join_verifications_dataset(verification_dataset.select_verification_columns_with_aliases)
169
+ end
170
+
171
+ def left_outer_join_verifications_dataset(verifications)
172
+ left_outer_join(verifications, { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }, { table_alias: :v } )
173
+ end
174
+
175
+ # @private
176
+ def inner_join_verifications_dataset(verifications_dataset)
177
+ join(verifications_dataset, { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }, { table_alias: :v } )
178
+ end
179
+
180
+ def most_recent(limit)
181
+ order(Sequel.desc(:created_at)).limit(limit)
182
+ end
183
+ end
184
+ end
185
+ end