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
@@ -25,16 +25,19 @@ module PactBroker
25
25
  # base_url raises a not implemented error
26
26
  def log_configuration(logger)
27
27
  source_info = to_source_trace
28
- (self.class.config_attributes - [:base_url]).collect(&:to_s).each_with_object({})do | key, new_hash |
28
+ attributes_to_log.collect(&:to_s).each_with_object({}) do | key, new_hash |
29
29
  new_hash[key] = {
30
30
  value: self.send(key.to_sym),
31
- source: source_info.dig(key, :source) || {:type=>:defaults}
31
+ source: source_info.dig(key, :source) || source_info.dig(key) || { type: :defaults }
32
32
  }
33
33
  end.sort_by { |key, _| key }.each { |key, value| log_config_inner(key, value, logger) }
34
- if self.webhook_redact_sensitive_data == false
35
- logger.warn("WARNING!!! webhook_redact_sensitive_data is set to false. This will allow authentication information to be included in the webhook logs. This should only be used for debugging purposes. Do not run the application permanently in production with this value.")
36
- end
34
+ print_warnings(logger)
35
+ end
36
+
37
+ def attributes_to_log
38
+ self.class.config_attributes - [:base_url]
37
39
  end
40
+ private :attributes_to_log
38
41
 
39
42
  def log_config_inner(key, value, logger)
40
43
  # TODO fix the source display for webhook_certificates set by environment variables
@@ -68,6 +71,13 @@ module PactBroker
68
71
  end
69
72
  end
70
73
  private :redact
74
+
75
+ def print_warnings(logger)
76
+ if self.webhook_redact_sensitive_data == false
77
+ logger.warn("WARNING!!! webhook_redact_sensitive_data is set to false. This will allow authentication information to be included in the webhook logs. This should only be used for debugging purposes. Do not run the application permanently in production with this value.")
78
+ end
79
+ end
80
+ private :print_warnings
71
81
  end
72
82
 
73
83
  def self.included(receiver)
@@ -82,23 +82,14 @@ module PactBroker
82
82
 
83
83
  def override_runtime_configuration!(overrides)
84
84
  new_runtime_configuration = runtime_configuration.dup
85
- valid_overrides = {}
86
- invalid_overrides = {}
87
-
88
- overrides.each do | key, value |
89
- if new_runtime_configuration.respond_to?("#{key}=")
90
- valid_overrides[key] = Anyway::AutoCast.call(value)
91
- else
92
- invalid_overrides[key] = Anyway::AutoCast.call(value)
93
- end
94
- end
85
+ valid_overrides, invalid_overrides = identify_valid_and_invalid_configuration_overrides(new_runtime_configuration, overrides)
95
86
 
96
87
  if logger.debug?
97
- logger.debug("Overridding runtime configuration", overrides: valid_overrides, ignoring: invalid_overrides)
88
+ logger.debug("Overriding runtime configuration", overrides: valid_overrides, ignoring: invalid_overrides)
98
89
  end
99
90
 
100
91
  valid_overrides.each do | key, value |
101
- new_runtime_configuration.public_send("#{key}=", value)
92
+ override_or_merge_value(new_runtime_configuration, key, value)
102
93
  end
103
94
 
104
95
  self.runtime_configuration = new_runtime_configuration
@@ -220,5 +211,31 @@ module PactBroker
220
211
  require "pact_broker/config/load"
221
212
  PactBroker::Config::Load.call(runtime_configuration)
222
213
  end
214
+
215
+ private
216
+
217
+ def identify_valid_and_invalid_configuration_overrides(new_runtime_configuration, overrides)
218
+ valid_overrides = {}
219
+ invalid_overrides = {}
220
+
221
+ overrides.each do | key, value |
222
+ if new_runtime_configuration.respond_to?("#{key}=")
223
+ valid_overrides[key] = Anyway::AutoCast.call(value)
224
+ else
225
+ invalid_overrides[key] = Anyway::AutoCast.call(value)
226
+ end
227
+ end
228
+
229
+ return valid_overrides, invalid_overrides
230
+ end
231
+
232
+ def override_or_merge_value(new_runtime_configuration, key, value)
233
+ # Do a merge if original value and new value are both hashes
234
+ if value.is_a?(Hash) && new_runtime_configuration.public_send(key).is_a?(Hash)
235
+ new_runtime_configuration.public_send("#{key}=", new_runtime_configuration.public_send(key).merge(value))
236
+ else
237
+ new_runtime_configuration.public_send("#{key}=", value)
238
+ end
239
+ end
223
240
  end
224
241
  end
@@ -10,6 +10,14 @@ module PactBroker
10
10
  def pacticipant_names
11
11
  contracts.flat_map(&:pacticipant_names).uniq
12
12
  end
13
+
14
+ def provider_names
15
+ contracts.flat_map(&:provider_name).uniq
16
+ end
17
+
18
+ def logging_info
19
+ to_h.slice(:pacticipant_name, :pacticipant_version_number, :tags, :branch, :build_url).merge(provider_names: provider_names)
20
+ end
13
21
  end
14
22
  end
15
23
  end
@@ -31,9 +31,11 @@ module PactBroker
31
31
  end
32
32
 
33
33
  def publish(parsed_contracts, base_url: )
34
+ logger.info("Publishing contracts", parsed_contracts.logging_info)
34
35
  version, version_notices = create_version(parsed_contracts)
35
36
  tags = create_tags(parsed_contracts, version)
36
37
  pacts, pact_notices = create_pacts(parsed_contracts, base_url)
38
+ update_integrations(pacts)
37
39
  notices = version_notices + pact_notices
38
40
  ContractsPublicationResults.from_hash(
39
41
  pacticipant: version.pacticipant,
@@ -65,7 +67,7 @@ module PactBroker
65
67
 
66
68
  def add_pact_conflict_notice(notices, parsed_contracts, contract_to_publish, existing_json_content, new_json_content)
67
69
  message_params = {
68
- consumer_name: contract_to_publish.provider_name,
70
+ consumer_name: contract_to_publish.consumer_name,
69
71
  consumer_version_number: parsed_contracts.pacticipant_version_number,
70
72
  provider_name: contract_to_publish.provider_name
71
73
  }
@@ -302,6 +304,10 @@ module PactBroker
302
304
  PactBroker::Api::PactBrokerUrls.triggered_webhook_logs_url(triggered_webhook, base_url)
303
305
  end
304
306
 
307
+ def update_integrations(pacts)
308
+ integration_service.handle_bulk_contract_data_published(pacts)
309
+ end
310
+
305
311
  private :url_for_triggered_webhook
306
312
  end
307
313
  end
@@ -0,0 +1,22 @@
1
+ require "forwardable"
2
+
3
+ # An array that provides the pagination details
4
+
5
+ module PactBroker
6
+ module Dataset
7
+ class Page < Array
8
+ extend Forwardable
9
+
10
+ attr_reader :query
11
+
12
+ PAGE_PROPERTIES = [:page_size, :page_count, :page_range, :current_page, :next_page, :prev_page, :first_page?, :last_page?, :pagination_record_count, :current_page_record_count, :current_page_record_range]
13
+
14
+ delegate PAGE_PROPERTIES => :query
15
+
16
+ def initialize(array, query)
17
+ super(array)
18
+ @query = query
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,122 @@
1
+ require "sequel"
2
+ require "pact_broker/dataset/page"
3
+
4
+ Sequel.extension :escaped_like
5
+
6
+ module PactBroker
7
+ module Dataset
8
+ module Helpers
9
+ extend self
10
+
11
+ def mysql?
12
+ Sequel::Model.db.adapter_scheme.to_s =~ /mysql/
13
+ end
14
+
15
+ def postgres?
16
+ Sequel::Model.db.adapter_scheme.to_s =~ /postgres/
17
+ end
18
+
19
+ def escape_wildcards(value)
20
+ value.gsub("_", "\\_").gsub("%", "\\%")
21
+ end
22
+ end
23
+
24
+ include Helpers
25
+
26
+ # Return a dataset that only includes the rows where the specified column
27
+ # includes the given query string.
28
+ # @return [Sequel::Dataset]
29
+ def filter(column_name, query_string)
30
+ where(Sequel.ilike(column_name, "%" + escape_wildcards(query_string) + "%"))
31
+ end
32
+
33
+ def name_like column_name, value
34
+ if PactBroker.configuration.use_case_sensitive_resource_names
35
+ if mysql?
36
+ # sigh, mysql, this is the only way to perform a case sensitive search
37
+ Sequel.like(column_name, value.gsub("_", "\\_"), { case_insensitive: false })
38
+ else
39
+ { column_name => value }
40
+ end
41
+ else
42
+ Sequel.like(column_name, value.gsub("_", "\\_"), { case_insensitive: true })
43
+ end
44
+ end
45
+
46
+ def where_name_like(column_name, value)
47
+ where(name_like(column_name, value))
48
+ end
49
+
50
+ def select_all_qualified
51
+ select(Sequel[model.table_name].*)
52
+ end
53
+
54
+ def all_with_pagination_options(pagination_options)
55
+ if pagination_options&.any?
56
+ query = paginate(pagination_options[:page_number], pagination_options[:page_size])
57
+ Page.new(query.all, query)
58
+ else
59
+ all
60
+ end
61
+ end
62
+
63
+ def all_forbidding_lazy_load
64
+ all.each{ | row | row.forbid_lazy_load if row.respond_to?(:forbid_lazy_load) }
65
+ end
66
+
67
+ def all_allowing_lazy_load
68
+ all.each{ | row | row.allow_lazy_load if row.respond_to?(:allow_lazy_load) }
69
+ end
70
+
71
+ # @param [Symbol] max_column the name of the column of which to calculate the maxiumum
72
+ # @param [Array<Symbol>] group_by_columns the names of the columns by which to group
73
+ def max_group_by(max_column, group_by_columns, &extra_criteria_block)
74
+ maximums_base_query = extra_criteria_block ? extra_criteria_block.call(self) : self
75
+ maximums = maximums_base_query.select_group(*group_by_columns).select_append(Sequel.function(:max, max_column).as(:max_value))
76
+
77
+ max_join = group_by_columns.each_with_object({ Sequel[:maximums][:max_value] => max_column }) do | column_name, joins |
78
+ joins[Sequel[:maximums][column_name]] = column_name
79
+ end
80
+
81
+ join(maximums, max_join, table_alias: :maximums)
82
+ end
83
+
84
+ def select_for_subquery column
85
+ if mysql? #stoopid mysql doesn't allow you to modify datasets with subqueries
86
+ column_name = column.respond_to?(:alias) ? column.alias : column
87
+ select(column).collect{ | it | it[column_name] }
88
+ else
89
+ select(column)
90
+ end
91
+ end
92
+
93
+ def no_columns_selected?
94
+ opts[:select].nil?
95
+ end
96
+
97
+ def order_ignore_case column_name = :name
98
+ order(Sequel.function(:lower, column_name))
99
+ end
100
+
101
+ def order_append_ignore_case column_name = :name
102
+ order_append(Sequel.function(:lower, column_name))
103
+ end
104
+ end
105
+ end
106
+
107
+ module Sequel
108
+ # For matching identifying names based on the :use_case_sensitive_resource_names config setting.
109
+ # This has been used inconsistently, and in the next major version, support for case insensitive names will be dropped.
110
+ def self.name_like(column_name, value)
111
+ if PactBroker.configuration.use_case_sensitive_resource_names
112
+ if PactBroker::Dataset::Helpers.mysql?
113
+ # sigh, mysql, this is the only way to perform a case sensitive search
114
+ Sequel.like(column_name, PactBroker::Dataset::Helpers.escape_wildcards(value), { case_insensitive: false })
115
+ else
116
+ { column_name => value }
117
+ end
118
+ else
119
+ Sequel.like(column_name, PactBroker::Dataset::Helpers.escape_wildcards(value), { case_insensitive: true })
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,47 @@
1
+ # Populate the newly created contract_data_updated_at date in the integrations table
2
+ # using the latest created_at date from the pact_publications or verifications tables.
3
+ module PactBroker
4
+ module DB
5
+ module DataMigrations
6
+ class SetContractDataUpdatedAtForIntegrations
7
+ def self.call(connection)
8
+ join = {
9
+ Sequel[:integrations][:consumer_id] => Sequel[:target][:consumer_id],
10
+ Sequel[:integrations][:provider_id] => Sequel[:target][:provider_id]
11
+ }
12
+
13
+ max_created_at_for_each_integration = integrations_max_created_at(connection).from_self(alias: :target).select(:created_at).where(join)
14
+
15
+ connection[:integrations]
16
+ .where(contract_data_updated_at: nil)
17
+ .update(contract_data_updated_at: max_created_at_for_each_integration)
18
+ end
19
+
20
+ # @return [Sequel::Dataset] the overall max created_at from the union of the pact_publications and verifications tables,
21
+ # for each integration keyed by consumer_id/provider_id
22
+ def self.integrations_max_created_at(connection)
23
+ pact_publication_max_created_at(connection)
24
+ .union(verification_max_created_at(connection))
25
+ .select_group(:consumer_id, :provider_id)
26
+ .select_append{ max(:created_at).as(:created_at) }
27
+ end
28
+
29
+ # @return [Sequel::Dataset] the max created_at from the pact_publications table
30
+ # for each integration keyed by consumer_id/provider_id
31
+ def self.pact_publication_max_created_at(connection)
32
+ connection[:pact_publications]
33
+ .select_group(:consumer_id, :provider_id)
34
+ .select_append{ max(:created_at).as(:created_at) }
35
+ end
36
+
37
+ # @return [Sequel::Dataset] the max created_at from the verifications table
38
+ # for each integration keyed by consumer_id/provider_id
39
+ def self.verification_max_created_at(connection)
40
+ connection[:verifications]
41
+ .select_group(:consumer_id, :provider_id)
42
+ .select_append{ max(:created_at).as(:created_at) }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -29,6 +29,7 @@ module PactBroker
29
29
  DataMigrations::CreateBranches.call(database_connection)
30
30
  DataMigrations::MigrateIntegrations.call(database_connection)
31
31
  DataMigrations::MigratePactVersionProviderTagSuccessfulVerifications.call(database_connection)
32
+ DataMigrations::SetContractDataUpdatedAtForIntegrations.call(database_connection)
32
33
  end
33
34
  end
34
35
  end
@@ -17,7 +17,7 @@ require "pact_broker/deployments/released_version"
17
17
  require "pact_broker/versions/branch"
18
18
  require "pact_broker/versions/branch_version"
19
19
  require "pact_broker/versions/branch_head"
20
- require "pact_broker/matrix/quick_row"
20
+ require "pact_broker/matrix/matrix_row"
21
21
  require "pact_broker/matrix/every_row"
22
22
 
23
23
  module PactBroker
@@ -1,5 +1,4 @@
1
- require "sequel"
2
- require "pact_broker/repositories/helpers"
1
+ require "pact_broker/dataset"
3
2
 
4
3
  module PactBroker
5
4
  module Deployments
@@ -8,9 +7,7 @@ module PactBroker
8
7
 
9
8
  plugin :upsert, identifying_columns: [:pacticipant_id, :environment_id, :target_for_index]
10
9
 
11
- dataset_module do
12
- include PactBroker::Repositories::Helpers
13
- end
10
+ dataset_module(PactBroker::Dataset)
14
11
  end
15
12
  end
16
13
  end
@@ -1,4 +1,4 @@
1
- require "pact_broker/repositories/helpers"
1
+ require "pact_broker/dataset"
2
2
  require "pact_broker/deployments/currently_deployed_version_id"
3
3
 
4
4
  module PactBroker
@@ -15,7 +15,7 @@ module PactBroker
15
15
  plugin :insert_ignore, identifying_columns: [:pacticipant_id, :version_id, :environment_id, :target_for_index]
16
16
 
17
17
  dataset_module do
18
- include PactBroker::Repositories::Helpers
18
+ include PactBroker::Dataset
19
19
 
20
20
  def user_created
21
21
  where(auto_created: false)
@@ -50,7 +50,7 @@ module PactBroker
50
50
  end
51
51
 
52
52
  def for_pacticipant_name(pacticipant_name)
53
- where(pacticipant_id: db[:pacticipants].select(:id).where(name_like(:name, pacticipant_name)))
53
+ where(pacticipant_id: db[:pacticipants].select(:id).where(Sequel.name_like(:name, pacticipant_name)))
54
54
  end
55
55
 
56
56
  def for_version_and_environment(version, environment)
@@ -1,7 +1,5 @@
1
- require "sequel"
2
1
  require "sequel/plugins/serialization"
3
2
 
4
-
5
3
  module PactBroker
6
4
  module Deployments
7
5
  class Environment < Sequel::Model
@@ -1,5 +1,4 @@
1
- require "sequel"
2
- require "pact_broker/repositories/helpers"
1
+ require "pact_broker/dataset"
3
2
 
4
3
  module PactBroker
5
4
  module Deployments
@@ -14,7 +13,7 @@ module PactBroker
14
13
  plugin :insert_ignore, identifying_columns: [:version_id, :environment_id]
15
14
 
16
15
  dataset_module do
17
- include PactBroker::Repositories::Helpers
16
+ include PactBroker::Dataset
18
17
 
19
18
  def currently_supported
20
19
  where(support_ended_at: nil)
@@ -25,11 +24,11 @@ module PactBroker
25
24
  end
26
25
 
27
26
  def for_pacticipant_name(pacticipant_name)
28
- where(pacticipant_id: db[:pacticipants].select(:id).where(name_like(:name, pacticipant_name)))
27
+ where(pacticipant_id: db[:pacticipants].select(:id).where(Sequel.name_like(:name, pacticipant_name)))
29
28
  end
30
29
 
31
30
  def for_pacticipant_version_number(pacticipant_version_number)
32
- where(version_id: db[:versions].select(:id).where(name_like(:number, pacticipant_version_number)))
31
+ where(version_id: db[:versions].select(:id).where(Sequel.name_like(:number, pacticipant_version_number)))
33
32
  end
34
33
 
35
34
  def for_version_and_environment(version, environment)
@@ -0,0 +1,25 @@
1
+ # Pacticipant branch
2
+
3
+ Allowed methods: `GET`, `DELETE`
4
+
5
+ Path: `/pacticipants/{pacticipant}/branches/{branch}`
6
+
7
+ Get or delete a pacticipant branch.
8
+
9
+ ## Create
10
+
11
+ Branches cannot be created via the resource URL. They are created automatically when publishing contracts.
12
+
13
+ ## Get
14
+
15
+ ### Example
16
+
17
+ curl http://broker/pacticipants/Bar/branches/main -H "Accept: application/hal+json"
18
+
19
+ ## Delete
20
+
21
+ Deletes a pacticipant branch. Does NOT delete the associated pacticipant versions.
22
+
23
+ Send a `DELETE` request to the branch resource.
24
+
25
+ curl -XDELETE http://broker/pacticipants/Bar/branches/main
@@ -1,4 +1,4 @@
1
- require "pact_broker/db"
1
+ require "pact_broker/dataset"
2
2
 
3
3
  module PactBroker
4
4
  module Domain
@@ -6,15 +6,18 @@ module PactBroker
6
6
  set_primary_key([:name, :pacticipant_id])
7
7
  unrestrict_primary_key
8
8
 
9
+ plugin :timestamps, update_on_create: true
10
+
9
11
  associate(:many_to_one, :pacticipant, :class => "PactBroker::Domain::Pacticipant", :key => :pacticipant_id, :primary_key => :id)
10
12
 
11
13
  def <=> other
12
14
  name <=> other.name
13
15
  end
14
16
 
17
+ dataset_module do
18
+ include PactBroker::Dataset
19
+ end
15
20
  end
16
-
17
- Label.plugin :timestamps, update_on_create: true
18
21
  end
19
22
  end
20
23
 
@@ -1,4 +1,3 @@
1
- require "pact_broker/db"
2
1
  require "pact_broker/json"
3
2
  require "pact_broker/pacts/content"
4
3
 
@@ -23,10 +22,16 @@ module PactBroker
23
22
  :revision_number,
24
23
  :pact_version_sha,
25
24
  :head_tag_names
26
- attr_writer :consumer, :latest_verification
25
+
26
+ attr_writer :consumer,
27
+ :latest_verification,
28
+ :consumer_version_tag_names,
29
+ :consumer_version_branch_names
27
30
 
28
31
  def initialize attributes = {}
29
32
  @latest_verification = UnsetAttribute.new
33
+ @consumer_version_tag_names = UnsetAttribute.new
34
+ @consumer_version_branch_names = UnsetAttribute.new
30
35
  attributes.each_pair do | key, value |
31
36
  self.send(key.to_s + "=", value)
32
37
  end
@@ -45,11 +50,11 @@ module PactBroker
45
50
  end
46
51
 
47
52
  def consumer_version_tag_names
48
- consumer_version.tags.collect(&:name)
53
+ get_attribute_if_set :consumer_version_tag_names
49
54
  end
50
55
 
51
- def latest_consumer_version_tag_names= latest_consumer_version_tag_names
52
- @latest_consumer_version_tag_names = latest_consumer_version_tag_names
56
+ def consumer_version_branch_names
57
+ get_attribute_if_set :consumer_version_branch_names
53
58
  end
54
59
 
55
60
  def latest_verification
@@ -1,42 +1,12 @@
1
- require "pact_broker/db"
1
+ require "pact_broker/dataset"
2
2
  require "pact_broker/messages"
3
- require "pact_broker/repositories/helpers"
4
3
  require "pact_broker/domain/label"
5
4
  require "pact_broker/string_refinements"
6
5
  require "pact_broker/pacticipants/generate_display_name"
6
+ require "pact_broker/pacticipants/latest_version_for_pacticipant_eager_loader"
7
7
 
8
8
  module PactBroker
9
9
  module Domain
10
- class LatestVersionForPacticipantEagerLoader
11
- def self.call(eo, **_other)
12
- populate_associations(eo[:rows])
13
- end
14
-
15
- def self.populate_associations(pacticipants)
16
- pacticipants.each { | pacticipant | pacticipant.associations[:latest_version] = nil }
17
- pacticipant_ids = pacticipants.collect(&:id)
18
-
19
- max_orders = PactBroker::Domain::Version
20
- .where(pacticipant_id: pacticipant_ids)
21
- .select_group(:pacticipant_id)
22
- .select_append { max(order).as(latest_order) }
23
-
24
- max_orders_join = {
25
- Sequel[:max_orders][:latest_order] => Sequel[:versions][:order],
26
- Sequel[:max_orders][:pacticipant_id] => Sequel[:versions][:pacticipant_id]
27
- }
28
-
29
- latest_versions = PactBroker::Domain::Version
30
- .select_all_qualified
31
- .join(max_orders, max_orders_join, { table_alias: :max_orders})
32
-
33
- latest_versions.each do | version |
34
- pacticipant = pacticipants.find{ | p | p.id == version.pacticipant_id }
35
- pacticipant.associations[:latest_version] = version
36
- end
37
- end
38
- end
39
-
40
10
  class Pacticipant < Sequel::Model
41
11
 
42
12
  include Messages
@@ -55,13 +25,13 @@ module PactBroker
55
25
  one_to_one :latest_version, :class => "PactBroker::Domain::Version",
56
26
  primary_key: :id, key: :pacticipant_id,
57
27
  dataset: lambda { PactBroker::Domain::Version.where(pacticipant_id: id).order(Sequel.desc(:order)).limit(1) },
58
- eager_loader: LatestVersionForPacticipantEagerLoader
28
+ eager_loader: PactBroker::Pacticipants::LatestVersionForPacticipantEagerLoader
59
29
 
60
30
  one_to_many :branch_heads, class: "PactBroker::Versions::BranchHead", primary_key: :id, key: :pacticipant_id
61
31
  one_to_many :branches, class: "PactBroker::Versions::Branch", primary_key: :id, key: :pacticipant_id
62
32
 
63
33
  dataset_module do
64
- include PactBroker::Repositories::Helpers
34
+ include PactBroker::Dataset
65
35
 
66
36
  def with_main_branch_set
67
37
  exclude(main_branch: nil)
@@ -1,5 +1,4 @@
1
- require "pact_broker/db"
2
- require "pact_broker/repositories/helpers"
1
+ require "pact_broker/dataset"
3
2
  require "pact_broker/tags/eager_loaders"
4
3
 
5
4
  module PactBroker
@@ -24,7 +23,7 @@ module PactBroker
24
23
  eager_loader: PactBroker::Tags::EagerLoaders::HeadTag
25
24
 
26
25
  dataset_module do
27
- include PactBroker::Repositories::Helpers
26
+ include PactBroker::Dataset
28
27
 
29
28
  def join_pact_publications
30
29
  join(:pact_publications, { Sequel[:tags][:version_id] => Sequel[:pact_publications][:consumer_version_id] } )
@@ -32,9 +31,9 @@ module PactBroker
32
31
 
33
32
  def for(pacticipant_name, version_number, tag_name)
34
33
  where(
35
- version_id: db[:versions].select(:id).where(
34
+ version_id: PactBroker::Domain::Version.select(:id).where(
36
35
  number: version_number,
37
- pacticipant_id: db[:pacticipants].select(:id).where(name_like(:name, pacticipant_name))
36
+ pacticipant_id: PactBroker::Domain::Pacticipant.select(:id).where_name_like(:name, pacticipant_name)
38
37
  ),
39
38
  name: tag_name
40
39
  ).single_record
@@ -1,7 +1,5 @@
1
+ require "pact_broker/dataset"
1
2
  require "json"
2
- require "sequel"
3
- require "pact_broker/repositories/helpers"
4
- require "pact_broker/tags/tag_with_latest_flag"
5
3
  require "pact_broker/pacts/content"
6
4
  require "sequel/extensions/symbol_aref_refinement"
7
5
 
@@ -27,7 +25,7 @@ module PactBroker
27
25
  end
28
26
 
29
27
  dataset_module do
30
- include PactBroker::Repositories::Helpers
28
+ include PactBroker::Dataset
31
29
 
32
30
  def for_provider_name(provider_name)
33
31
  where(provider: PactBroker::Domain::Pacticipant.find_by_name(provider_name))