pact_broker 2.81.0 → 2.82.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/CHANGELOG.md +30 -0
  4. data/DEVELOPER_SETUP.md +1 -1
  5. data/README.md +7 -5
  6. data/config.ru +3 -28
  7. data/db/migrations/20210722_add_index_to_triggered_webhooks_webhook_uuid.rb +7 -0
  8. data/db/migrations/20210810_set_allow_contract_modification.rb +17 -0
  9. data/docs/CONFIGURATION.md +398 -0
  10. data/docs/configuration.yml +320 -0
  11. data/example/Gemfile +4 -4
  12. data/example/README.md +15 -22
  13. data/example/config.ru +1 -24
  14. data/example/config/pact_broker.yml +9 -0
  15. data/example/config/puma.rb +3 -0
  16. data/lib/db.rb +1 -1
  17. data/lib/pact_broker/api/authorization/resource_access_policy.rb +68 -0
  18. data/lib/pact_broker/api/authorization/resource_access_rules.rb +40 -0
  19. data/lib/pact_broker/api/decorators/deployed_version_decorator.rb +2 -0
  20. data/lib/pact_broker/api/decorators/released_version_decorator.rb +2 -0
  21. data/lib/pact_broker/api/middleware/basic_auth.rb +63 -0
  22. data/lib/pact_broker/api/resources/pact.rb +15 -6
  23. data/lib/pact_broker/api/resources/tag.rb +1 -14
  24. data/lib/pact_broker/app.rb +52 -30
  25. data/lib/pact_broker/config/basic_auth_configuration.rb +38 -0
  26. data/lib/pact_broker/config/load.rb +21 -10
  27. data/lib/pact_broker/config/runtime_configuration.rb +188 -0
  28. data/lib/pact_broker/config/runtime_configuration_coercion_methods.rb +41 -0
  29. data/lib/pact_broker/config/runtime_configuration_database_methods.rb +119 -0
  30. data/lib/pact_broker/config/runtime_configuration_logging_methods.rb +61 -0
  31. data/lib/pact_broker/configuration.rb +67 -131
  32. data/lib/pact_broker/contracts/notice.rb +4 -0
  33. data/lib/pact_broker/contracts/service.rb +4 -4
  34. data/lib/pact_broker/db/models.rb +3 -0
  35. data/lib/pact_broker/db/validate_encoding.rb +0 -4
  36. data/lib/pact_broker/deployments/deployed_version.rb +8 -2
  37. data/lib/pact_broker/deployments/deployed_version_service.rb +13 -6
  38. data/lib/pact_broker/deployments/environment.rb +1 -1
  39. data/lib/pact_broker/deployments/released_version.rb +8 -0
  40. data/lib/pact_broker/deployments/released_version_service.rb +12 -0
  41. data/lib/pact_broker/doc/views/provider-pacts-for-verification.markdown +4 -0
  42. data/lib/pact_broker/domain/pacticipant.rb +17 -13
  43. data/lib/pact_broker/domain/verification.rb +4 -22
  44. data/lib/pact_broker/domain/version.rb +9 -5
  45. data/lib/pact_broker/domain/webhook.rb +4 -0
  46. data/lib/pact_broker/error.rb +1 -0
  47. data/lib/pact_broker/errors.rb +1 -1
  48. data/lib/pact_broker/feature_toggle.rb +3 -5
  49. data/lib/pact_broker/hash_refinements.rb +0 -1
  50. data/lib/pact_broker/index/service.rb +4 -6
  51. data/lib/pact_broker/initializers/database_connection.rb +80 -0
  52. data/lib/pact_broker/integrations/integration.rb +5 -0
  53. data/lib/pact_broker/integrations/service.rb +4 -2
  54. data/lib/pact_broker/locale/en.yml +1 -0
  55. data/lib/pact_broker/logging.rb +2 -1
  56. data/lib/pact_broker/matrix/integration.rb +1 -1
  57. data/lib/pact_broker/matrix/parse_can_i_deploy_query.rb +2 -2
  58. data/lib/pact_broker/matrix/quick_row.rb +10 -0
  59. data/lib/pact_broker/matrix/repository.rb +64 -3
  60. data/lib/pact_broker/metrics/service.rb +16 -13
  61. data/lib/pact_broker/pacticipants/repository.rb +4 -0
  62. data/lib/pact_broker/pacticipants/service.rb +9 -1
  63. data/lib/pact_broker/pacts/pact_publication.rb +10 -13
  64. data/lib/pact_broker/pacts/pact_publication_dataset_module.rb +6 -1
  65. data/lib/pact_broker/pacts/pact_publication_selector_dataset_module.rb +1 -2
  66. data/lib/pact_broker/pacts/pact_version.rb +25 -11
  67. data/lib/pact_broker/pacts/pacts_for_verification_repository.rb +54 -77
  68. data/lib/pact_broker/pacts/selected_pact.rb +1 -1
  69. data/lib/pact_broker/pacts/selector.rb +15 -2
  70. data/lib/pact_broker/pacts/selectors.rb +4 -0
  71. data/lib/pact_broker/pacts/service.rb +4 -0
  72. data/lib/pact_broker/repositories/scopes.rb +12 -1
  73. data/lib/pact_broker/string_refinements.rb +6 -0
  74. data/lib/pact_broker/tags/service.rb +8 -1
  75. data/lib/pact_broker/test/http_test_data_builder.rb +11 -5
  76. data/lib/pact_broker/ui/views/index/_css_and_js.haml +11 -9
  77. data/lib/pact_broker/ui/views/index/_pagination.haml +3 -1
  78. data/lib/pact_broker/ui/views/layouts/main.haml +5 -3
  79. data/lib/pact_broker/ui/views/matrix/show.haml +10 -8
  80. data/lib/pact_broker/verifications/required_verification.rb +28 -0
  81. data/lib/pact_broker/verifications/service.rb +49 -1
  82. data/lib/pact_broker/version.rb +1 -1
  83. data/lib/pact_broker/versions/repository.rb +15 -0
  84. data/lib/pact_broker/versions/service.rb +32 -2
  85. data/lib/pact_broker/webhooks/event_listener.rb +3 -0
  86. data/lib/pact_broker/webhooks/trigger_service.rb +30 -14
  87. data/lib/pact_broker/webhooks/triggered_webhook.rb +1 -0
  88. data/lib/pact_broker/webhooks/webhook.rb +2 -2
  89. data/lib/pact_broker/webhooks/webhook_event.rb +6 -1
  90. data/lib/semantic_logger/formatters/short.rb +29 -0
  91. data/pact_broker.gemspec +1 -0
  92. data/script/data/auto-create-things-for-tags.rb +19 -0
  93. data/script/data/contract-published-requiring-verification.rb +27 -0
  94. data/script/{reproduce-issue-expand-currently-deployed.rb → data/expand-currently-deployed.rb} +0 -0
  95. data/script/docs/generate-configuration-docs.rb +86 -0
  96. data/spec/features/get_latest_pact_badge_spec.rb +1 -0
  97. data/spec/features/get_matrix_badge_spec.rb +1 -0
  98. data/spec/features/publish_pact_spec.rb +21 -7
  99. data/spec/features/wip_pacts_spec.rb +1 -1
  100. data/spec/fixtures/approvals/matrix_integration_environment_spec.approved.json +62 -0
  101. data/spec/fixtures/approvals/matrix_integration_ignore_spec.approved.json +124 -0
  102. data/spec/fixtures/approvals/matrix_integration_spec.approved.json +173 -0
  103. data/spec/fixtures/approvals/publish_contract_no_branch.approved.json +9 -9
  104. data/spec/fixtures/approvals/publish_contract_nothing_exists.approved.json +7 -7
  105. data/spec/fixtures/approvals/publish_contract_nothing_exists_with_webhook.approved.json +5 -5
  106. data/spec/fixtures/approvals/publish_contract_verification_already_exists.approved.json +5 -5
  107. data/spec/lib/pact_broker/api/middleware/basic_auth_spec.rb +312 -0
  108. data/spec/lib/pact_broker/api/resources/tag_spec.rb +14 -39
  109. data/spec/lib/pact_broker/app_basic_auth_spec.rb +122 -0
  110. data/spec/lib/pact_broker/config/load_spec.rb +33 -6
  111. data/spec/lib/pact_broker/config/runtime_configuration_logging_methods_spec.rb +22 -0
  112. data/spec/lib/pact_broker/config/runtime_configuration_spec.rb +71 -0
  113. data/spec/lib/pact_broker/configuration_spec.rb +51 -25
  114. data/spec/lib/pact_broker/errors/error_logger_spec.rb +3 -0
  115. data/spec/lib/pact_broker/feature_toggle_spec.rb +18 -19
  116. data/spec/lib/pact_broker/matrix/integration_environment_spec.rb +12 -0
  117. data/spec/lib/pact_broker/matrix/integration_ignore_spec.rb +15 -3
  118. data/spec/lib/pact_broker/matrix/integration_spec.rb +47 -6
  119. data/spec/lib/pact_broker/matrix/parse_can_i_deploy_query_spec.rb +16 -1
  120. data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +0 -2
  121. data/spec/lib/pact_broker/matrix/repository_spec.rb +0 -2
  122. data/spec/lib/pact_broker/metrics/service_spec.rb +44 -0
  123. data/spec/lib/pact_broker/pacticipants/service_spec.rb +28 -5
  124. data/spec/lib/pact_broker/pacts/pact_publication_selector_dataset_module_spec.rb +25 -0
  125. data/spec/lib/pact_broker/pacts/pact_version_spec.rb +30 -1
  126. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +107 -20
  127. data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +1 -1
  128. data/spec/lib/pact_broker/tags/service_spec.rb +24 -8
  129. data/spec/lib/pact_broker/verifications/service_spec.rb +146 -0
  130. data/spec/lib/pact_broker/versions/repository_spec.rb +38 -2
  131. data/spec/lib/pact_broker/versions/service_spec.rb +93 -2
  132. data/spec/lib/pact_broker/webhooks/trigger_service_spec.rb +54 -2
  133. data/spec/lib/rack/pact_broker/invalid_uri_protection_spec.rb +3 -3
  134. data/spec/spec_helper.rb +2 -1
  135. data/spec/support/approvals.rb +29 -0
  136. metadata +52 -13
  137. data/example/basic_auth/Gemfile +0 -5
  138. data/example/basic_auth/Procfile +0 -1
  139. data/example/basic_auth/README.md +0 -43
  140. data/example/basic_auth/config.ru +0 -19
  141. data/example/example_data.sql +0 -19
  142. data/spec/lib/pact_broker/config/save_and_load_spec.rb +0 -25
  143. data/spec/lib/pact_broker/pacts/service_find_for_verification_spec.rb +0 -50
@@ -13,7 +13,7 @@ module PactBroker
13
13
 
14
14
  def self.merge(selected_pacts)
15
15
  latest_selected_pact = selected_pacts.sort_by(&:consumer_version_order).last
16
- selectors = selected_pacts.collect(&:selectors).reduce(&:+)
16
+ selectors = selected_pacts.collect(&:selectors).reduce(&:+).sort
17
17
  SelectedPact.new(latest_selected_pact.pact, selectors)
18
18
  end
19
19
 
@@ -101,7 +101,7 @@ module PactBroker
101
101
  end
102
102
 
103
103
  def currently_deployed?
104
- currently_deployed
104
+ !!currently_deployed
105
105
  end
106
106
 
107
107
  def currently_supported= currently_supported
@@ -113,7 +113,7 @@ module PactBroker
113
113
  end
114
114
 
115
115
  def currently_supported?
116
- currently_supported
116
+ !!currently_supported
117
117
  end
118
118
 
119
119
  def environment_name= environment_name
@@ -204,6 +204,10 @@ module PactBroker
204
204
  Selector.new(hash)
205
205
  end
206
206
 
207
+ def for_consumer(consumer)
208
+ Selector.new(to_h.merge(consumer: consumer))
209
+ end
210
+
207
211
  def latest_for_main_branch?
208
212
  !!main_branch
209
213
  end
@@ -334,6 +338,15 @@ module PactBroker
334
338
  def == other
335
339
  super && consumer_version == other.consumer_version
336
340
  end
341
+
342
+ def <=> other
343
+ comparison = super
344
+ if comparison == 0
345
+ consumer_version.order <=> other.consumer_version.order
346
+ else
347
+ comparison
348
+ end
349
+ end
337
350
  end
338
351
  end
339
352
  end
@@ -43,6 +43,10 @@ module PactBroker
43
43
  Selectors.new(super)
44
44
  end
45
45
 
46
+ def sort
47
+ Selectors.new(super)
48
+ end
49
+
46
50
  def overall_latest?
47
51
  any?(&:overall_latest?)
48
52
  end
@@ -156,6 +156,10 @@ module PactBroker
156
156
  updated_pact
157
157
  end
158
158
 
159
+ def disallowed_modification?(existing_pact, new_json_content)
160
+ !PactBroker.configuration.allow_dangerous_contract_modification && existing_pact && existing_pact.pact_version_sha != generate_sha(new_json_content)
161
+ end
162
+
159
163
  private :update_pact
160
164
 
161
165
  # When no publication for the given consumer/provider/consumer version number exists
@@ -1,8 +1,19 @@
1
1
  module PactBroker
2
2
  module Repositories
3
3
  module Scopes
4
+ def with_no_scope
5
+ @unscoped = true
6
+ yield self
7
+ ensure
8
+ @unscoped = false
9
+ end
10
+
4
11
  def scope_for(scope)
5
- PactBroker.policy_scope!(scope)
12
+ if @unscoped == true
13
+ scope
14
+ else
15
+ PactBroker.policy_scope!(scope)
16
+ end
6
17
  end
7
18
 
8
19
  # For the times when it doesn't make sense to use the scoped class, this is a way to
@@ -6,6 +6,12 @@ module PactBroker
6
6
  end
7
7
  end
8
8
 
9
+ refine Numeric do
10
+ def blank?
11
+ false
12
+ end
13
+ end
14
+
9
15
  refine String do
10
16
  def not_blank?
11
17
  !blank?
@@ -1,15 +1,22 @@
1
1
  require "pact_broker/repositories"
2
+ require "pact_broker/configuration"
3
+ require "pact_broker/logging"
2
4
 
3
5
  module PactBroker
4
6
  module Tags
5
7
  module Service
6
8
  extend self
7
9
  extend PactBroker::Repositories
10
+ extend PactBroker::Services
11
+ include PactBroker::Logging
8
12
 
9
13
  def create args
14
+ tag_name = args.fetch(:tag_name)
10
15
  pacticipant = pacticipant_repository.find_by_name_or_create args.fetch(:pacticipant_name)
11
16
  version = version_repository.find_by_pacticipant_id_and_number_or_create pacticipant.id, args.fetch(:pacticipant_version_number)
12
- tag_repository.create version: version, name: args.fetch(:tag_name)
17
+ version_service.maybe_set_version_branch_from_tag(version, tag_name)
18
+ pacticipant_service.maybe_set_main_branch(version.pacticipant, tag_name)
19
+ tag_repository.create(version: version, name: tag_name)
13
20
  end
14
21
 
15
22
  def find args
@@ -180,17 +180,19 @@ module PactBroker
180
180
  self
181
181
  end
182
182
 
183
- def create_global_webhook_for_contract_changed(uuid: nil, url: "https://postman-echo.com/post", body: nil)
183
+ def create_global_webhook_for_event(uuid: nil, url: "https://postman-echo.com/post", body: nil, event_name: )
184
184
  puts "Creating global webhook for contract changed event with uuid #{uuid}"
185
185
  uuid ||= SecureRandom.uuid
186
186
  default_body = {
187
- "deployedProviderVersion" => "${pactbroker.currentlyDeployedProviderVersionNumber}",
187
+ "providerVersionNumber" => "${pactbroker.providerVersionNumber}",
188
+ "providerVersionBranch" => "${pactbroker.providerVersionBranch}",
189
+ "consumerVersionNumber" => "${pactbroker.consumerVersionNumber}",
188
190
  "consumerVersionBranch" => "${pactbroker.consumerVersionBranch}"
189
191
  }
190
192
  request_body = {
191
193
  "description" => "A webhook for all consumers and providers",
192
194
  "events" => [{
193
- "name" => "contract_content_changed"
195
+ "name" => event_name
194
196
  }],
195
197
  "request" => {
196
198
  "method" => "POST",
@@ -204,6 +206,10 @@ module PactBroker
204
206
  self
205
207
  end
206
208
 
209
+ def create_global_webhook_for_contract_changed(uuid: nil, url: "https://postman-echo.com/post", body: nil)
210
+ create_global_webhook_for_event(uuid: uuid, url: url, body: body, event_name: "contract_content_changed")
211
+ end
212
+
207
213
  def create_global_webhook_for_anything_published(uuid: nil, url: "https://postman-echo.com/post")
208
214
  puts "Creating global webhook for contract changed event with uuid #{uuid}"
209
215
  uuid ||= SecureRandom.uuid
@@ -248,8 +254,8 @@ module PactBroker
248
254
  self
249
255
  end
250
256
 
251
- def can_i_deploy(pacticipant:, version:, to:)
252
- can_i_deploy_response = client.get("can-i-deploy", { pacticipant: pacticipant, version: version, to: to} ).tap { |response| check_for_error(response) }
257
+ def can_i_deploy(pacticipant:, version:, to: nil, to_environment: nil)
258
+ can_i_deploy_response = client.get("can-i-deploy", { pacticipant: pacticipant, version: version, to: to, environment: to_environment}.compact ).tap { |response| check_for_error(response) }
253
259
  can = !!(can_i_deploy_response.body["summary"] || {})["deployable"]
254
260
  puts "can-i-deploy #{pacticipant} version #{version} to #{to}: #{can ? 'yes' : 'no'}"
255
261
  summary = can_i_deploy_response.body["summary"]
@@ -1,9 +1,11 @@
1
- %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/index.css"}
2
- %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/material-menu.css"}
3
- %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/material-icon.css"}
4
- %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/jquery-confirm.min.css"}
5
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/jquery.tablesorter.min.js"}
6
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/material-menu.js"}
7
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/index.js"}
8
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/clipboard.js"}
9
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/jquery-confirm.min.js"}
1
+ - require "pact_broker/version"
2
+
3
+ %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/index.css?v=#{PactBroker::VERSION}"}
4
+ %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/material-menu.css?v=#{PactBroker::VERSION}"}
5
+ %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/material-icon.css?v=#{PactBroker::VERSION}"}
6
+ %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/jquery-confirm.min.css?v=#{PactBroker::VERSION}"}
7
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/jquery.tablesorter.min.js?v=#{PactBroker::VERSION}"}
8
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/material-menu.js?v=#{PactBroker::VERSION}"}
9
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/index.js?v=#{PactBroker::VERSION}"}
10
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/clipboard.js?v=#{PactBroker::VERSION}"}
11
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/jquery-confirm.min.js?v=#{PactBroker::VERSION}"}
@@ -1,4 +1,6 @@
1
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/pagination.js"}
1
+ - require "pact_broker/version"
2
+
3
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/pagination.js?v=#{PactBroker::VERSION}"}
2
4
 
3
5
  :javascript
4
6
  const PAGE_NUMBER = #{page_number};
@@ -1,9 +1,11 @@
1
+ - require "pact_broker/version"
2
+
1
3
  <!DOCTYPE html>
2
4
  %html
3
5
  %head
4
6
  %title= defined?(title) ? title : ""
5
7
  %link{rel: 'shortcut icon', href: "#{base_url}/images/favicon.ico", type:'image/x-icon'}
6
- %link{rel: 'stylesheet', href: "#{base_url}/css/bootstrap.min.css"}
7
- %script{type: 'text/javascript', src:"#{base_url}/javascripts/jquery-3.5.1.min.js"}
8
- %script{type: 'text/javascript', src:"#{base_url}/js/bootstrap.bundle.min.js"}
8
+ %link{rel: 'stylesheet', href: "#{base_url}/css/bootstrap.min.css?v=#{PactBroker::VERSION}"}
9
+ %script{type: 'text/javascript', src:"#{base_url}/javascripts/jquery-3.5.1.min.js?v=#{PactBroker::VERSION}"}
10
+ %script{type: 'text/javascript', src:"#{base_url}/js/bootstrap.bundle.min.js?v=#{PactBroker::VERSION}"}
9
11
  != yield
@@ -1,12 +1,14 @@
1
+ - require "pact_broker/version"
2
+
1
3
  %body
2
- %link{rel: 'stylesheet', href: "#{base_url}/css/bootstrap.min.css"}
3
- %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/index.css"}
4
- %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/matrix.css"}
5
- %script{type: 'text/javascript', src: "#{base_url}/javascripts/jquery-3.5.1.min.js"}
6
- %script{type: 'text/javascript', src: "#{base_url}/javascripts/jquery.tablesorter.min.js"}
7
- %script{type: 'text/javascript', src: "#{base_url}/javascripts/matrix.js"}
8
- %script{type: 'text/javascript', src: "#{base_url}/javascripts/clipboard.js"}
9
- %script{type: 'text/javascript', src: "#{base_url}/js/bootstrap.bundle.min.js"}
4
+ %link{rel: 'stylesheet', href: "#{base_url}/css/bootstrap.min.css?v=#{PactBroker::VERSION}"}
5
+ %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/index.css?v=#{PactBroker::VERSION}"}
6
+ %link{rel: 'stylesheet', href: "#{base_url}/stylesheets/matrix.css?v=#{PactBroker::VERSION}"}
7
+ %script{type: 'text/javascript', src: "#{base_url}/javascripts/jquery-3.5.1.min.js?v=#{PactBroker::VERSION}"}
8
+ %script{type: 'text/javascript', src: "#{base_url}/javascripts/jquery.tablesorter.min.js?v=#{PactBroker::VERSION}"}
9
+ %script{type: 'text/javascript', src: "#{base_url}/javascripts/matrix.js?v=#{PactBroker::VERSION}"}
10
+ %script{type: 'text/javascript', src: "#{base_url}/javascripts/clipboard.js?v=#{PactBroker::VERSION}"}
11
+ %script{type: 'text/javascript', src: "#{base_url}/js/bootstrap.bundle.min.js?v=#{PactBroker::VERSION}"}
10
12
 
11
13
  .container
12
14
  .navbar-right
@@ -0,0 +1,28 @@
1
+ module PactBroker
2
+ module Verifications
3
+ class RequiredVerification
4
+ attr_reader :provider_version, :provider_version_descriptions
5
+
6
+ def initialize(attributes = {})
7
+ attributes.each do | (name, value) |
8
+ instance_variable_set("@#{name}", value) if respond_to?(name)
9
+ end
10
+ end
11
+
12
+ def == other
13
+ provider_version == other.provider_version && provider_version_descriptions == other.provider_version_descriptions
14
+ end
15
+
16
+ def + other
17
+ if provider_version != other.provider_version
18
+ raise PactBroker::Error.new("Can't + RequiredVerifications with different provider versions (#{provider_version.number}/#{other.provider_version.number})")
19
+ end
20
+
21
+ RequiredVerification.new(
22
+ provider_version: provider_version,
23
+ provider_version_descriptions: (provider_version_descriptions + other.provider_version_descriptions).uniq
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
@@ -5,6 +5,7 @@ require "pact_broker/verifications/summary_for_consumer_version"
5
5
  require "pact_broker/logging"
6
6
  require "pact_broker/hash_refinements"
7
7
  require "pact_broker/events/publisher"
8
+ require "pact_broker/verifications/required_verification"
8
9
 
9
10
  module PactBroker
10
11
  module Verifications
@@ -89,7 +90,16 @@ module PactBroker
89
90
  verification_repository.delete_all_verifications_between(consumer_name, options)
90
91
  end
91
92
 
92
- private
93
+ def calculate_required_verifications_for_pact(pact)
94
+ pact_version = PactBroker::Pacts::PactVersion.for_pact_domain(pact)
95
+ required_verifications = required_verifications_for_main_branch(pact_version) +
96
+ required_verifications_for_deployed_versions(pact_version) +
97
+ required_verifications_for_released_versions(pact_version)
98
+ required_verifications
99
+ .group_by(&:provider_version)
100
+ .values
101
+ .flat_map { | required_verifications_for_provider_version | required_verifications_for_provider_version.reduce(&:+) }
102
+ end
93
103
 
94
104
  def broadcast_events(verification, pact, event_context)
95
105
  event_params = {
@@ -105,6 +115,44 @@ module PactBroker
105
115
  broadcast(:provider_verification_failed, event_params)
106
116
  end
107
117
  end
118
+ private :broadcast_events
119
+
120
+ def identify_required_verification(pact_version, provider_version, description)
121
+ any_verifications = PactBroker::Domain::Verification.where(pact_version_id: pact_version.id, provider_version_id: provider_version.id).any?
122
+ if !any_verifications
123
+ RequiredVerification.new(provider_version: provider_version, provider_version_descriptions: [description])
124
+ end
125
+ end
126
+ private :identify_required_verification
127
+
128
+ def required_verifications_for_main_branch(pact_version)
129
+ latest_version_from_main_branch = [version_service.find_latest_version_from_main_branch(pact_version.provider)].compact
130
+
131
+ latest_version_from_main_branch.collect do | main_branch_version |
132
+ identify_required_verification(pact_version, main_branch_version, "latest version from main branch")
133
+ end.compact
134
+ end
135
+ private :required_verifications_for_main_branch
136
+
137
+ def required_verifications_for_deployed_versions(pact_version)
138
+ deployed_versions = deployed_version_service.with_no_scope do | unscoped_service |
139
+ unscoped_service.find_currently_deployed_versions_for_pacticipant(pact_version.provider)
140
+ end
141
+ deployed_versions.collect do | deployed_version |
142
+ identify_required_verification(pact_version, deployed_version.version, "currently deployed version (#{deployed_version.environment_name})")
143
+ end.compact
144
+ end
145
+ private :required_verifications_for_deployed_versions
146
+
147
+ def required_verifications_for_released_versions(pact_version)
148
+ released_versions = released_version_service.with_no_scope do | unscoped_service |
149
+ unscoped_service.find_currently_supported_versions_for_pacticipant(pact_version.provider)
150
+ end
151
+ released_versions.collect do | released_version |
152
+ identify_required_verification(pact_version, released_version.version, "currently released version (#{released_version.environment_name})")
153
+ end.compact
154
+ end
155
+ private :required_verifications_for_released_versions
108
156
  end
109
157
  end
110
158
  end
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = "2.81.0"
2
+ VERSION = "2.82.0"
3
3
  end
@@ -128,6 +128,21 @@ module PactBroker
128
128
  def find_versions_for_selector(selector)
129
129
  PactBroker::Domain::Version.select_all_qualified.for_selector(selector).all
130
130
  end
131
+
132
+ def set_branch_if_unset(version, branch)
133
+ version.update(branch: branch) if version.branch.nil?
134
+ version
135
+ end
136
+
137
+ def find_latest_version_from_main_branch(pacticipant)
138
+ if pacticipant.main_branch
139
+ latest_from_main_branch = PactBroker::Domain::Version
140
+ .latest_versions_for_pacticipant_branches(pacticipant.id, pacticipant.main_branch)
141
+ .single_record
142
+
143
+ latest_from_main_branch || find_by_pacticipant_name_and_latest_tag(pacticipant.name, pacticipant.main_branch)
144
+ end
145
+ end
131
146
  end
132
147
  end
133
148
  end
@@ -1,3 +1,4 @@
1
+ require "pact_broker/logging"
1
2
  require "pact_broker/repositories"
2
3
  require "pact_broker/messages"
3
4
 
@@ -6,6 +7,8 @@ module PactBroker
6
7
  class Service
7
8
  extend PactBroker::Messages
8
9
  extend PactBroker::Repositories
10
+ extend PactBroker::Services
11
+ include PactBroker::Logging
9
12
 
10
13
  def self.conflict_errors(_existing_version, _open_struct_version, _version_url)
11
14
  # This validation is causing problems in the PF build when branches are merged
@@ -38,12 +41,20 @@ module PactBroker
38
41
 
39
42
  def self.create_or_overwrite(pacticipant_name, version_number, version)
40
43
  pacticipant = pacticipant_repository.find_by_name_or_create(pacticipant_name)
41
- version_repository.create_or_overwrite(pacticipant, version_number, version)
44
+ version = version_repository.create_or_overwrite(pacticipant, version_number, version)
45
+ pacticipant_service.maybe_set_main_branch(pacticipant, version.branch)
46
+ version
42
47
  end
43
48
 
44
49
  def self.create_or_update(pacticipant_name, version_number, version)
45
50
  pacticipant = pacticipant_repository.find_by_name_or_create(pacticipant_name)
46
- version_repository.create_or_update(pacticipant, version_number, version)
51
+ version = version_repository.create_or_update(pacticipant, version_number, version)
52
+ pacticipant_service.maybe_set_main_branch(pacticipant, version.branch)
53
+ version
54
+ end
55
+
56
+ def self.find_latest_version_from_main_branch(pacticipant)
57
+ version_repository.find_latest_version_from_main_branch(pacticipant)
47
58
  end
48
59
 
49
60
  def self.delete version
@@ -53,6 +64,25 @@ module PactBroker
53
64
  verification_repository.delete_by_provider_version_id version.id
54
65
  version_repository.delete_by_id version.id
55
66
  end
67
+
68
+ def self.maybe_set_version_branch_from_tag(version, tag_name)
69
+ if use_tag_as_branch?(version) && !version.branch
70
+ logger.info "Setting #{version.pacticipant.name} version #{version.number} branch to '#{tag_name}' from first tag (because use_first_tag_as_branch=true)"
71
+ version_repository.set_branch_if_unset(version, tag_name)
72
+ end
73
+ end
74
+
75
+ def self.use_tag_as_branch?(version)
76
+ version.tags.count == 0 &&
77
+ PactBroker.configuration.use_first_tag_as_branch &&
78
+ ((now - version.created_at.to_datetime) * 24 * 60 * 60) <= PactBroker.configuration.use_first_tag_as_branch_time_limit
79
+ end
80
+ private_class_method :use_tag_as_branch?
81
+
82
+ def self.now
83
+ Time.now.utc.to_datetime
84
+ end
85
+ private_class_method :now
56
86
  end
57
87
  end
58
88
  end