Skip to content

Commit 426b0b1

Browse files
authored
feat: add metadata to webhook and verification URLs to correctly track relevant versions and tags (pact-foundation#274)
* refactor: pass in database_connector from rack env instead of thread for verifications, and refactor webhook options * refactor: pass in database_connector from rack env instead of thread for pact publications, and refactor webhook options * refactor: pass in webhook show_response setting from resource via execution options * test: add code for manual webhook testing
1 parent 55d7f4a commit 426b0b1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+716
-269
lines changed

lib/pact_broker/api.rb

+2
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ module PactBroker
1717
# Pacts
1818
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number], Api::Resources::Pact, {resource_name: "pact_publication"}
1919
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha], Api::Resources::PactVersion, {resource_name: "pact_publication"}
20+
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha, 'metadata', :metadata], Api::Resources::PactVersion, {resource_name: "pact_publication"}
2021
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number, 'previous-distinct'], Api::Resources::PreviousDistinctPactVersion, {resource_name: "previous_distinct_pact_version"}
2122
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number, 'diff', 'previous-distinct'], Api::Resources::PactContentDiff, {resource_name: "previous_distinct_pact_version_diff"}
2223
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number, 'diff', 'version', :comparison_consumer_version], Api::Resources::PactContentDiff, {resource_name: "pact_version_diff_by_consumer_version"}
2324
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha, 'diff', 'pact-version', :comparison_pact_version_sha], Api::Resources::PactContentDiff, {resource_name: "pact_version_diff_by_pact_version_sha"}
2425

2526
# Verifications
2627
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha, 'verification-results'], Api::Resources::Verifications, {resource_name: "verification_results"}
28+
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha, 'metadata', :metadata, 'verification-results'], Api::Resources::Verifications, {resource_name: "verification_results"}
2729
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha, 'verification-results', :verification_number], Api::Resources::Verification, {resource_name: "verification_result"}
2830
add ['pacts', 'provider', :provider_name, 'consumer', :consumer_name, 'pact-version', :pact_version_sha, 'verification-results', :verification_number, 'triggered-webhooks'], Api::Resources::VerificationTriggeredWebhooks, {resource_name: "verification_result_triggered_webhooks"}
2931
add ['verification-results', 'consumer', :consumer_name, 'version', :consumer_version_number,'latest'], Api::Resources::LatestVerificationsForConsumerVersion, {resource_name: "verification_results_for_consumer_version"}

lib/pact_broker/api/decorators/pact_decorator.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def to_hash(options = {})
146146
link :'pb:publish-verification-results' do | options |
147147
{
148148
title: "Publish verification results",
149-
href: verification_publication_url(represented, options.fetch(:base_url))
149+
href: verification_publication_url(represented, options.fetch(:base_url), options[:metadata])
150150
}
151151
end
152152

lib/pact_broker/api/pact_broker_urls.rb

+24-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,27 @@ def pact_version_url pact, base_url = ''
5454
"#{pactigration_base_url(base_url, pact)}/pact-version/#{pact.pact_version_sha}"
5555
end
5656

57+
def pact_version_url_with_metadata pact, base_url = ''
58+
"#{pactigration_base_url(base_url, pact)}/pact-version/#{pact.pact_version_sha}/metadata/#{build_webhook_metadata(pact)}"
59+
end
60+
61+
def build_webhook_metadata(pact)
62+
Base64.strict_encode64(Rack::Utils.build_nested_query(
63+
consumer_version_number: pact.consumer_version_number,
64+
consumer_version_tags: pact.consumer_version_tag_names
65+
))
66+
end
67+
68+
def parse_webhook_metadata(metadata)
69+
if metadata
70+
Rack::Utils.parse_nested_query(Base64.strict_decode64(metadata)).each_with_object({}) do | (k, v), new_hash |
71+
new_hash[k.to_sym] = v
72+
end
73+
else
74+
{}
75+
end
76+
end
77+
5778
def pact_url_from_params base_url, params
5879
[ base_url, 'pacts',
5980
'provider', url_encode(params[:provider_name]),
@@ -136,8 +157,9 @@ def verification_triggered_webhooks_url verification, base_url = ''
136157
"#{verification_url(verification, base_url)}/triggered-webhooks"
137158
end
138159

139-
def verification_publication_url pact, base_url
140-
"#{pactigration_base_url(base_url, pact)}/pact-version/#{pact.pact_version_sha}/verification-results"
160+
def verification_publication_url pact, base_url, metadata = ""
161+
metadata_part = metadata ? "/metadata/#{metadata}" : ""
162+
"#{pactigration_base_url(base_url, pact)}/pact-version/#{pact.pact_version_sha}#{metadata_part}/verification-results"
141163
end
142164

143165
def tag_url base_url, tag

lib/pact_broker/api/resources/base_resource.rb

+4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ def provider
167167
def pact
168168
@pact ||= pact_service.find_pact(pact_params)
169169
end
170+
171+
def database_connector
172+
request.env["pactbroker.database_connector"]
173+
end
170174
end
171175
end
172176
end

lib/pact_broker/api/resources/pact.rb

+15-3
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,17 @@ def from_json
6565
response_code = pact ? 200 : 201
6666

6767
if request.patch? && resource_exists?
68-
@pact = pact_service.merge_pact(pact_params)
68+
@pact = pact_service.merge_pact(pact_params, webhook_options)
6969
else
70-
@pact = pact_service.create_or_update_pact(pact_params)
70+
@pact = pact_service.create_or_update_pact(pact_params, webhook_options)
7171
end
7272

7373
response.body = to_json
7474
response_code
7575
end
7676

7777
def to_json
78-
PactBroker::Api::Decorators::PactDecorator.new(pact).to_json(user_options: { base_url: base_url })
78+
PactBroker::Api::Decorators::PactDecorator.new(pact).to_json(user_options: decorator_context(metadata: identifier_from_path[:metadata]))
7979
end
8080

8181
def to_html
@@ -118,6 +118,18 @@ def set_post_deletion_response
118118
response.body = response_body.to_json
119119
response.headers["Content-Type" => "application/hal+json;charset=utf-8"]
120120
end
121+
122+
def webhook_options
123+
{
124+
database_connector: database_connector,
125+
execution_options: {
126+
show_response: PactBroker.configuration.show_webhook_response?
127+
},
128+
webhook_context: {
129+
base_url: base_url
130+
}
131+
}
132+
end
121133
end
122134
end
123135
end

lib/pact_broker/api/resources/verification.rb

-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
module PactBroker
88
module Api
99
module Resources
10-
1110
class Verification < BaseResource
12-
1311
def content_types_provided
1412
[["application/hal+json", :to_json], ["application/json", :to_json]]
1513
end

lib/pact_broker/api/resources/verifications.rb

+18-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def create_path
4747
end
4848

4949
def from_json
50-
verification = verification_service.create(next_verification_number, params_with_string_keys, pact)
50+
verification = verification_service.create(next_verification_number, params_with_string_keys, pact, webhook_options)
5151
response.body = decorator_for(verification).to_json(user_options: {base_url: base_url})
5252
true
5353
end
@@ -69,6 +69,23 @@ def decorator_for model
6969
def update_matrix_after_request?
7070
request.post?
7171
end
72+
73+
74+
def metadata
75+
PactBrokerUrls.parse_webhook_metadata(identifier_from_path[:metadata])
76+
end
77+
78+
def webhook_options
79+
{
80+
database_connector: database_connector,
81+
execution_options: {
82+
show_response: PactBroker.configuration.show_webhook_response?
83+
},
84+
webhook_context: metadata.merge(
85+
base_url: base_url
86+
)
87+
}
88+
end
7289
end
7390
end
7491
end

lib/pact_broker/api/resources/webhook_execution.rb

+17-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def allowed_methods
1414
end
1515

1616
def process_post
17-
webhook_execution_result = webhook_service.test_execution(webhook)
17+
webhook_execution_result = webhook_service.test_execution(webhook, webhook_options)
1818
response.headers['Content-Type'] = 'application/hal+json;charset=utf-8'
1919
response.body = post_response_body webhook_execution_result
2020
if webhook_execution_result.success?
@@ -44,7 +44,22 @@ def uuid
4444
end
4545

4646
def user_options
47-
{ base_url: base_url, webhook: webhook, show_response: PactBroker.configuration.show_webhook_response? }
47+
{
48+
base_url: base_url,
49+
webhook: webhook,
50+
show_response: PactBroker.configuration.show_webhook_response?
51+
}
52+
end
53+
54+
def webhook_options
55+
{
56+
execution_options: {
57+
show_response: PactBroker.configuration.show_webhook_response?
58+
},
59+
webhook_context: {
60+
base_url: base_url
61+
}
62+
}
4863
end
4964
end
5065
end

lib/pact_broker/domain/verification.rb

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ def provider_version_number
8080
provider_version.number
8181
end
8282

83+
def provider_version_tag_names
84+
provider_version.tags.collect(&:name)
85+
end
86+
8387
def latest_pact_publication
8488
pact_version.latest_pact_publication
8589
end

lib/pact_broker/domain/webhook.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def request_description
5252

5353
def execute pact, verification, options
5454
logger.info "Executing #{self}"
55-
request.build(pact: pact, verification: verification, base_url: options[:base_url]).execute(options)
55+
request.build(pact: pact, verification: verification, webhook_context: options.fetch(:webhook_context)).execute(options.fetch(:execution_options))
5656
end
5757

5858
def to_s

lib/pact_broker/domain/webhook_request.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def log_request
152152

153153
def log_response response
154154
log_response_to_application_logger(response)
155-
if options[:show_response]
155+
if options.fetch(:show_response)
156156
log_response_to_execution_logger(response)
157157
else
158158
execution_logger.info response_body_hidden_message

lib/pact_broker/pacts/service.rb

+16-9
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,28 @@ def delete params
4040
pact_repository.delete(params)
4141
end
4242

43-
def create_or_update_pact params
43+
def create_or_update_pact params, webhook_options
4444
provider = pacticipant_repository.find_by_name_or_create params[:provider_name]
4545
consumer = pacticipant_repository.find_by_name_or_create params[:consumer_name]
4646
consumer_version = version_repository.find_by_pacticipant_id_and_number_or_create consumer.id, params[:consumer_version_number]
4747
existing_pact = pact_repository.find_by_version_and_provider(consumer_version.id, provider.id)
4848

4949
if existing_pact
50-
update_pact params, existing_pact
50+
update_pact params, existing_pact, webhook_options
5151
else
52-
create_pact params, consumer_version, provider
52+
create_pact params, consumer_version, provider, webhook_options
5353
end
5454
end
5555

56-
def merge_pact params
56+
def merge_pact params, webhook_options
5757
provider = pacticipant_repository.find_by_name_or_create params[:provider_name]
5858
consumer = pacticipant_repository.find_by_name_or_create params[:consumer_name]
5959
consumer_version = version_repository.find_by_pacticipant_id_and_number_or_create consumer.id, params[:consumer_version_number]
6060
existing_pact = pact_repository.find_by_version_and_provider(consumer_version.id, provider.id)
6161

6262
params.merge!(json_content: Merger.merge_pacts(existing_pact.json_content, params[:json_content]))
6363

64-
update_pact params, existing_pact
64+
update_pact params, existing_pact, webhook_options
6565
end
6666

6767
def find_all_pact_versions_between consumer, options
@@ -113,21 +113,21 @@ def find_distinct_pacts_between consumer, options
113113
private
114114

115115
# Overwriting an existing pact with the same consumer/provider/consumer version number
116-
def update_pact params, existing_pact
116+
def update_pact params, existing_pact, webhook_options
117117
logger.info "Updating existing pact publication with params #{params.reject{ |k, v| k == :json_content}}"
118118
logger.debug "Content #{params[:json_content]}"
119119
pact_version_sha = generate_sha(params[:json_content])
120120
json_content = add_interaction_ids(params[:json_content])
121121
update_params = { pact_version_sha: pact_version_sha, json_content: json_content }
122122
updated_pact = pact_repository.update(existing_pact.id, update_params)
123123

124-
webhook_trigger_service.trigger_webhooks_for_updated_pact(existing_pact, updated_pact)
124+
webhook_trigger_service.trigger_webhooks_for_updated_pact(existing_pact, updated_pact, merge_consumer_version_info(webhook_options, updated_pact))
125125

126126
updated_pact
127127
end
128128

129129
# When no publication for the given consumer/provider/consumer version number exists
130-
def create_pact params, version, provider
130+
def create_pact params, version, provider, webhook_options
131131
logger.info "Creating new pact publication with params #{params.reject{ |k, v| k == :json_content}}"
132132
logger.debug "Content #{params[:json_content]}"
133133
pact_version_sha = generate_sha(params[:json_content])
@@ -139,7 +139,7 @@ def create_pact params, version, provider
139139
pact_version_sha: pact_version_sha,
140140
json_content: json_content
141141
)
142-
webhook_trigger_service.trigger_webhooks_for_new_pact pact
142+
webhook_trigger_service.trigger_webhooks_for_new_pact(pact, merge_consumer_version_info(webhook_options, pact))
143143
pact
144144
end
145145

@@ -150,6 +150,13 @@ def generate_sha(json_content)
150150
def add_interaction_ids(json_content)
151151
Content.from_json(json_content).with_ids.to_json
152152
end
153+
154+
def merge_consumer_version_info(webhook_options, pact)
155+
webhook_context = webhook_options.fetch(:webhook_context, {}).merge(
156+
consumer_version_tags: pact.consumer_version_tag_names
157+
)
158+
webhook_options.merge(webhook_context: webhook_context)
159+
end
153160
end
154161
end
155162
end

lib/pact_broker/test/test_data_builder.rb

+4
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ def create_global_webhook parameters = {}
242242
create_webhook(parameters.merge(consumer: nil, provider: nil))
243243
end
244244

245+
def create_global_verification_webhook parameters = {}
246+
create_webhook(parameters.merge(consumer: nil, provider: nil, event_names: [PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED]))
247+
end
248+
245249
def create_provider_webhook parameters = {}
246250
create_webhook(parameters.merge(consumer: nil))
247251
end

lib/pact_broker/verifications/service.rb

+10-2
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,22 @@ def next_number
1818
verification_repository.next_number
1919
end
2020

21-
def create next_verification_number, params, pact
21+
def create next_verification_number, params, pact, webhook_options
2222
logger.info "Creating verification #{next_verification_number} for pact_id=#{pact.id} from params #{params}"
2323
verification = PactBroker::Domain::Verification.new
2424
provider_version_number = params.fetch('providerApplicationVersion')
2525
PactBroker::Api::Decorators::VerificationDecorator.new(verification).from_hash(params)
2626
verification.number = next_verification_number
2727
verification = verification_repository.create(verification, provider_version_number, pact)
28-
webhook_service.trigger_webhooks pact, verification, PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED
28+
webhook_context = webhook_options[:webhook_context].merge(
29+
provider_version_tags: verification.provider_version_tag_names
30+
)
31+
32+
webhook_service.trigger_webhooks(pact,
33+
verification,
34+
PactBroker::Webhooks::WebhookEvent::VERIFICATION_PUBLISHED,
35+
webhook_options.merge(webhook_context: webhook_context)
36+
)
2937
verification
3038
end
3139

lib/pact_broker/webhooks/job.rb

+8-5
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def perform_with_connection(data)
3434
def perform_with_triggered_webhook
3535
@error_count = data[:error_count] || 0
3636
begin
37-
webhook_execution_result = PactBroker::Webhooks::Service.execute_triggered_webhook_now triggered_webhook, execution_options(data)
37+
webhook_execution_result = PactBroker::Webhooks::Service.execute_triggered_webhook_now(triggered_webhook, webhook_options(data))
3838
if webhook_execution_result.success?
3939
handle_success
4040
else
@@ -45,11 +45,14 @@ def perform_with_triggered_webhook
4545
end
4646
end
4747

48-
def execution_options(data)
49-
{
48+
def webhook_options(data)
49+
execution_options = data[:execution_options].merge(
5050
success_log_message: "Successfully executed webhook",
51-
failure_log_message: failure_log_message,
52-
base_url: data.fetch(:base_url)
51+
failure_log_message: failure_log_message
52+
)
53+
{
54+
execution_options: execution_options,
55+
webhook_context: data[:webhook_context]
5356
}
5457
end
5558

0 commit comments

Comments
 (0)