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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/ISSUES.md +10 -2
- data/docker-compose-issue-repro-with-pact-broker-docker-image.yml +16 -5
- data/lib/pact_broker/api/resources/verifications.rb +5 -2
- data/lib/pact_broker/api/resources/webhook_execution.rb +1 -1
- data/lib/pact_broker/domain/webhook.rb +8 -8
- data/lib/pact_broker/hash_refinements.rb +4 -0
- data/lib/pact_broker/pacts/service.rb +4 -2
- data/lib/pact_broker/test/http_test_data_builder.rb +63 -18
- data/lib/pact_broker/verifications/service.rb +2 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/webhooks/pact_and_verification_parameters.rb +10 -3
- data/lib/pact_broker/webhooks/service.rb +8 -7
- data/lib/pact_broker/webhooks/trigger_service.rb +56 -23
- data/lib/pact_broker/webhooks/triggered_webhook.rb +3 -1
- data/script/reproduce-issue-starting-up.rb +13 -23
- data/script/reproduce-issue.rb +2 -1
- data/script/trigger-release.sh +1 -1
- data/script/webhook-server.ru +5 -5
- data/spec/lib/pact_broker/api/resources/verifications_spec.rb +2 -5
- data/spec/lib/pact_broker/api/resources/webhook_execution_spec.rb +3 -2
- data/spec/lib/pact_broker/domain/webhook_spec.rb +6 -6
- data/spec/lib/pact_broker/pacts/service_spec.rb +7 -5
- data/spec/lib/pact_broker/verifications/service_spec.rb +4 -1
- data/spec/lib/pact_broker/webhooks/render_spec.rb +6 -5
- data/spec/lib/pact_broker/webhooks/service_spec.rb +13 -9
- data/spec/lib/pact_broker/webhooks/trigger_service_spec.rb +60 -18
- metadata +2 -3
- data/docker-compose-issue-repro.yml +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdc8ed42038e4b622005f53471a000d870efd99a6dbd6b773aa9e8a3f9a993cb
|
4
|
+
data.tar.gz: d2f42cd3e13007471cdd33fabbe515afa9c9ff4896566868accd9961f66f557f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a250f5f452356d3a9eb87659933cc47d0e947b7ce10a8c984d7cd296a28bc9be7dcfe82bd37fba29919f570a949b9b4a46b1622d6d242b92698268e54018aadf
|
7
|
+
data.tar.gz: c136cbe836ed813de2819480cf3347de86248f00258e0f8e89ec33375cf0c929186a65c51ef620995c11d2c596d496bec858c430894f80bacd6f647877f4af3e
|
data/CHANGELOG.md
CHANGED
@@ -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
|
-
|
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
|
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.
|
14
|
+
image: pactfoundation/pact-broker:2.76.0.0
|
15
15
|
ports:
|
16
16
|
- "9292:9292"
|
17
|
-
depends_on:
|
18
|
-
|
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:
|
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}
|
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,
|
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,
|
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,
|
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
|
-
|
120
|
+
event_context
|
121
121
|
)
|
122
122
|
end
|
123
123
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
data/lib/pact_broker/version.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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::
|
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: "
|
12
|
-
.
|
13
|
-
.
|
14
|
-
.
|
15
|
-
.
|
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
|
-
|
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:
|
25
|
+
success: true
|
26
26
|
)
|
27
|
-
|
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
|
-
|
data/script/reproduce-issue.rb
CHANGED
@@ -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: "
|
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,
|
data/script/trigger-release.sh
CHANGED
@@ -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
|
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
|
data/script/webhook-server.ru
CHANGED
@@ -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
|
-
|
6
|
-
|
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, {}, ["
|
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(:
|
15
|
+
let(:event_context) { { some: 'things' } }
|
16
16
|
let(:logging_options) { { other: 'options' } }
|
17
|
-
let(: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
|
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,
|
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,
|
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),
|
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) {
|
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
|
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
|
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
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
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.
|
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-
|
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
|