Skip to content

Commit

Permalink
feat(can-i-deploy): allow pacticipant version to be checked against l…
Browse files Browse the repository at this point in the history
…atest tagged versions of all the other pacticipants
  • Loading branch information
bethesque committed Nov 9, 2017
1 parent 818bf2e commit 7f10e13
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 12 deletions.
11 changes: 6 additions & 5 deletions lib/pact_broker/client/can_i_deploy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion lib/pact_broker/client/cli/broker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down
6 changes: 5 additions & 1 deletion lib/pact_broker/client/cli/can_i_deploy_long_desc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/pact_broker/client/matrix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions spec/lib/pact_broker/client/can_i_deploy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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' } } }
Expand All @@ -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

Expand Down
18 changes: 15 additions & 3 deletions spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
32 changes: 32 additions & 0 deletions spec/pacts/pact_broker_client-pact_broker.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
36 changes: 36 additions & 0 deletions spec/service_providers/pact_broker_client_matrix_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 7f10e13

Please sign in to comment.