pact_broker 2.76.1 → 2.76.2

Sign up to get free protection for your applications and to get access to all the features.
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