From 710293f5b2c1286fb2da65da158f461fee03495a Mon Sep 17 00:00:00 2001 From: Ivan Rabotyaga Date: Wed, 6 Oct 2021 13:00:13 +0300 Subject: [PATCH] feat: add pacticipant label options to webhook create/update commands (#96) --- README.md | 8 + .../Pact Broker Client - Pact Broker.md | 222 +++++++++++++++++ .../client/cli/webhook_commands.rb | 17 +- lib/pact_broker/client/webhooks/create.rb | 4 + .../cli/broker_run_webhook_commands_spec.rb | 55 ++++ .../pacts/pact_broker_client-pact_broker.json | 234 ++++++++++++++++++ .../service_providers/webhooks_create_spec.rb | 58 +++++ 7 files changed, 597 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 64415d31..ae0a18e0 100644 --- a/README.md +++ b/README.md @@ -607,8 +607,12 @@ Options: # Webhook basic auth username and password eg. username:password [--consumer=CONSUMER] # Consumer name + [--consumer-label=CONSUMER_LABEL] + # Consumer label [--provider=PROVIDER] # Provider name + [--provider-label=PROVIDER_LABEL] + # Provider label [--description=DESCRIPTION] # Webhook description [--contract-content-changed], [--no-contract-content-changed] @@ -663,8 +667,12 @@ Options: # Webhook basic auth username and password eg. username:password [--consumer=CONSUMER] # Consumer name + [--consumer-label=CONSUMER_LABEL] + # Consumer label [--provider=PROVIDER] # Provider name + [--provider-label=PROVIDER_LABEL] + # Provider label [--description=DESCRIPTION] # Webhook description [--contract-content-changed], [--no-contract-content-changed] diff --git a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md index e2e1ce9d..683c18a7 100644 --- a/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +++ b/doc/pacts/markdown/Pact Broker Client - Pact Broker.md @@ -64,10 +64,14 @@ * [A request to create a webhook with a JSON body for a consumer and provider](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker +* [A request to create a webhook with a JSON body for a consumer specified by a label](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_specified_by_a_label) + * [A request to create a webhook with a JSON body for a consumer that does not exist](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_consumer_that_does_not_exist) * [A request to create a webhook with a JSON body for a provider](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker +* [A request to create a webhook with a JSON body for a provider specified by a label](#a_request_to_create_a_webhook_with_a_JSON_body_for_a_provider_specified_by_a_label) + * [A request to create a webhook with a non-JSON body for a consumer and provider](#a_request_to_create_a_webhook_with_a_non-JSON_body_for_a_consumer_and_provider_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker * [A request to create a webhook with every possible event type](#a_request_to_create_a_webhook_with_every_possible_event_type_given_the_'Pricing_Service'_and_'Condor'_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker @@ -1089,6 +1093,16 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -1222,6 +1236,16 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -1276,6 +1300,16 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -1327,6 +1361,80 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + } +} +``` + +Upon receiving **a request to create a webhook with a JSON body for a consumer specified by a label** from Pact Broker Client, with +```json +{ + "method": "post", + "path": "/HAL-REL-PLACEHOLDER-PB-WEBHOOKS", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "description": "a webhook", + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + }, + "consumer": { + "label": "consumer_label" + } + } +} +``` +Pact Broker will respond with: +```json +{ + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -1433,6 +1541,80 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + } +} +``` + +Upon receiving **a request to create a webhook with a JSON body for a provider specified by a label** from Pact Broker Client, with +```json +{ + "method": "post", + "path": "/HAL-REL-PLACEHOLDER-PB-WEBHOOKS", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "description": "a webhook", + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + }, + "provider": { + "label": "provider_label" + } + } +} +``` +Pact Broker will respond with: +```json +{ + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -1482,6 +1664,14 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": "" + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -1545,6 +1735,28 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + }, + { + "name": "contract_published" + }, + { + "name": "provider_verification_published" + }, + { + "name": "provider_verification_succeeded" + }, + { + "name": "provider_verification_failed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2550,6 +2762,16 @@ Pact Broker will respond with: }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", diff --git a/lib/pact_broker/client/cli/webhook_commands.rb b/lib/pact_broker/client/cli/webhook_commands.rb index 86017cbd..5c940a44 100644 --- a/lib/pact_broker/client/cli/webhook_commands.rb +++ b/lib/pact_broker/client/cli/webhook_commands.rb @@ -15,7 +15,9 @@ def self.shared_options_for_webhook_commands method_option :data, aliases: "-d", desc: "Webhook payload (file or string)" method_option :user, aliases: "-u", desc: "Webhook basic auth username and password eg. username:password" method_option :consumer, desc: "Consumer name" + method_option :consumer_label, desc: "Consumer label, mutually exclusive with consumer name" method_option :provider, desc: "Provider name" + method_option :provider_label, desc: "Provider label, mutually exclusive with provider name" method_option :description, desc: "Webhook description" method_option :contract_content_changed, type: :boolean, desc: "Trigger this webhook when the pact content changes" method_option :contract_published, type: :boolean, desc: "Trigger this webhook when a pact is published" @@ -70,6 +72,7 @@ def parse_webhook_events end def parse_webhook_options(webhook_url) + validate_mutual_exclusiveness_of_participant_name_and_label_options events = parse_webhook_events # TODO update for contract_requiring_verification_published when released @@ -102,7 +105,9 @@ def parse_webhook_options(webhook_url) password: password, body: body, consumer: options.consumer, + consumer_label: options.consumer_label, provider: options.provider, + provider_label: options.provider_label, events: events, team_uuid: options.team_uuid } @@ -118,10 +123,20 @@ def run_webhook_commands webhook_url rescue PactBroker::Client::Error => e raise WebhookCreationError, "#{e.class} - #{e.message}" end + + def validate_mutual_exclusiveness_of_participant_name_and_label_options + if options.consumer && options.consumer_label + raise WebhookCreationError.new("Consumer name (--consumer) and label (--consumer_label) options are mutually exclusive") + end + + if options.provider && options.provider_label + raise WebhookCreationError.new("Provider name (--provider) and label (--provider_label) options are mutually exclusive") + end + end end end end end end end -end \ No newline at end of file +end diff --git a/lib/pact_broker/client/webhooks/create.rb b/lib/pact_broker/client/webhooks/create.rb index 5d97ebf4..f90381b2 100644 --- a/lib/pact_broker/client/webhooks/create.rb +++ b/lib/pact_broker/client/webhooks/create.rb @@ -81,10 +81,14 @@ def request_body_with_optional_consumer_and_provider if params.consumer body[:consumer] = { name: params.consumer } + elsif params.consumer_label + body[:consumer] = { label: params.consumer_label } end if params.provider body[:provider] = { name: params.provider } + elsif params.provider_label + body[:provider] = { label: params.provider_label } end if params.team_uuid diff --git a/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb b/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb index 22ac5442..7818becc 100644 --- a/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb +++ b/spec/lib/pact_broker/client/cli/broker_run_webhook_commands_spec.rb @@ -49,7 +49,9 @@ module CLI password: "password", body: "data", consumer: "consumer", + consumer_label: nil, provider: "provider", + provider_label: nil, events: ["contract_content_changed"], team_uuid: "1234" }.tap { |it| Pact::Fixture.add_fixture(:create_webhook_params, it) } @@ -223,6 +225,59 @@ module CLI expect { subject }.to raise_error(WebhookCreationError, /foo/) end end + + end + + context "when both consumer name and label options are specified" do + before do + options_hash[:consumer_label] = "consumer_label" + broker.options = OpenStruct.new(options_hash) + end + + it "raises a WebhookCreationError" do + expect { subject }.to raise_error( + WebhookCreationError, + "Consumer name (--consumer) and label (--consumer_label) options are mutually exclusive" + ) + end + end + + context "when both provider name and label options are specified" do + before do + options_hash[:provider_label] = "provider_label" + broker.options = OpenStruct.new(options_hash) + end + + it "raises a WebhookCreationError" do + expect { subject }.to raise_error( + WebhookCreationError, + "Provider name (--provider) and label (--provider_label) options are mutually exclusive" + ) + end + end + + context "when participant labels are specified" do + before do + options_hash.delete(:consumer) + options_hash.delete(:provider) + options_hash.merge!(consumer_label: 'consumer_label', provider_label: 'provider_label') + expected_params.merge!( + consumer: nil, + consumer_label: 'consumer_label', + provider: nil, + provider_label: 'provider_label' + ) + + broker.options = OpenStruct.new(options_hash) + end + + it "calls PactBroker::Client::Webhooks::Create with participant labels in params" do + expect(PactBroker::Client::Webhooks::Create).to receive(:call) do | params, _, _ | + expect(params).to eq expected_params + command_result + end + subject + end end end end diff --git a/spec/pacts/pact_broker_client-pact_broker.json b/spec/pacts/pact_broker_client-pact_broker.json index dfe19d95..fec09ef2 100644 --- a/spec/pacts/pact_broker_client-pact_broker.json +++ b/spec/pacts/pact_broker_client-pact_broker.json @@ -1995,6 +1995,16 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2067,6 +2077,28 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + }, + { + "name": "contract_published" + }, + { + "name": "provider_verification_published" + }, + { + "name": "provider_verification_succeeded" + }, + { + "name": "provider_verification_failed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2125,6 +2157,14 @@ }, "body": { "description": "a webhook", + "request": { + "body": "" + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2323,6 +2363,88 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + }, + "matchingRules": { + "$.body.description": { + "match": "type" + }, + "$.body._links.self.href": { + "match": "regex", + "regex": "http:\\/\\/.*" + }, + "$.body._links.self.title": { + "match": "type" + } + } + } + }, + { + "description": "a request to create a webhook with a JSON body for a consumer specified by a label", + "request": { + "method": "post", + "path": "/HAL-REL-PLACEHOLDER-PB-WEBHOOKS", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "description": "a webhook", + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + }, + "consumer": { + "label": "consumer_label" + } + } + }, + "response": { + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2442,6 +2564,88 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], + "_links": { + "self": { + "href": "http://localhost:1234/some-url", + "title": "A title" + } + } + }, + "matchingRules": { + "$.body.description": { + "match": "type" + }, + "$.body._links.self.href": { + "match": "regex", + "regex": "http:\\/\\/.*" + }, + "$.body._links.self.title": { + "match": "type" + } + } + } + }, + { + "description": "a request to create a webhook with a JSON body for a provider specified by a label", + "request": { + "method": "post", + "path": "/HAL-REL-PLACEHOLDER-PB-WEBHOOKS", + "headers": { + "Content-Type": "application/json", + "Accept": "application/hal+json" + }, + "body": { + "description": "a webhook", + "events": [ + { + "name": "contract_content_changed" + } + ], + "request": { + "url": "https://webhook", + "method": "POST", + "headers": { + "Foo": "bar", + "Bar": "foo" + }, + "body": { + "some": "body" + }, + "username": "username", + "password": "password" + }, + "provider": { + "label": "provider_label" + } + } + }, + "response": { + "status": 201, + "headers": { + "Content-Type": "application/hal+json;charset=utf-8" + }, + "body": { + "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2501,6 +2705,16 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2597,6 +2811,16 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", @@ -2663,6 +2887,16 @@ }, "body": { "description": "a webhook", + "request": { + "body": { + "some": "body" + } + }, + "events": [ + { + "name": "contract_content_changed" + } + ], "_links": { "self": { "href": "http://localhost:1234/some-url", diff --git a/spec/service_providers/webhooks_create_spec.rb b/spec/service_providers/webhooks_create_spec.rb index ad9119d8..3d5fe2ea 100644 --- a/spec/service_providers/webhooks_create_spec.rb +++ b/spec/service_providers/webhooks_create_spec.rb @@ -54,6 +54,14 @@ headers: pact_broker_response_headers, body: { description: Pact.like("a webhook"), + request: { + body: { + some: "body" + } + }, + events: [ + name: "contract_content_changed" + ], _links: { self: { href: Pact.term('http://localhost:1234/some-url', %r{http://.*}), @@ -92,6 +100,7 @@ before do params.merge!(events: event_names) request_body.merge!("events" => event_names.map{ |event_name| { "name" => event_name } }) + success_response[:body].merge!(events: event_names.map{ |event_name| { "name" => event_name } }) pact_broker .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker") @@ -112,6 +121,7 @@ context "when a valid webhook with an XML body is submitted" do before do request_body["request"]["body"] = body + success_response[:body][:request][:body] = body pact_broker .given("the 'Pricing Service' and 'Condor' already exist in the pact-broker") @@ -207,6 +217,30 @@ end end + context "when consumer is specified using a label" do + before do + params.delete(:consumer) + params.delete(:provider) + params.merge!(consumer_label: "consumer_label") + request_body["consumer"] = { "label" => "consumer_label" } + mock_pact_broker_index(self) + + pact_broker + .upon_receiving("a request to create a webhook with a JSON body for a consumer specified by a label") + .with( + method: :post, + path: placeholder_path('pb:webhooks'), + headers: post_request_headers, + body: request_body) + .will_respond_with(success_response) + end + + it "returns a CommandResult with success = true" do + expect(subject.success).to be true + expect(subject.message).to eq "Webhook \"a webhook\" created" + end + end + context "when only a consumer is specified and it does not exist" do before do params.delete(:provider) @@ -257,6 +291,30 @@ end end + context "when provider is specified using a label" do + before do + params.delete(:consumer) + params.delete(:provider) + params.merge!(provider_label: "provider_label") + request_body["provider"] = { "label" => "provider_label" } + mock_pact_broker_index(self) + + pact_broker + .upon_receiving("a request to create a webhook with a JSON body for a provider specified by a label") + .with( + method: :post, + path: placeholder_path('pb:webhooks'), + headers: post_request_headers, + body: request_body) + .will_respond_with(success_response) + end + + it "returns a CommandResult with success = true" do + expect(subject.success).to be true + expect(subject.message).to eq "Webhook \"a webhook\" created" + end + end + context "when neither consumer nor provider are specified" do before do params.delete(:consumer)