From 7f10e13f40ddd77c46eeaf804ca95c8e229754c8 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Thu, 9 Nov 2017 17:42:14 +1100 Subject: [PATCH] feat(can-i-deploy): allow pacticipant version to be checked against latest tagged versions of all the other pacticipants --- lib/pact_broker/client/can_i_deploy.rb | 11 +++--- lib/pact_broker/client/cli/broker.rb | 3 +- .../client/cli/can_i_deploy_long_desc.txt | 6 +++- lib/pact_broker/client/matrix.rb | 4 +++ .../pact_broker/client/can_i_deploy_spec.rb | 5 +-- .../client/cli/broker_can_i_deploy_spec.rb | 18 ++++++++-- .../pacts/pact_broker_client-pact_broker.json | 32 +++++++++++++++++ .../pact_broker_client_matrix_spec.rb | 36 +++++++++++++++++++ 8 files changed, 103 insertions(+), 12 deletions(-) diff --git a/lib/pact_broker/client/can_i_deploy.rb b/lib/pact_broker/client/can_i_deploy.rb index fb6c1332..4474119b 100644 --- a/lib/pact_broker/client/can_i_deploy.rb +++ b/lib/pact_broker/client/can_i_deploy.rb @@ -17,13 +17,14 @@ def initialize success, message = nil end end - def self.call(pact_broker_base_url, version_selectors, options, pact_broker_client_options={}) - new(pact_broker_base_url, version_selectors, options, pact_broker_client_options).call + def self.call(pact_broker_base_url, version_selectors, matrix_options, options, pact_broker_client_options={}) + new(pact_broker_base_url, version_selectors, matrix_options, options, pact_broker_client_options).call end - def initialize(pact_broker_base_url, version_selectors, options, pact_broker_client_options) + def initialize(pact_broker_base_url, version_selectors, matrix_options, options, pact_broker_client_options) @pact_broker_base_url = pact_broker_base_url @version_selectors = version_selectors + @matrix_options = matrix_options @options = options @pact_broker_client_options = pact_broker_client_options end @@ -42,7 +43,7 @@ def call private - attr_reader :pact_broker_base_url, :version_selectors, :options, :pact_broker_client_options + attr_reader :pact_broker_base_url, :version_selectors, :matrix_options, :options, :pact_broker_client_options def success_message(matrix) message = format_matrix(matrix) @@ -73,7 +74,7 @@ def reason(matrix) end def matrix - @matrix ||= Retry.until_true { pact_broker_client.matrix.get(version_selectors) } + @matrix ||= Retry.until_true { pact_broker_client.matrix.get(version_selectors, matrix_options) } end def pact_broker_client diff --git a/lib/pact_broker/client/cli/broker.rb b/lib/pact_broker/client/cli/broker.rb index 46e5d621..887fddbb 100644 --- a/lib/pact_broker/client/cli/broker.rb +++ b/lib/pact_broker/client/cli/broker.rb @@ -21,6 +21,7 @@ class Broker < CustomThor method_option :pacticipant, required: true, aliases: "-a", desc: "The pacticipant name. Use once for each pacticipant being checked." method_option :version, required: false, aliases: "-e", desc: "The pacticipant version. Must be entered after the --pacticipant that it relates to." method_option :latest, required: false, aliases: "-l", banner: '[TAG]', desc: "Use the latest pacticipant version. Optionally specify a TAG to use the latest version with the specified tag." + method_option :to, required: false, banner: 'TAG', desc: "This is too hard to explain in a short sentence. Look at the examples.", default: nil method_option :broker_base_url, required: true, aliases: "-b", desc: "The base URL of the Pact Broker" method_option :broker_username, aliases: "-u", desc: "Pact Broker basic auth username" method_option :broker_password, aliases: "-p", desc: "Pact Broker basic auth password" @@ -30,7 +31,7 @@ class Broker < CustomThor def can_i_deploy(*ignored_but_necessary) selectors = VersionSelectorOptionsParser.call(ARGV) validate_can_i_deploy_selectors(selectors) - result = CanIDeploy.call(options.broker_base_url, selectors, {output: options.output}, pact_broker_client_options) + result = CanIDeploy.call(options.broker_base_url, selectors, {to_tag: options.to}, {output: options.output}, pact_broker_client_options) $stdout.puts result.message exit(1) unless result.success end diff --git a/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt b/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt index 9b13eed1..f3f27148 100644 --- a/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt +++ b/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt @@ -6,10 +6,14 @@ The environment variables PACT_BROKER_BASE_URL_BASE_URL, PACT_BROKER_BASE_URL_US SCENARIOS -Check the status of the pacts for a pacticipant version (note that this only checks that each pact has been verified succesfully by *a* version of the provider. It doesn't provide any assurance that it has been verified by the *production* version of the provider): +Check the status of the pacts for a pacticipant version. Note that this only checks that the most recent verification for each pact is successful. It doesn't provide any assurance that the pact has been verified by the *production* version of the provider, however, it is sufficient if you are doing true continuous deployment. $ pact-broker can-i-deploy --pacticipant PACTICIPANT --version VERSION --broker-base-url BROKER_BASE_URL +If all applications within the pact network are not being deployed continuously (ie. if there is a gap between pact verification and actual deployment) then the following strategy is recommended. Each application version should be tagged in the broker with the name of the stage (eg. test, staging, production) as it is deployed (see the pact-broker create-version-tag CLI). This enables you to use the following very simple command to check if the application version you are about to deploy is compatible with every other application version already deployed in that environment. + + $ pact-broker can-i-deploy --pacticipant PACTICIPANT --version VERSION --to TAG --broker-base-url BROKER_BASE_URL + Check the status of the pacts for the latest pacticipant version: $ pact-broker can-i-deploy --pacticipant PACTICIPANT --latest --broker-base-url BROKER_BASE_URL diff --git a/lib/pact_broker/client/matrix.rb b/lib/pact_broker/client/matrix.rb index 8c11e53c..3277cb3a 100644 --- a/lib/pact_broker/client/matrix.rb +++ b/lib/pact_broker/client/matrix.rb @@ -47,6 +47,10 @@ def query_options(options) if options.key?(:success) opts[:success] = [*options[:success]] end + if options[:to_tag] + opts[:latest] = 'true' + opts[:tag] = options[:to_tag] + end opts end diff --git a/spec/lib/pact_broker/client/can_i_deploy_spec.rb b/spec/lib/pact_broker/client/can_i_deploy_spec.rb index 05eaa6f1..35257601 100644 --- a/spec/lib/pact_broker/client/can_i_deploy_spec.rb +++ b/spec/lib/pact_broker/client/can_i_deploy_spec.rb @@ -5,6 +5,7 @@ module Client describe CanIDeploy do let(:pact_broker_base_url) { 'http://example.org' } let(:version_selectors) { [{ pacticipant: "Foo", version: "1" }] } + let(:matrix_options) { {} } let(:pact_broker_client_options) { { foo: 'bar' } } let(:matrix_client) { instance_double('PactBroker::Client::Matrix') } let(:matrix) { { matrix: ['foo'], summary: { deployable: true, reason: 'some reason' } } } @@ -16,10 +17,10 @@ module Client allow(Matrix::Formatter).to receive(:call).and_return('text matrix') end - subject { CanIDeploy.call(pact_broker_base_url, version_selectors, options, pact_broker_client_options) } + subject { CanIDeploy.call(pact_broker_base_url, version_selectors, matrix_options, options, pact_broker_client_options) } it "retrieves the matrix from the pact broker" do - expect(matrix_client).to receive(:get).with(version_selectors) + expect(matrix_client).to receive(:get).with(version_selectors, matrix_options) subject end diff --git a/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb b/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb index 5a57b415..8689da64 100644 --- a/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +++ b/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb @@ -32,7 +32,7 @@ module CLI end it "invokes the CanIDeploy service" do - expect(CanIDeploy).to receive(:call).with('http://pact-broker', version_selectors, {output: 'table'}, {verbose: 'verbose'}) + expect(CanIDeploy).to receive(:call).with('http://pact-broker', version_selectors, {to_tag: nil}, {output: 'table'}, {verbose: 'verbose'}) invoke_can_i_deploy end @@ -44,13 +44,25 @@ module CLI end end + context "with --to" do + before do + subject.options.to = 'prod' + end + + it "passes the value as the matrix options" do + expect(CanIDeploy).to receive(:call).with(anything, anything, {to_tag: 'prod'}, anything, anything) + invoke_can_i_deploy + end + end + context "with basic auth" do before do - subject.options = OpenStruct.new(minimum_valid_options.merge(broker_username: 'foo', broker_password: 'bar')) + subject.options.broker_username = 'foo' + subject.options.broker_password = 'bar' end it "invokes the CanIDeploy service with the basic auth credentials" do - expect(CanIDeploy).to receive(:call).with(anything, anything, anything, {basic_auth: {username: "foo", password: "bar"}, verbose: 'verbose'}) + expect(CanIDeploy).to receive(:call).with(anything, anything, anything, anything, {basic_auth: {username: "foo", password: "bar"}, verbose: 'verbose'}) invoke_can_i_deploy end end diff --git a/spec/pacts/pact_broker_client-pact_broker.json b/spec/pacts/pact_broker_client-pact_broker.json index 51de0590..6aeb0b46 100644 --- a/spec/pacts/pact_broker_client-pact_broker.json +++ b/spec/pacts/pact_broker_client-pact_broker.json @@ -595,6 +595,38 @@ } } }, + { + "description": "a request for the compatibility matrix for Foo version 1.2.3 and the latest prod versions of all other pacticipants", + "providerState": "the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7", + "request": { + "method": "get", + "path": "/matrix", + "query": "q[][pacticipant]=Foo&q[][version]=1.2.3&latestby=cvp&latest=true&tag=prod" + }, + "response": { + "status": 200, + "headers": { + }, + "body": { + "matrix": [ + { + "consumer": { + "name": "Foo", + "version": { + "number": "1.2.3" + } + }, + "provider": { + "name": "Bar", + "version": { + "number": "4.5.6" + } + } + } + ] + } + } + }, { "description": "a request to publish a pact", "providerState": "the 'Pricing Service' already exists in the pact-broker", diff --git a/spec/service_providers/pact_broker_client_matrix_spec.rb b/spec/service_providers/pact_broker_client_matrix_spec.rb index 888da23f..b30e1f50 100644 --- a/spec/service_providers/pact_broker_client_matrix_spec.rb +++ b/spec/service_providers/pact_broker_client_matrix_spec.rb @@ -243,6 +243,42 @@ module PactBroker::Client expect(matrix[:matrix].size).to eq 1 end end + + context "when checking if we can deploy with the latest tagged versions of the other services" do + before do + pact_broker. + given("the pact for Foo version 1.2.3 has been successfully verified by Bar version 4.5.6 (tagged prod) and version 5.6.7"). + upon_receiving("a request for the compatibility matrix for Foo version 1.2.3 and the latest prod versions of all other pacticipants"). + with( + method: :get, + path: "/matrix", + query: "q[][pacticipant]=Foo&q[][version]=1.2.3&latestby=cvp&latest=true&tag=prod" + ). + will_respond_with( + status: 200, + headers: pact_broker_response_headers, + body: matrix_response_body + ) + end + + let(:selectors) { [{ pacticipant: "Foo", version: "1.2.3" }] } + + let(:matrix_response_body) { + { + matrix: [{ + consumer: { name: 'Foo', version: { number: '1.2.3' } }, + provider: { name: 'Bar', version: { number: '4.5.6'} }, + }] + } + } + + let(:options) { { to_tag: 'prod' } } + + it "returns the matrix with the latest prod version of Bar" do + matrix = pact_broker_client.matrix.get(selectors, options) + expect(matrix[:matrix].size).to eq 1 + end + end end end end