pact_broker 2.76.1 → 2.76.2

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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/ISSUES.md +10 -2
  4. data/docker-compose-issue-repro-with-pact-broker-docker-image.yml +16 -5
  5. data/lib/pact_broker/api/resources/verifications.rb +5 -2
  6. data/lib/pact_broker/api/resources/webhook_execution.rb +1 -1
  7. data/lib/pact_broker/domain/webhook.rb +8 -8
  8. data/lib/pact_broker/hash_refinements.rb +4 -0
  9. data/lib/pact_broker/pacts/service.rb +4 -2
  10. data/lib/pact_broker/test/http_test_data_builder.rb +63 -18
  11. data/lib/pact_broker/verifications/service.rb +2 -1
  12. data/lib/pact_broker/version.rb +1 -1
  13. data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +10 -3
  14. data/lib/pact_broker/webhooks/service.rb +8 -7
  15. data/lib/pact_broker/webhooks/trigger_service.rb +56 -23
  16. data/lib/pact_broker/webhooks/triggered_webhook.rb +3 -1
  17. data/script/reproduce-issue-starting-up.rb +13 -23
  18. data/script/reproduce-issue.rb +2 -1
  19. data/script/trigger-release.sh +1 -1
  20. data/script/webhook-server.ru +5 -5
  21. data/spec/lib/pact_broker/api/resources/verifications_spec.rb +2 -5
  22. data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +3 -2
  23. data/spec/lib/pact_broker/domain/webhook_spec.rb +6 -6
  24. data/spec/lib/pact_broker/pacts/service_spec.rb +7 -5
  25. data/spec/lib/pact_broker/verifications/service_spec.rb +4 -1
  26. data/spec/lib/pact_broker/webhooks/render_spec.rb +6 -5
  27. data/spec/lib/pact_broker/webhooks/service_spec.rb +13 -9
  28. data/spec/lib/pact_broker/webhooks/trigger_service_spec.rb +60 -18
  29. metadata +2 -3
  30. data/docker-compose-issue-repro.yml +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1ab8b654502c5bbc4d263c4bd14fdb0e6dc3771173cfdf21a01118143528bd4
4
- data.tar.gz: b1d929d7bfe56369c5985b94ad88f9adf3abdb27e9177b6249ba7cd68d03c85d
3
+ metadata.gz: cdc8ed42038e4b622005f53471a000d870efd99a6dbd6b773aa9e8a3f9a993cb
4
+ data.tar.gz: d2f42cd3e13007471cdd33fabbe515afa9c9ff4896566868accd9961f66f557f
5
5
  SHA512:
6
- metadata.gz: ca79f6928c69425d89d0fa179094d007f26d5f25f02ee7fc2be771bb4208d2ecaef136af5391feea4c92588876e7162d205774451d00f9175463f03b9f1cdcd9
7
- data.tar.gz: febb82748bb5929d393af212797a3d9c484c9825a8c83bc44e4d52aa7cb6fbce93863decb305a7d6ed3160a3b447bed6368339a38322f6084fb34de97f3698cc
6
+ metadata.gz: a250f5f452356d3a9eb87659933cc47d0e947b7ce10a8c984d7cd296a28bc9be7dcfe82bd37fba29919f570a949b9b4a46b1622d6d242b92698268e54018aadf
7
+ data.tar.gz: c136cbe836ed813de2819480cf3347de86248f00258e0f8e89ec33375cf0c929186a65c51ef620995c11d2c596d496bec858c430894f80bacd6f647877f4af3e
@@ -1,3 +1,10 @@
1
+ <a name="v2.76.2"></a>
2
+ ### v2.76.2 (2021-01-29)
3
+
4
+ #### Bug Fixes
5
+
6
+ * trigger one webhook for each pact publication that the verified content belongs to when using the 'pacts for verification' API (#378) ([114ccad0](/../../commit/114ccad0))
7
+
1
8
  <a name="v2.76.1"></a>
2
9
  ### v2.76.1 (2021-01-28)
3
10
 
data/ISSUES.md CHANGED
@@ -11,13 +11,21 @@ To use it:
11
11
  * Run the Pact Broker using a specific Pact Broker Docker image by setting the required tag for the pact-broker service in the docker-compose-issue-repro-with-pact-broker-docker-image.yml file.
12
12
 
13
13
  ```
14
- docker-compose -f docker-compose-issue-repro-with-pact-broker-docker-image.yml up --build pact-broker
14
+ # might need to try twice if it doesn't connect to postgres
15
+ docker-compose -f docker-compose-issue-repro-with-pact-broker-docker-image.yml up pact-broker
16
+
17
+ # if needing webhooks - new window
18
+ docker-compose -f docker-compose-issue-repro-with-pact-broker-docker-image.yml up webhook-server
19
+
20
+ # new window
21
+ docker-compose -f docker-compose-issue-repro-with-pact-broker-docker-image.yml run repro-issue
22
+
15
23
  ```
16
24
 
17
25
  * Run the reproduction script.
18
26
 
19
27
  ```
20
- docker-compose -f docker-compose-issue-repro-with-pact-broker-docker-image.yml up repro-issue
28
+ docker-compose -f docker-compose-issue-repro-with-pact-broker-docker-image.yml run repro-issue
21
29
  ```
22
30
 
23
31
  You can modify `script/reproduce-issue.rb` and then re-run it with the change applied.
@@ -11,23 +11,34 @@ services:
11
11
  POSTGRES_DB: postgres
12
12
 
13
13
  pact-broker:
14
- image: pactfoundation/pact-broker:2.73.0.0
14
+ image: pactfoundation/pact-broker:2.76.0.0
15
15
  ports:
16
16
  - "9292:9292"
17
- depends_on:
18
- - postgres
17
+ # depends_on:
18
+ # - postgres
19
19
  environment:
20
20
  PACT_BROKER_PORT: '9292'
21
- PACT_BROKER_DATABASE_URL: "postgres://postgres:password@postgres/postgres"
21
+ #PACT_BROKER_DATABASE_URL: "postgres://postgres:password@postgres/postgres"
22
+ PACT_BROKER_DATABASE_URL: "sqlite:////tmp/pact_broker.sqlite3"
22
23
  PACT_BROKER_LOG_LEVEL: INFO
23
24
  PACT_BROKER_SQL_LOG_LEVEL: DEBUG
25
+ PACT_BROKER_WEBHOOK_SCHEME_WHITELIST: "http https"
26
+ PACT_BROKER_WEBHOOK_HOST_WHITELIST: "/.*/"
24
27
 
25
28
  repro-issue:
26
29
  build: .
27
30
  depends_on:
28
31
  - pact-broker
29
- command: dockerize -wait http://pact-broker:9292 -timeout 30s /home/script/reproduce-issue.rb
32
+ command: -wait http://pact-broker:9292 -timeout 30s /home/script/reproduce-issue.rb
33
+ entrypoint: dockerize
30
34
  environment:
31
35
  - PACT_BROKER_BASE_URL=http://pact-broker:9292
32
36
  volumes:
33
37
  - $PWD:/home
38
+ working_dir: /home
39
+
40
+ webhook-server:
41
+ build: .
42
+ entrypoint: ["/bin/sh", "-c", "bundle exec rackup -p 9393 -o 0.0.0.0 /home/script/webhook-server.ru"]
43
+ volumes:
44
+ - ./script/webhook-server.ru:/home/script/webhook-server.ru
@@ -50,7 +50,7 @@ module PactBroker
50
50
  end
51
51
 
52
52
  def from_json
53
- verification = verification_service.create(next_verification_number, verification_params, pact, webhook_options)
53
+ verification = verification_service.create(next_verification_number, verification_params, pact, event_context, webhook_options)
54
54
  response.body = decorator_for(verification).to_json(decorator_options)
55
55
  true
56
56
  end
@@ -81,11 +81,14 @@ module PactBroker
81
81
  metadata[:wip] == 'true'
82
82
  end
83
83
 
84
+ def event_context
85
+ metadata
86
+ end
87
+
84
88
  def webhook_options
85
89
  {
86
90
  database_connector: database_connector,
87
91
  webhook_execution_configuration: webhook_execution_configuration
88
- .with_webhook_context(metadata)
89
92
  }
90
93
  end
91
94
 
@@ -26,7 +26,7 @@ module PactBroker
26
26
  end
27
27
 
28
28
  def process_post
29
- webhook_execution_result = webhook_service.test_execution(webhook, webhook_execution_configuration)
29
+ webhook_execution_result = webhook_service.test_execution(webhook, webhook_execution_configuration.webhook_context, webhook_execution_configuration)
30
30
  response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
31
31
  response.body = post_response_body(webhook_execution_result)
32
32
  true
@@ -52,15 +52,15 @@ module PactBroker
52
52
  request && request.description
53
53
  end
54
54
 
55
- def execute pact, verification, options
56
- logger.info "Executing #{self} webhook_context=#{options.fetch(:webhook_context)}"
57
- webhook_request = request.build(template_parameters(pact, verification, options))
55
+ def execute pact, verification, event_context, options
56
+ logger.info "Executing #{self} event_context=#{event_context}"
57
+ webhook_request = request.build(template_parameters(pact, verification, event_context, options))
58
58
  http_response, error = execute_request(webhook_request)
59
59
 
60
60
  PactBroker::Webhooks::WebhookExecutionResult.new(
61
61
  webhook_request.http_request,
62
62
  http_response,
63
- generate_logs(webhook_request, http_response, error, options[:webhook_context], options.fetch(:logging_options)),
63
+ generate_logs(webhook_request, http_response, error, event_context, options.fetch(:logging_options)),
64
64
  error
65
65
  )
66
66
  end
@@ -106,18 +106,18 @@ module PactBroker
106
106
  return http_response, error
107
107
  end
108
108
 
109
- def template_parameters(pact, verification, options)
110
- PactBroker::Webhooks::PactAndVerificationParameters.new(pact, verification, options.fetch(:webhook_context)).to_hash
109
+ def template_parameters(pact, verification, event_context, options)
110
+ PactBroker::Webhooks::PactAndVerificationParameters.new(pact, verification, event_context).to_hash
111
111
  end
112
112
 
113
- def generate_logs(webhook_request, http_response, error, webhook_context, logging_options)
113
+ def generate_logs(webhook_request, http_response, error, event_context, logging_options)
114
114
  webhook_request_logger = PactBroker::Webhooks::WebhookRequestLogger.new(logging_options)
115
115
  webhook_request_logger.log(
116
116
  uuid,
117
117
  webhook_request,
118
118
  http_response,
119
119
  error,
120
- webhook_context
120
+ event_context
121
121
  )
122
122
  end
123
123
  end
@@ -30,6 +30,10 @@ module PactBroker
30
30
  keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
31
31
  end
32
32
 
33
+ def without(*keys)
34
+ reject { |k,_| keys.include?(k) }
35
+ end
36
+
33
37
  def camelcase_keys
34
38
  camelcase_keys_private(self)
35
39
  end
@@ -152,7 +152,8 @@ module PactBroker
152
152
  update_params = { pact_version_sha: pact_version_sha, json_content: json_content }
153
153
  updated_pact = pact_repository.update(existing_pact.id, update_params)
154
154
 
155
- webhook_trigger_service.trigger_webhooks_for_updated_pact(existing_pact, updated_pact, merge_consumer_version_info(webhook_options, updated_pact))
155
+ event_context = { consumer_version_tags: updated_pact.consumer_version_tag_names }
156
+ webhook_trigger_service.trigger_webhooks_for_updated_pact(existing_pact, updated_pact, event_context, merge_consumer_version_info(webhook_options, updated_pact))
156
157
 
157
158
  updated_pact
158
159
  end
@@ -170,7 +171,8 @@ module PactBroker
170
171
  pact_version_sha: pact_version_sha,
171
172
  json_content: json_content
172
173
  )
173
- webhook_trigger_service.trigger_webhooks_for_new_pact(pact, merge_consumer_version_info(webhook_options, pact))
174
+ event_context = { consumer_version_tags: pact.consumer_version_tag_names }
175
+ webhook_trigger_service.trigger_webhooks_for_new_pact(pact, event_context, merge_consumer_version_info(webhook_options, pact))
174
176
  pact
175
177
  end
176
178
 
@@ -24,8 +24,8 @@ module PactBroker
24
24
  end
25
25
  end
26
26
 
27
- def sleep
28
- Kernel.sleep 0.5
27
+ def sleep(seconds = 0.5)
28
+ Kernel.sleep(seconds)
29
29
  self
30
30
  end
31
31
 
@@ -111,28 +111,22 @@ module PactBroker
111
111
  self
112
112
  end
113
113
 
114
+ def verify_latest_pact_for_tag(success: true, provider: last_provider_name, consumer: last_consumer_name, consumer_version_tag: , provider_version:, provider_version_tag: nil)
115
+ @last_provider_name = provider
116
+ @last_consumer_name = consumer
117
+ url_of_pact_to_verify = "pacts/provider/#{encode(provider)}/consumer/#{encode(consumer)}/latest/#{encode(consumer_version_tag)}"
118
+ publish_verification_results(url_of_pact_to_verify, provider, provider_version, provider_version_tag, success)
119
+ separate
120
+ self
121
+ end
122
+
114
123
  def verify_pact(index: 0, success:, provider: last_provider_name, provider_version_tag: , provider_version: )
115
124
  @last_provider_name = provider
116
125
  pact_to_verify = @pacts_for_verification_response.body["_embedded"]["pacts"][index]
117
126
  raise "No pact found to verify at index #{index}" unless pact_to_verify
118
127
  url_of_pact_to_verify = pact_to_verify["_links"]["self"]["href"]
119
128
 
120
- [*provider_version_tag].each do | tag |
121
- create_tag(pacticipant: provider, version: provider_version, tag: tag)
122
- end
123
- puts "" if [*provider_version_tag].any?
124
-
125
- pact_response = client.get(url_of_pact_to_verify).tap { |response| check_for_error(response) }
126
- verification_results_url = pact_response.body["_links"]["pb:publish-verification-results"]["href"]
127
-
128
- results = {
129
- success: success,
130
- testResults: [],
131
- providerApplicationVersion: provider_version
132
- }
133
- puts "Publishing verification"
134
- puts results.to_yaml
135
- response = client.post(verification_results_url, results.to_json).tap { |response| check_for_error(response) }
129
+ publish_verification_results(url_of_pact_to_verify, provider, provider_version, provider_version_tag, success)
136
130
  separate
137
131
  self
138
132
  end
@@ -156,6 +150,36 @@ module PactBroker
156
150
  self
157
151
  end
158
152
 
153
+ def create_global_webhook_for_verification_published(uuid: nil, url: "https://postman-echo.com/post")
154
+ puts "Creating global webhook for contract changed event with uuid #{uuid}"
155
+ uuid ||= SecureRandom.uuid
156
+ request_body = {
157
+ "description" => "A webhook for all consumers and providers",
158
+ "events" => [{
159
+ "name" => "contract_published"
160
+ },{
161
+ "name" => "provider_verification_published"
162
+ }],
163
+ "request" => {
164
+ "method" => "POST",
165
+ "url" => url,
166
+ "headers" => { "Content-Type" => "application/json"},
167
+ "body" => {
168
+ "eventName" => "${pactbroker.eventName}",
169
+ "consumerVersionNumber" => "${pactbroker.consumerVersionNumber}",
170
+ "consumerVersionTags" => "${pactbroker.consumerVersionTags}",
171
+ "githubVerificationStatus" => "${pactbroker.githubVerificationStatus}",
172
+ "providerVersionNumber" => "${pactbroker.providerVersionNumber}",
173
+ "providerVersionTags" => "${pactbroker.providerVersionTags}"
174
+ }
175
+ }
176
+ }
177
+ path = "webhooks/#{uuid}"
178
+ response = client.put(path, request_body.to_json).tap { |response| check_for_error(response) }
179
+ separate
180
+ self
181
+ end
182
+
159
183
  def delete_webhook(uuid:)
160
184
  puts "Deleting webhook with uuid #{uuid}"
161
185
  path = "webhooks/#{uuid}"
@@ -220,6 +244,27 @@ module PactBroker
220
244
  }
221
245
  end
222
246
 
247
+ private
248
+
249
+ def publish_verification_results(url_of_pact_to_verify, provider, provider_version, provider_version_tag, success)
250
+ [*provider_version_tag].each do | tag |
251
+ create_tag(pacticipant: provider, version: provider_version, tag: tag)
252
+ end
253
+ puts "" if [*provider_version_tag].any?
254
+
255
+ pact_response = client.get(url_of_pact_to_verify).tap { |response| check_for_error(response) }
256
+ verification_results_url = pact_response.body["_links"]["pb:publish-verification-results"]["href"]
257
+
258
+ results = {
259
+ success: success,
260
+ testResults: [],
261
+ providerApplicationVersion: provider_version
262
+ }
263
+ puts "Publishing verification"
264
+ puts results.to_yaml
265
+ response = client.post(verification_results_url, results.to_json).tap { |response| check_for_error(response) }
266
+ end
267
+
223
268
  def encode string
224
269
  ERB::Util.url_encode(string)
225
270
  end
@@ -20,7 +20,7 @@ module PactBroker
20
20
  verification_repository.next_number
21
21
  end
22
22
 
23
- def create next_verification_number, params, pact, webhook_options
23
+ def create next_verification_number, params, pact, event_context, webhook_options
24
24
  logger.info "Creating verification #{next_verification_number} for pact_id=#{pact.id}", payload: params.reject{ |k,_| k == "testResults"}
25
25
  verification = PactBroker::Domain::Verification.new
26
26
  provider_version_number = params.fetch('providerApplicationVersion')
@@ -35,6 +35,7 @@ module PactBroker
35
35
  webhook_trigger_service.trigger_webhooks_for_verification_results_publication(
36
36
  pact,
37
37
  verification,
38
+ event_context.merge(provider_version_tags: verification.provider_version_tag_names),
38
39
  webhook_options.deep_merge(webhook_execution_configuration: execution_configuration)
39
40
  )
40
41
  verification
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = '2.76.1'
2
+ VERSION = '2.76.2'
3
3
  end
@@ -13,6 +13,7 @@ module PactBroker
13
13
  BITBUCKET_VERIFICATION_STATUS = 'pactbroker.bitbucketVerificationStatus'
14
14
  CONSUMER_LABELS = 'pactbroker.consumerLabels'
15
15
  PROVIDER_LABELS = 'pactbroker.providerLabels'
16
+ EVENT_NAME = 'pactbroker.eventName'
16
17
 
17
18
  ALL = [
18
19
  CONSUMER_NAME,
@@ -26,7 +27,8 @@ module PactBroker
26
27
  GITHUB_VERIFICATION_STATUS,
27
28
  BITBUCKET_VERIFICATION_STATUS,
28
29
  CONSUMER_LABELS,
29
- PROVIDER_LABELS
30
+ PROVIDER_LABELS,
31
+ EVENT_NAME
30
32
  ]
31
33
 
32
34
  def initialize(pact, trigger_verification, webhook_context)
@@ -49,7 +51,8 @@ module PactBroker
49
51
  GITHUB_VERIFICATION_STATUS => github_verification_status,
50
52
  BITBUCKET_VERIFICATION_STATUS => bitbucket_verification_status,
51
53
  CONSUMER_LABELS => pacticipant_labels(pact && pact.consumer),
52
- PROVIDER_LABELS => pacticipant_labels(pact && pact.provider)
54
+ PROVIDER_LABELS => pacticipant_labels(pact && pact.provider),
55
+ EVENT_NAME => event_name
53
56
  }
54
57
  end
55
58
 
@@ -116,6 +119,10 @@ module PactBroker
116
119
  def pacticipant_labels pacticipant
117
120
  pacticipant && pacticipant.labels ? pacticipant.labels.collect(&:name).join(", ") : ""
118
121
  end
122
+
123
+ def event_name
124
+ webhook_context.fetch(:event_name)
125
+ end
119
126
  end
120
127
  end
121
- end
128
+ end
@@ -87,7 +87,7 @@ module PactBroker
87
87
  webhook_repository.find_all
88
88
  end
89
89
 
90
- def self.test_execution webhook, execution_configuration
90
+ def self.test_execution webhook, event_context, execution_configuration
91
91
  merged_options = execution_configuration.with_failure_log_message("Webhook execution failed").to_hash
92
92
 
93
93
  verification = nil
@@ -96,7 +96,7 @@ module PactBroker
96
96
  end
97
97
 
98
98
  pact = pact_service.search_for_latest_pact(consumer_name: webhook.consumer_name, provider_name: webhook.provider_name) || PactBroker::Pacts::PlaceholderPact.new
99
- webhook.execute(pact, verification, merged_options)
99
+ webhook.execute(pact, verification, event_context.merge(event_name: "test"), merged_options)
100
100
  end
101
101
 
102
102
  def self.execute_triggered_webhook_now triggered_webhook, webhook_execution_configuration_hash
@@ -121,23 +121,24 @@ module PactBroker
121
121
  webhook_repository.find_by_consumer_and_provider consumer, provider
122
122
  end
123
123
 
124
- def self.trigger_webhooks pact, verification, event_name, options
124
+ def self.trigger_webhooks pact, verification, event_name, event_context, options
125
125
  webhooks = webhook_repository.find_by_consumer_and_or_provider_and_event_name pact.consumer, pact.provider, event_name
126
126
 
127
127
  if webhooks.any?
128
128
  webhook_execution_configuration = options.fetch(:webhook_execution_configuration).with_webhook_context(event_name: event_name)
129
- run_later(webhooks, pact, verification, event_name, options.merge(webhook_execution_configuration: webhook_execution_configuration))
129
+ # bit messy to merge in base_url here, but easier than a big refactor
130
+ base_url = options.fetch(:webhook_execution_configuration).webhook_context.fetch(:base_url)
131
+ run_later(webhooks, pact, verification, event_name, event_context.merge(event_name: event_name, base_url: base_url), options.merge(webhook_execution_configuration: webhook_execution_configuration))
130
132
  else
131
133
  logger.info "No enabled webhooks found for consumer \"#{pact.consumer.name}\" and provider \"#{pact.provider.name}\" and event #{event_name}"
132
134
  end
133
135
  end
134
136
 
135
- def self.run_later webhooks, pact, verification, event_name, options
137
+ def self.run_later webhooks, pact, verification, event_name, event_context, options
136
138
  trigger_uuid = next_uuid
137
139
  webhooks.each do | webhook |
138
140
  begin
139
- webhook_context = options.fetch(:webhook_execution_configuration).webhook_context
140
- triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, verification, RESOURCE_CREATION, event_name, webhook_context)
141
+ triggered_webhook = webhook_repository.create_triggered_webhook(trigger_uuid, webhook, pact, verification, RESOURCE_CREATION, event_name, event_context)
141
142
  logger.info "Scheduling job for webhook with uuid #{webhook.uuid}"
142
143
  logger.debug "Schedule webhook with options #{options}"
143
144
  job_data = { triggered_webhook: triggered_webhook }.deep_merge(options)
@@ -1,4 +1,5 @@
1
1
  require 'pact_broker/services'
2
+ require 'pact_broker/hash_refinements'
2
3
 
3
4
  module PactBroker
4
5
  module Webhooks
@@ -8,50 +9,56 @@ module PactBroker
8
9
  extend PactBroker::Repositories
9
10
  extend PactBroker::Services
10
11
  include PactBroker::Logging
12
+ using PactBroker::HashRefinements
11
13
 
12
- def trigger_webhooks_for_new_pact(pact, webhook_options)
13
- webhook_service.trigger_webhooks pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, webhook_options
14
+ def trigger_webhooks_for_new_pact(pact, event_context, webhook_options)
15
+ webhook_service.trigger_webhooks pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, event_context, webhook_options
14
16
  if pact_is_new_or_newly_tagged_or_pact_has_changed_since_previous_version?(pact)
15
- webhook_service.trigger_webhooks pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, webhook_options
17
+ webhook_service.trigger_webhooks pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, event_context, webhook_options
16
18
  else
17
19
  logger.info "Pact content has not changed since previous version, not triggering webhooks for changed content"
18
20
  end
19
21
  end
20
22
 
21
- def trigger_webhooks_for_updated_pact(existing_pact, updated_pact, webhook_options)
22
- webhook_service.trigger_webhooks updated_pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, webhook_options
23
+ def trigger_webhooks_for_updated_pact(existing_pact, updated_pact, event_context, webhook_options)
24
+ webhook_service.trigger_webhooks updated_pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, event_context, webhook_options
23
25
  # TODO this should use the sha!
24
26
  if existing_pact.pact_version_sha != updated_pact.pact_version_sha
25
27
  logger.info "Existing pact for version #{existing_pact.consumer_version_number} has been updated with new content, triggering webhooks for changed content"
26
- webhook_service.trigger_webhooks updated_pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, webhook_options
28
+ webhook_service.trigger_webhooks updated_pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, event_context, webhook_options
27
29
  else
28
30
  logger.info "Pact content has not changed since previous revision, not triggering webhooks for changed content"
29
31
  end
30
32
  end
31
33
 
32
- def trigger_webhooks_for_verification_results_publication(pact, verification, webhook_options)
33
- if verification.success
34
- webhook_service.trigger_webhooks(
35
- pact,
36
- verification,
37
- PactBroker::Webhooks::WebhookEvent::VERIFICATION_SUCCEEDED,
38
- webhook_options
39
- )
40
- else
34
+ def trigger_webhooks_for_verification_results_publication(pact, verification, event_context, webhook_options)
35
+ expand_events(event_context).each do | reconstituted_event_context |
36
+ if verification.success
37
+ webhook_service.trigger_webhooks(
38
+ pact,
39
+ verification,
40
+ PactBroker::Webhooks::WebhookEvent::VERIFICATION_SUCCEEDED,
41
+ reconstituted_event_context,
42
+ webhook_options
43
+ )
44
+ else
45
+ webhook_service.trigger_webhooks(
46
+ pact,
47
+ verification,
48
+ PactBroker::Webhooks::WebhookEvent::VERIFICATION_FAILED,
49
+ reconstituted_event_context,
50
+ webhook_options
51
+ )
52
+ end
53
+
41
54
  webhook_service.trigger_webhooks(
42
55
  pact,
43
56
  verification,
44
- PactBroker::Webhooks::WebhookEvent::VERIFICATION_FAILED,
57
+ PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED,
58
+ reconstituted_event_context,
45
59
  webhook_options
46
60
  )
47
61
  end
48
-
49
- webhook_service.trigger_webhooks(
50
- pact,
51
- verification,
52
- PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED,
53
- webhook_options
54
- )
55
62
  end
56
63
 
57
64
  private
@@ -68,6 +75,32 @@ module PactBroker
68
75
  previous_pact.nil? || new_pact.pact_version_sha != previous_pact.pact_version_sha
69
76
  end
70
77
 
78
+ def merge_consumer_version_selectors(consumer_version_number, selectors, event_context)
79
+ event_context.merge(
80
+ consumer_version_number: consumer_version_number,
81
+ consumer_version_tags: selectors.collect{ | selector | selector[:tag] }.compact.uniq
82
+ )
83
+ end
84
+
85
+ # Now that we de-duplicate the pact contents when verifying though the 'pacts for verification' API,
86
+ # we no longer get a webhook triggered for the verification results publication of each indiviual
87
+ # consumer version tag, meaning that only the most recent commit will get the updated verification status.
88
+ # To fix this, each URL of the pacts returned by the 'pacts for verification' API now contains the
89
+ # relevant selectors in the metadata, so that when the verification results are published,
90
+ # we can parse that metadata, and trigger one webhook for each consumer version like we used to.
91
+ # Actually, we used to trigger one webhook per tag, but given that the most likely use of the
92
+ # verification published webhook is for reporting git statuses,
93
+ # it makes more sense to trigger per consumer version number (ie. commit).
94
+ def expand_events(event_context)
95
+ triggers = if event_context[:consumer_version_selectors].is_a?(Array)
96
+ event_context[:consumer_version_selectors]
97
+ .group_by{ | selector | selector[:consumer_version_number] }
98
+ .collect { | consumer_version_number, selectors | merge_consumer_version_selectors(consumer_version_number, selectors, event_context.without(:consumer_version_selectors)) }
99
+ else
100
+ [event_context]
101
+ end
102
+ end
103
+
71
104
  def print_debug_messages(changed_pacts)
72
105
  if changed_pacts.any?
73
106
  messages = changed_pacts.collect do |tag, previous_pact|
@@ -1,6 +1,7 @@
1
1
  require 'sequel'
2
2
  require 'pact_broker/repositories/helpers'
3
3
  require 'pact_broker/webhooks/execution'
4
+ require 'pact_broker/hash_refinements'
4
5
 
5
6
  # Represents the relationship between a webhook and the event and object
6
7
  # that caused it to be triggered. eg a pact publication
@@ -8,6 +9,7 @@ require 'pact_broker/webhooks/execution'
8
9
  module PactBroker
9
10
  module Webhooks
10
11
  class TriggeredWebhook < Sequel::Model(:triggered_webhooks)
12
+ using PactBroker::HashRefinements
11
13
  plugin :timestamps, update_on_create: true
12
14
  plugin :serialization, :json, :event_context
13
15
 
@@ -60,7 +62,7 @@ module PactBroker
60
62
  # getting a random 'no method to_domain for null' error
61
63
  # not sure on which object, so splitting this out into two lines
62
64
  pact = pact_publication.to_domain
63
- webhook.to_domain.execute(pact, verification, options)
65
+ webhook.to_domain.execute(pact, verification, event_context.symbolize_keys, options)
64
66
  end
65
67
 
66
68
  def consumer_name
@@ -1,43 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $LOAD_PATH << "#{Dir.pwd}/lib"
4
-
5
3
  begin
6
4
 
5
+ $LOAD_PATH << "#{Dir.pwd}/lib"
7
6
  require 'pact_broker/test/http_test_data_builder'
8
7
  base_url = ENV['PACT_BROKER_BASE_URL'] || 'http://localhost:9292'
9
8
 
10
- td = PactBroker::Test::HttpTestDataBuilder.new(base_url, { })
11
- td.delete_integration(consumer: "MyConsumer", provider: "MyProvider")
12
- .can_i_deploy(pacticipant: "MyProvider", version: "1", to: "prod")
13
- .can_i_deploy(pacticipant: "MyConsumer", version: "1", to: "prod")
14
- .publish_pact(consumer: "MyConsumer", consumer_version: "1", provider: "MyProvider", content_id: "111", tag: "feature/a")
15
- .can_i_deploy(pacticipant: "MyProvider", version: "1", to: "prod")
9
+ td = PactBroker::Test::HttpTestDataBuilder.new(base_url)
10
+ td.delete_integration(consumer: "Foo", provider: "Bar")
11
+ .delete_integration(consumer: "foo-consumer", provider: "bar-provider")
12
+ .create_pacticipant("foo-consumer")
13
+ .create_pacticipant("foo-provider")
14
+ .create_global_webhook_for_verification_published(uuid: "ba8feb17-558a-4b3f-a078-f52c6fafd014", url: "http://webhook-server:9393")
15
+ .publish_pact(consumer: "foo-consumer", consumer_version: "1", provider: "bar-provider", content_id: "111", tag: "main")
16
+ .publish_pact(consumer: "foo-consumer", consumer_version: "2", provider: "bar-provider", content_id: "111", tag: ["feat/x", "feat/y"])
17
+ .sleep(10)
16
18
  .get_pacts_for_verification(
17
- enable_pending: true,
18
19
  provider_version_tag: "main",
19
- include_wip_pacts_since: "2020-01-01",
20
- consumer_version_selectors: [{ tag: "main", latest: true }])
20
+ consumer_version_selectors: [{ tag: "main", latest: true }, { tag: "feat/x", latest: true }, { tag: "feat/y", latest: true }])
21
21
  .verify_pact(
22
22
  index: 0,
23
23
  provider_version_tag: "main",
24
24
  provider_version: "1",
25
- success: false
25
+ success: true
26
26
  )
27
- .get_pacts_for_verification(
28
- enable_pending: true,
29
- provider_version_tag: "main",
30
- include_wip_pacts_since: "2020-01-01",
31
- consumer_version_selectors: [{ tag: "main", latest: true }])
32
- .can_i_deploy(pacticipant: "MyProvider", version: "1", to: "prod")
33
- .can_i_deploy(pacticipant: "MyConsumer", version: "1", to: "prod")
34
- .deploy_to_prod(pacticipant: "MyProvider", version: "1")
35
- .can_i_deploy(pacticipant: "MyConsumer", version: "1", to: "prod")
36
- .deploy_to_prod(pacticipant: "MyConsumer", version: "1")
27
+
37
28
 
38
29
  rescue StandardError => e
39
30
  puts "#{e.class} #{e.message}"
40
31
  puts e.backtrace
41
32
  exit 1
42
33
  end
43
-
@@ -6,7 +6,8 @@ begin
6
6
  base_url = ENV['PACT_BROKER_BASE_URL'] || 'http://localhost:9292'
7
7
 
8
8
  td = PactBroker::Test::HttpTestDataBuilder.new(base_url)
9
- td.delete_integration(consumer: "foo-consumer", provider: "bar-provider")
9
+ td.delete_integration(consumer: "Foo", provider: "Bar")
10
+ .delete_integration(consumer: "foo-consumer", provider: "bar-provider")
10
11
  .publish_pact(consumer: "foo-consumer", consumer_version: "1", provider: "bar-provider", content_id: "111", tag: "main")
11
12
  .get_pacts_for_verification(
12
13
  enable_pending: true,
@@ -19,7 +19,7 @@ output=$(curl -v https://api.github.com/repos/${repository_slug}/dispatches \
19
19
  -H "Authorization: Bearer $GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES" \
20
20
  -d "{\"event_type\": \"release-triggered\", \"client_payload\": {\"increment\": ${increment}}}" 2>&1)
21
21
 
22
- if ! echo "${output}" | grep "HTTP\/1.1 204" > /dev/null; then
22
+ if ! echo "${output}" | grep "HTTP\/.* 204" > /dev/null; then
23
23
  echo "$output" | sed "s/${GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES}/********/g"
24
24
  echo "Failed to trigger release"
25
25
  exit 1
@@ -1,10 +1,10 @@
1
1
  require 'rack/utils'
2
+ STDOUT.sync = true
3
+ puts "Starting webhook server"
2
4
 
3
- count = 0
4
5
  run -> (env) {
5
- count += 1
6
- status = (count % 3 == 0) ? 200 : 500
7
- puts Rack::Utils.parse_nested_query(env['QUERY_STRING'])
6
+ status = 200
7
+ puts Rack::Utils.parse_nested_query(env['QUERY_STRING']) if env['QUERY_STRING'] && env['QUERY_STRING'] != ''
8
8
  puts env['rack.input'].read
9
- [status, {}, ["Hello. This might be an error.\n"]]
9
+ [status, {"Content-Type" => "text/plain"}, ["Webhook response.\n"]]
10
10
  }
@@ -81,16 +81,12 @@ module PactBroker
81
81
  expect(subject.headers['Location']).to eq("http://example.org/pacts/provider/Provider/consumer/Consumer/pact-version/1234/verification-results/2")
82
82
  end
83
83
 
84
- it "merges the upstream verification metdata into the webhook context" do
85
- expect(webhook_execution_configuration).to receive(:with_webhook_context).with(parsed_metadata)
86
- subject
87
- end
88
-
89
84
  it "stores the verification in the database" do
90
85
  expect(PactBroker::Verifications::Service).to receive(:create).with(
91
86
  next_verification_number,
92
87
  hash_including('some' => 'params', 'wip' => false),
93
88
  pact,
89
+ parsed_metadata,
94
90
  {
95
91
  webhook_execution_configuration: webhook_execution_configuration,
96
92
  database_connector: database_connector
@@ -117,6 +113,7 @@ module PactBroker
117
113
  anything,
118
114
  hash_including('wip' => true),
119
115
  anything,
116
+ anything,
120
117
  anything
121
118
  )
122
119
  subject
@@ -30,7 +30,8 @@ module PactBroker
30
30
  let(:pact) { instance_double("PactBroker::Domain::Pact") }
31
31
  let(:consumer_name) { "foo" }
32
32
  let(:provider_name) { "bar" }
33
- let(:webhook_execution_configuration) { instance_double(PactBroker::Webhooks::ExecutionConfiguration) }
33
+ let(:webhook_execution_configuration) { instance_double(PactBroker::Webhooks::ExecutionConfiguration, webhook_context: event_context) }
34
+ let(:event_context) { { some: "data" } }
34
35
 
35
36
  before do
36
37
  allow(PactBroker::Webhooks::Service).to receive(:test_execution).and_return(execution_result)
@@ -39,7 +40,7 @@ module PactBroker
39
40
  end
40
41
 
41
42
  it "executes the webhook" do
42
- expect(PactBroker::Webhooks::Service).to receive(:test_execution).with(webhook, webhook_execution_configuration)
43
+ expect(PactBroker::Webhooks::Service).to receive(:test_execution).with(webhook, event_context, webhook_execution_configuration)
43
44
  subject
44
45
  end
45
46
 
@@ -12,9 +12,9 @@ module PactBroker
12
12
  let(:webhook_template_parameters_hash) { { 'foo' => 'bar' } }
13
13
  let(:http_request) { double('http request') }
14
14
  let(:http_response) { double('http response') }
15
- let(:webhook_context) { { some: 'things' } }
15
+ let(:event_context) { { some: 'things' } }
16
16
  let(:logging_options) { { other: 'options' } }
17
- let(:options) { { webhook_context: webhook_context, logging_options: logging_options } }
17
+ let(:options) { { logging_options: logging_options } }
18
18
  let(:pact) { double('pact') }
19
19
  let(:verification) { double('verification') }
20
20
  let(:logger) { double('logger').as_null_object }
@@ -61,11 +61,11 @@ module PactBroker
61
61
 
62
62
  let(:webhook_request_logger) { instance_double(PactBroker::Webhooks::WebhookRequestLogger, log: "logs") }
63
63
 
64
- let(:execute) { subject.execute pact, verification, options }
64
+ let(:execute) { subject.execute(pact, verification, event_context, options) }
65
65
 
66
66
  it "creates the template parameters" do
67
67
  expect(PactBroker::Webhooks::PactAndVerificationParameters).to receive(:new).with(
68
- pact, verification, webhook_context
68
+ pact, verification, event_context
69
69
  )
70
70
  execute
71
71
  end
@@ -81,7 +81,7 @@ module PactBroker
81
81
  end
82
82
 
83
83
  it "generates the execution logs" do
84
- expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, http_response, nil, webhook_context)
84
+ expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, http_response, nil, event_context)
85
85
  execute
86
86
  end
87
87
 
@@ -106,7 +106,7 @@ module PactBroker
106
106
  end
107
107
 
108
108
  it "generates the execution logs" do
109
- expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, nil, instance_of(error_class), webhook_context)
109
+ expect(webhook_request_logger).to receive(:log).with(uuid, webhook_request, nil, instance_of(error_class), event_context)
110
110
  execute
111
111
  end
112
112
 
@@ -33,7 +33,7 @@ module PactBroker
33
33
  let(:provider) { double('provider', id: 2) }
34
34
  let(:version) { double('version', id: 3, pacticipant_id: 1) }
35
35
  let(:existing_pact) { nil }
36
- let(:new_pact) { double('new_pact', consumer_version_tag_names: %[dev], json_content: json_content) }
36
+ let(:new_pact) { double('new_pact', consumer_version_tag_names: %w[dev], json_content: json_content) }
37
37
  let(:json_content) { { the: "contract" }.to_json }
38
38
  let(:json_content_with_ids) { { the: "contract with ids" }.to_json }
39
39
  let(:previous_pacts) { [] }
@@ -49,7 +49,7 @@ module PactBroker
49
49
  let(:content_with_interaction_ids) { double('content_with_interaction_ids', to_json: json_content_with_ids) }
50
50
  let(:webhook_options) { { webhook_execution_configuration: webhook_execution_configuration } }
51
51
  let(:webhook_execution_configuration) { instance_double(PactBroker::Webhooks::ExecutionConfiguration) }
52
-
52
+ let(:expected_event_context) { { consumer_version_tags: ["dev"] } }
53
53
 
54
54
  before do
55
55
  allow(Content).to receive(:from_json).and_return(content)
@@ -73,12 +73,12 @@ module PactBroker
73
73
  end
74
74
 
75
75
  it "sets the consumer version tags" do
76
- expect(webhook_execution_configuration).to receive(:with_webhook_context).with(consumer_version_tags: %[dev]).and_return(webhook_execution_configuration)
76
+ expect(webhook_execution_configuration).to receive(:with_webhook_context).with(consumer_version_tags: %w[dev]).and_return(webhook_execution_configuration)
77
77
  subject
78
78
  end
79
79
 
80
80
  it "triggers webhooks" do
81
- expect(webhook_trigger_service).to receive(:trigger_webhooks_for_new_pact).with(new_pact, webhook_options)
81
+ expect(webhook_trigger_service).to receive(:trigger_webhooks_for_new_pact).with(new_pact, expected_event_context, webhook_options)
82
82
  subject
83
83
  end
84
84
  end
@@ -92,6 +92,8 @@ module PactBroker
92
92
  )
93
93
  end
94
94
 
95
+ let(:expected_event_context) { { consumer_version_tags: ["dev"] } }
96
+
95
97
  it "creates the sha before adding the interaction ids" do
96
98
  expect(PactBroker::Pacts::GenerateSha).to receive(:call).ordered
97
99
  expect(content).to receive(:with_ids).ordered
@@ -104,7 +106,7 @@ module PactBroker
104
106
  end
105
107
 
106
108
  it "triggers webhooks" do
107
- expect(webhook_trigger_service).to receive(:trigger_webhooks_for_updated_pact).with(existing_pact, new_pact, webhook_options)
109
+ expect(webhook_trigger_service).to receive(:trigger_webhooks_for_updated_pact).with(existing_pact, new_pact, expected_event_context, webhook_options)
108
110
  subject
109
111
  end
110
112
  end
@@ -22,6 +22,8 @@ module PactBroker
22
22
  end
23
23
 
24
24
  let(:options) { { webhook_execution_configuration: webhook_execution_configuration } }
25
+ let(:event_context) { { some: "data" } }
26
+ let(:expected_event_context) { { some: "data", provider_version_tags: ["dev"] } }
25
27
  let(:webhook_execution_configuration) { instance_double(PactBroker::Webhooks::ExecutionConfiguration) }
26
28
  let(:params) { { 'success' => true, 'providerApplicationVersion' => '4.5.6', 'wip' => true, 'testResults' => { 'some' => 'results' }} }
27
29
  let(:pact) do
@@ -30,7 +32,7 @@ module PactBroker
30
32
  .create_provider_version_tag('dev')
31
33
  .and_return(:pact)
32
34
  end
33
- let(:create_verification) { subject.create 3, params, pact, options }
35
+ let(:create_verification) { subject.create 3, params, pact, event_context, options }
34
36
 
35
37
  it "logs the creation" do
36
38
  expect(logger).to receive(:info).with(/.*verification.*3/, payload: {"providerApplicationVersion"=>"4.5.6", "success"=>true, "wip"=>true})
@@ -67,6 +69,7 @@ module PactBroker
67
69
  expect(PactBroker::Webhooks::TriggerService).to have_received(:trigger_webhooks_for_verification_results_publication).with(
68
70
  pact,
69
71
  verification,
72
+ expected_event_context,
70
73
  options
71
74
  )
72
75
  end
@@ -94,7 +94,7 @@ module PactBroker
94
94
  [ double("label", name: "foo"), double("label", name: "bar") ]
95
95
  end
96
96
 
97
- let(:webhook_context) { { base_url: base_url } }
97
+ let(:webhook_context) { { base_url: base_url, event_name: "something" } }
98
98
 
99
99
  let(:nil_pact) { nil }
100
100
  let(:nil_verification) { nil }
@@ -158,7 +158,8 @@ module PactBroker
158
158
  {
159
159
  consumer_version_number: "webhook-version-number",
160
160
  consumer_version_tags: %w[webhook tags],
161
- base_url: base_url
161
+ base_url: base_url,
162
+ event_name: "something"
162
163
 
163
164
  }
164
165
  end
@@ -186,16 +187,16 @@ module PactBroker
186
187
  let(:base_url) { "http://broker" }
187
188
 
188
189
  let(:template_parameters) do
189
- PactAndVerificationParameters.new(placeholder_pact, nil, { base_url: base_url }).to_hash
190
+ PactAndVerificationParameters.new(placeholder_pact, nil, { base_url: base_url, event_name: "something" }).to_hash
190
191
  end
191
192
 
192
193
  it "does not blow up with a placeholder pact" do
193
- template_parameters = PactAndVerificationParameters.new(placeholder_pact, nil, { base_url: base_url }).to_hash
194
+ template_parameters = PactAndVerificationParameters.new(placeholder_pact, nil, { base_url: base_url, event_name: "something" }).to_hash
194
195
  Render.call("", template_parameters)
195
196
  end
196
197
 
197
198
  it "does not blow up with a placeholder verification" do
198
- template_parameters = PactAndVerificationParameters.new(placeholder_pact, placeholder_verification, { base_url: base_url }).to_hash
199
+ template_parameters = PactAndVerificationParameters.new(placeholder_pact, placeholder_verification, { base_url: base_url, event_name: "something" }).to_hash
199
200
  Render.call("", template_parameters)
200
201
  end
201
202
  end
@@ -181,7 +181,9 @@ module PactBroker
181
181
  let(:webhooks) { [instance_double(PactBroker::Domain::Webhook, description: 'description', uuid: '1244')]}
182
182
  let(:triggered_webhook) { instance_double(PactBroker::Webhooks::TriggeredWebhook) }
183
183
  let(:webhook_execution_configuration) { double('webhook_execution_configuration', webhook_context: webhook_context) }
184
- let(:webhook_context) { double('webhook_context') }
184
+ let(:webhook_context) { { base_url: "http://example.org" } }
185
+ let(:event_context) { { some: "data" } }
186
+ let(:expected_event_context) { { some: "data", event_name: PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, base_url: "http://example.org" } }
185
187
  let(:options) do
186
188
  { database_connector: double('database_connector'),
187
189
  webhook_execution_configuration: webhook_execution_configuration,
@@ -196,7 +198,7 @@ module PactBroker
196
198
  allow(Job).to receive(:perform_in)
197
199
  end
198
200
 
199
- subject { Service.trigger_webhooks pact, verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, options }
201
+ subject { Service.trigger_webhooks(pact, verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, event_context, options) }
200
202
 
201
203
  it "finds the webhooks" do
202
204
  expect_any_instance_of(PactBroker::Webhooks::Repository).to receive(:find_by_consumer_and_or_provider_and_event_name).with(consumer, provider, PactBroker::Webhooks::WebhookEvent::DEFAULT_EVENT_NAME)
@@ -205,7 +207,7 @@ module PactBroker
205
207
 
206
208
  context "when webhooks are found" do
207
209
  it "executes the webhook" do
208
- expect(Service).to receive(:run_later).with(webhooks, pact, verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, options)
210
+ expect(Service).to receive(:run_later).with(webhooks, pact, verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, expected_event_context, options)
209
211
  subject
210
212
  end
211
213
 
@@ -258,6 +260,7 @@ module PactBroker
258
260
  instance_double(PactBroker::Webhooks::ExecutionConfiguration, to_hash: execution_configuration_hash)
259
261
  end
260
262
  let(:execution_configuration_hash) { { the: 'options' } }
263
+ let(:event_context) { { some: "data" } }
261
264
 
262
265
  before do
263
266
  allow(PactBroker::Pacts::Service).to receive(:search_for_latest_pact).and_return(pact)
@@ -266,7 +269,7 @@ module PactBroker
266
269
  allow(execution_configuration).to receive(:with_failure_log_message).and_return(execution_configuration)
267
270
  end
268
271
 
269
- subject { Service.test_execution(webhook, execution_configuration) }
272
+ subject { Service.test_execution(webhook, event_context, execution_configuration) }
270
273
 
271
274
  it "searches for the latest matching pact" do
272
275
  expect(PactBroker::Pacts::Service).to receive(:search_for_latest_pact).with(consumer_name: 'consumer', provider_name: 'provider')
@@ -279,7 +282,7 @@ module PactBroker
279
282
 
280
283
  context "when the trigger is not for a verification" do
281
284
  it "executes the webhook with the pact" do
282
- expect(webhook).to receive(:execute).with(pact, nil, execution_configuration_hash)
285
+ expect(webhook).to receive(:execute).with(pact, nil, event_context.merge(event_name: "test"), execution_configuration_hash)
283
286
  subject
284
287
  end
285
288
  end
@@ -288,7 +291,7 @@ module PactBroker
288
291
  let(:pact) { nil }
289
292
 
290
293
  it "executes the webhook with a placeholder pact" do
291
- expect(webhook).to receive(:execute).with(an_instance_of(PactBroker::Pacts::PlaceholderPact), anything, anything)
294
+ expect(webhook).to receive(:execute).with(an_instance_of(PactBroker::Pacts::PlaceholderPact), anything, anything, anything)
292
295
  subject
293
296
  end
294
297
  end
@@ -302,7 +305,7 @@ module PactBroker
302
305
  end
303
306
 
304
307
  it "executes the webhook with the pact and the verification" do
305
- expect(webhook).to receive(:execute).with(pact, verification, execution_configuration_hash)
308
+ expect(webhook).to receive(:execute).with(pact, verification, event_context.merge(event_name: "test"), execution_configuration_hash)
306
309
  subject
307
310
  end
308
311
 
@@ -310,7 +313,7 @@ module PactBroker
310
313
  let(:verification) { nil }
311
314
 
312
315
  it "executes the webhook with a placeholder verification" do
313
- expect(webhook).to receive(:execute).with(anything, an_instance_of(PactBroker::Verifications::PlaceholderVerification), anything)
316
+ expect(webhook).to receive(:execute).with(anything, an_instance_of(PactBroker::Verifications::PlaceholderVerification), anything, anything)
314
317
  subject
315
318
  end
316
319
  end
@@ -329,6 +332,7 @@ module PactBroker
329
332
  .with_webhook_context(base_url: 'http://example.org')
330
333
  .with_show_response(true)
331
334
  end
335
+ let(:event_context) { { some: "data", base_url: "http://example.org" }}
332
336
  let(:options) do
333
337
  {
334
338
  database_connector: database_connector,
@@ -347,7 +351,7 @@ module PactBroker
347
351
  .and_return(:pact)
348
352
  end
349
353
 
350
- subject { PactBroker::Webhooks::Service.trigger_webhooks pact, td.verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, options }
354
+ subject { PactBroker::Webhooks::Service.trigger_webhooks(pact, td.verification, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, event_context, options) }
351
355
 
352
356
  it "executes the HTTP request of the webhook" do
353
357
  subject
@@ -11,6 +11,7 @@ module PactBroker
11
11
  let(:previous_pact_version_sha) { "111" }
12
12
  let(:previous_pacts) { { untagged: previous_pact } }
13
13
  let(:logger) { double('logger').as_null_object }
14
+ let(:event_context) { { some: "data" } }
14
15
  let(:webhook_options) { { the: 'options'} }
15
16
 
16
17
  before do
@@ -21,27 +22,27 @@ module PactBroker
21
22
 
22
23
  shared_examples_for "triggering a contract_published event" do
23
24
  it "triggers a contract_published webhook" do
24
- expect(webhook_service).to receive(:trigger_webhooks).with(pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, webhook_options)
25
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_PUBLISHED, event_context, webhook_options)
25
26
  subject
26
27
  end
27
28
  end
28
29
 
29
30
  shared_examples_for "triggering a contract_content_changed event" do
30
31
  it "triggers a contract_content_changed webhook" do
31
- expect(webhook_service).to receive(:trigger_webhooks).with(pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, webhook_options)
32
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, nil, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, event_context, webhook_options)
32
33
  subject
33
34
  end
34
35
  end
35
36
 
36
37
  shared_examples_for "not triggering a contract_content_changed event" do
37
38
  it "does not trigger a contract_content_changed webhook" do
38
- expect(webhook_service).to_not receive(:trigger_webhooks).with(anything, anything, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, anything)
39
+ expect(webhook_service).to_not receive(:trigger_webhooks).with(anything, anything, PactBroker::Webhooks::WebhookEvent::CONTRACT_CONTENT_CHANGED, event_context, anything)
39
40
  subject
40
41
  end
41
42
  end
42
43
 
43
44
  describe "#trigger_webhooks_for_new_pact" do
44
- subject { TriggerService.trigger_webhooks_for_new_pact(pact, webhook_options) }
45
+ subject { TriggerService.trigger_webhooks_for_new_pact(pact, event_context, webhook_options) }
45
46
 
46
47
  context "when no previous untagged pact exists" do
47
48
  let(:previous_pact) { nil }
@@ -117,7 +118,7 @@ module PactBroker
117
118
  end
118
119
  let(:existing_pact_version_sha) { pact_version_sha }
119
120
 
120
- subject { TriggerService.trigger_webhooks_for_updated_pact(existing_pact, pact, webhook_options) }
121
+ subject { TriggerService.trigger_webhooks_for_updated_pact(existing_pact, pact, event_context, webhook_options) }
121
122
 
122
123
  context "when the pact version sha of the previous revision is different" do
123
124
  let(:existing_pact_version_sha) { "456" }
@@ -140,32 +141,73 @@ module PactBroker
140
141
  describe "#trigger_webhooks_for_verification_results_publication" do
141
142
  let(:verification) { double("verification", success: success) }
142
143
  let(:success) { true }
144
+ # See lib/pact_broker/pacts/metadata.rb build_metadata_for_pact_for_verification
145
+ let(:selector_1) { { latest: true, consumer_version_number: "1", tag: "prod" } }
146
+ let(:selector_2) { { latest: true, consumer_version_number: "1", tag: "main" } }
147
+ let(:selector_3) { { latest: true, consumer_version_number: "2", tag: "feat/2" } }
148
+ let(:event_context) do
149
+ {
150
+ consumer_version_selectors: [selector_1, selector_2, selector_3],
151
+ other: "foo"
152
+ }
153
+ end
154
+ let(:expected_event_context_1) { { consumer_version_number: "1", consumer_version_tags: ["prod", "main"], other: "foo" } }
155
+ let(:expected_event_context_2) { { consumer_version_number: "2", consumer_version_tags: ["feat/2"], other: "foo" } }
143
156
 
144
- subject { TriggerService.trigger_webhooks_for_verification_results_publication(pact, verification, webhook_options) }
157
+ subject { TriggerService.trigger_webhooks_for_verification_results_publication(pact, verification, event_context, webhook_options) }
145
158
 
146
159
  context "when the verification is successful" do
147
- it "triggers a provider_verification_succeeded webhook" do
148
- expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_SUCCEEDED, webhook_options)
149
- subject
160
+
161
+ context "when there are consumer_version_selectors in the event_context" do
162
+ it "triggers a provider_verification_succeeded webhook for each consumer version (ie. commit)" do
163
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_SUCCEEDED, expected_event_context_1, webhook_options)
164
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_SUCCEEDED, expected_event_context_2, webhook_options)
165
+ subject
166
+ end
167
+
168
+ it "triggers a provider_verification_published webhook for each consumer version (ie. commit)" do
169
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, expected_event_context_1, webhook_options)
170
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, expected_event_context_2, webhook_options)
171
+ subject
172
+ end
150
173
  end
151
174
 
152
- it "triggers a provider_verification_published webhook" do
153
- expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, webhook_options)
154
- subject
175
+ context "when there are no consumer_version_selectors" do
176
+ let(:event_context) { { some: "data" } }
177
+
178
+ it "passes through the event context" do
179
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_SUCCEEDED, event_context, webhook_options)
180
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, event_context, webhook_options)
181
+ subject
182
+ end
155
183
  end
156
184
  end
157
185
 
158
186
  context "when the verification is not successful" do
159
187
  let(:success) { false }
160
188
 
161
- it "triggers a provider_verification_failed webhook" do
162
- expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_FAILED, webhook_options)
163
- subject
189
+ context "when there are consumer_version_selectors in the event_context" do
190
+ it "triggers a provider_verification_failed webhook for each consumer version (ie. commit)" do
191
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_FAILED, expected_event_context_1, webhook_options)
192
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_FAILED, expected_event_context_2, webhook_options)
193
+ subject
194
+ end
195
+
196
+ it "triggeres a provider_verification_published webhook for each consumer version (ie. commit)" do
197
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, expected_event_context_1, webhook_options)
198
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, expected_event_context_2, webhook_options)
199
+ subject
200
+ end
164
201
  end
165
202
 
166
- it "triggeres a provider_verification_published webhook" do
167
- expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, webhook_options)
168
- subject
203
+ context "when there are no consumer_version_selectors" do
204
+ let(:event_context) { { some: "data" } }
205
+
206
+ it "passes through the event context" do
207
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_FAILED, event_context, webhook_options)
208
+ expect(webhook_service).to receive(:trigger_webhooks).with(pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED, event_context, webhook_options)
209
+ subject
210
+ end
169
211
  end
170
212
  end
171
213
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.76.1
4
+ version: 2.76.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-01-27 00:00:00.000000000 Z
13
+ date: 2021-01-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: httparty
@@ -566,7 +566,6 @@ files:
566
566
  - docker-compose-ci-mysql.yml
567
567
  - docker-compose-dev-postgres.yml
568
568
  - docker-compose-issue-repro-with-pact-broker-docker-image.yml
569
- - docker-compose-issue-repro.yml
570
569
  - docker-compose-test.yml
571
570
  - docs/images/Pactflow logo - black small.png
572
571
  - example/Gemfile
@@ -1,22 +0,0 @@
1
- version: "3"
2
-
3
- services:
4
- pact-broker:
5
- build: .
6
- ports:
7
- - "9292:9292"
8
- entrypoint: /usr/local/bin/start
9
- environment:
10
- - RACK_ENV=production
11
- volumes:
12
- - $PWD:/home
13
-
14
- repro-issue:
15
- build: .
16
- depends_on:
17
- - pact-broker
18
- command: dockerize -wait http://pact-broker:9292 -timeout 30s /home/script/reproduce-issue.rb
19
- environment:
20
- - PACT_BROKER_BASE_URL=http://pact-broker:9292
21
- volumes:
22
- - $PWD:/home