pact_broker-client 0.0.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +57 -32
- data/README.md +47 -0
- data/doc/markdown/Pact Broker Client - Pact Broker.md +582 -0
- data/doc/markdown/README.md +3 -0
- data/lib/pact_broker/client/base_client.rb +3 -1
- data/lib/pact_broker/client/pact_broker_client.rb +4 -3
- data/lib/pact_broker/client/pacticipants.rb +1 -1
- data/lib/pact_broker/client/pacts.rb +22 -6
- data/lib/pact_broker/client/publish_pacts.rb +16 -6
- data/lib/pact_broker/client/retry.rb +26 -0
- data/lib/pact_broker/client/tasks/publication_task.rb +3 -2
- data/lib/pact_broker/client/version.rb +1 -1
- data/lib/pact_broker/client/versions.rb +1 -1
- data/spec/lib/pact_broker/client/base_client_spec.rb +51 -0
- data/spec/lib/pact_broker/client/pact_broker_client_spec.rb +28 -1
- data/spec/lib/pact_broker/client/pacticipants_spec.rb +18 -0
- data/spec/lib/pact_broker/client/publish_pacts_spec.rb +67 -5
- data/spec/lib/pact_broker/client/tasks/publication_task_spec.rb +4 -2
- data/spec/lib/pact_broker/client/versions_spec.rb +18 -0
- data/spec/pacts/pact_broker_client-pact_broker.json +87 -91
- data/spec/service_providers/pact_broker_client_pacticipant_version_spec.rb +56 -0
- data/spec/service_providers/pact_broker_client_publish_spec.rb +34 -12
- data/spec/service_providers/pact_broker_client_register_repository_spec.rb +2 -2
- data/spec/service_providers/pact_broker_client_retrive_pact_spec.rb +4 -47
- data/spec/service_providers/pact_broker_client_tags_spec.rb +3 -3
- data/spec/support/pacticipant_get.json +3 -3
- data/spec/support/pacticipants_list.json +1 -1
- data/spec/support/pacts_latest_list.json +2 -2
- metadata +34 -45
@@ -26,11 +26,13 @@ module PactBroker
|
|
26
26
|
include HTTParty
|
27
27
|
include StringToSymbol
|
28
28
|
|
29
|
-
attr_reader :base_url
|
29
|
+
attr_reader :base_url, :client_options
|
30
30
|
|
31
31
|
def initialize options
|
32
32
|
@base_url = options[:base_url]
|
33
|
+
@client_options = options[:client_options] || {}
|
33
34
|
self.class.base_uri base_url
|
35
|
+
self.class.basic_auth(client_options[:basic_auth][:username], client_options[:basic_auth][:password]) if client_options[:basic_auth]
|
34
36
|
end
|
35
37
|
|
36
38
|
def default_request_headers
|
@@ -14,19 +14,20 @@ module PactBroker
|
|
14
14
|
|
15
15
|
DEFAULT_OPTIONS = {base_url: DEFAULT_PACT_BROKER_BASE_URL}
|
16
16
|
|
17
|
-
attr_reader :base_url
|
17
|
+
attr_reader :base_url, :client_options
|
18
18
|
|
19
19
|
def initialize options = {}
|
20
20
|
merged_options = DEFAULT_OPTIONS.merge(options)
|
21
21
|
@base_url = merged_options[:base_url]
|
22
|
+
@client_options = merged_options[:client_options] || {}
|
22
23
|
end
|
23
24
|
|
24
25
|
def pacticipants
|
25
|
-
PactBroker::Client::Pacticipants.new base_url: base_url
|
26
|
+
PactBroker::Client::Pacticipants.new base_url: base_url, client_options: client_options
|
26
27
|
end
|
27
28
|
|
28
29
|
def pacts
|
29
|
-
PactBroker::Client::Pacts.new base_url: base_url
|
30
|
+
PactBroker::Client::Pacts.new base_url: base_url, client_options: client_options
|
30
31
|
end
|
31
32
|
|
32
33
|
end
|
@@ -13,7 +13,11 @@ module PactBroker
|
|
13
13
|
url = save_consumer_contract_url consumer_contract, consumer_version
|
14
14
|
response = self.class.put(url, body: pact_string, headers: default_put_headers)
|
15
15
|
handle_response(response) do
|
16
|
-
|
16
|
+
latest_link = find_latest_link JSON.parse(response.body)
|
17
|
+
if latest_link.nil?
|
18
|
+
"Please upgrade to the latest version of the pact broker to see the URL of the latest pact!"
|
19
|
+
end
|
20
|
+
latest_link
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
@@ -28,7 +32,7 @@ module PactBroker
|
|
28
32
|
def list_latest
|
29
33
|
response = self.class.get("/pacts/latest", headers: default_get_headers)
|
30
34
|
handle_response(response) do
|
31
|
-
|
35
|
+
map_pact_list_to_hash JSON.parse(response.body)["pacts"]
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
@@ -43,7 +47,7 @@ module PactBroker
|
|
43
47
|
private
|
44
48
|
|
45
49
|
#TODO Move into mapper class
|
46
|
-
def
|
50
|
+
def map_pact_list_to_hash pacts_list
|
47
51
|
pacts_list.collect do | pact_hash |
|
48
52
|
{
|
49
53
|
consumer: {
|
@@ -59,6 +63,18 @@ module PactBroker
|
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
66
|
+
def find_latest_link response
|
67
|
+
links = response['_links']
|
68
|
+
return nil unless links
|
69
|
+
key = links.keys.find{ | key | key =~ /latest/ && key =~ /pact/ && key =~ /version/ }
|
70
|
+
return links[key]['href'] if key
|
71
|
+
key = links.keys.find{ | key | key =~ /latest/ && key =~ /pact/ }
|
72
|
+
return links[key]['href'] if key
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
62
78
|
def find_latest_consumer_contract_query options
|
63
79
|
query = {:consumer => options[:consumer], :provider => options[:provider]}
|
64
80
|
query[:tag] = options[:tag] if options[:tag]
|
@@ -69,21 +85,21 @@ module PactBroker
|
|
69
85
|
consumer_name = encode_param(options[:consumer])
|
70
86
|
provider_name = encode_param(options[:provider])
|
71
87
|
tag = options[:tag] ? "/#{options[:tag]}" : ""
|
72
|
-
"/
|
88
|
+
"/pacts/provider/#{provider_name}/consumer/#{consumer_name}/latest#{tag}"
|
73
89
|
end
|
74
90
|
|
75
91
|
def get_consumer_contract_url options
|
76
92
|
consumer_name = encode_param(options[:consumer])
|
77
93
|
provider_name = encode_param(options[:provider])
|
78
94
|
consumer_version = encode_param(options[:consumer_version])
|
79
|
-
"/
|
95
|
+
"/pacts/provider/#{provider_name}/consumer/#{consumer_name}/version/#{consumer_version}"
|
80
96
|
end
|
81
97
|
|
82
98
|
def save_consumer_contract_url consumer_contract, consumer_version
|
83
99
|
consumer_name = encode_param(consumer_contract.consumer.name)
|
84
100
|
provider_name = encode_param(consumer_contract.provider.name)
|
85
101
|
version = encode_param(consumer_version)
|
86
|
-
"/
|
102
|
+
"/pacts/provider/#{provider_name}/consumer/#{consumer_name}/version/#{version}"
|
87
103
|
end
|
88
104
|
end
|
89
105
|
end
|
@@ -1,39 +1,49 @@
|
|
1
1
|
require 'pact_broker/client'
|
2
|
+
require 'pact_broker/client/retry'
|
2
3
|
|
3
4
|
module PactBroker
|
4
5
|
module Client
|
5
6
|
class PublishPacts
|
6
7
|
|
7
|
-
def initialize pact_broker_base_url, pact_files, consumer_version
|
8
|
+
def initialize pact_broker_base_url, pact_files, consumer_version, pact_broker_client_options={}
|
8
9
|
@pact_broker_base_url = pact_broker_base_url
|
9
10
|
@pact_files = pact_files
|
10
11
|
@consumer_version = consumer_version
|
12
|
+
@pact_broker_client_options = pact_broker_client_options
|
11
13
|
end
|
12
14
|
|
13
15
|
def call
|
14
16
|
validate
|
17
|
+
$stdout.puts("")
|
15
18
|
pact_files.collect{ | pact_file | publish_pact pact_file }.all?
|
16
19
|
end
|
17
20
|
|
18
21
|
private
|
19
22
|
|
20
|
-
attr_reader :pact_broker_base_url, :pact_files, :consumer_version
|
23
|
+
attr_reader :pact_broker_base_url, :pact_files, :consumer_version, :pact_broker_client_options
|
21
24
|
|
22
25
|
def pact_broker_client
|
23
|
-
@pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url)
|
26
|
+
@pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url, client_options: pact_broker_client_options)
|
24
27
|
end
|
25
28
|
|
26
29
|
def publish_pact pact_file
|
27
30
|
begin
|
28
|
-
puts "Publishing #{pact_file} to pact broker at #{pact_broker_base_url}"
|
29
|
-
|
30
|
-
true
|
31
|
+
$stdout.puts ">> Publishing #{pact_file} to pact broker at #{pact_broker_base_url}"
|
32
|
+
publish_pact_contents File.read(pact_file)
|
31
33
|
rescue => e
|
32
34
|
$stderr.puts "Failed to publish pact: #{pact_file} due to error: #{e.to_s}\n#{e.backtrace.join("\n")}"
|
33
35
|
false
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
39
|
+
def publish_pact_contents pact_file_contents
|
40
|
+
Retry.until_true do
|
41
|
+
latest_pact_url = pact_broker_client.pacticipants.versions.pacts.publish(pact_json: pact_file_contents, consumer_version: consumer_version)
|
42
|
+
$stdout.puts "The latest version of this pact can be accessed at the following URL (use this to configure the provider verification):\n#{latest_pact_url}\n\n"
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
37
47
|
def validate
|
38
48
|
raise "Please specify the consumer_version" unless (consumer_version && consumer_version.to_s.strip.size > 0)
|
39
49
|
raise "Please specify the pact_broker_base_url" unless (pact_broker_base_url && pact_broker_base_url.to_s.strip.size > 0)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module PactBroker
|
2
|
+
module Client
|
3
|
+
class Retry
|
4
|
+
|
5
|
+
def self.until_true options = {}
|
6
|
+
max_tries = options.fetch(:times, 3)
|
7
|
+
tries = 0
|
8
|
+
while true
|
9
|
+
begin
|
10
|
+
return yield
|
11
|
+
rescue StandardError => e
|
12
|
+
tries += 1
|
13
|
+
$stderr.puts "Error publishing pact - #{e.message}, attempt #{tries} of #{max_tries}"
|
14
|
+
sleep options
|
15
|
+
raise e if max_tries == tries
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.sleep options
|
21
|
+
Kernel.sleep options.fetch(:sleep, 5)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -15,7 +15,7 @@ module PactBroker
|
|
15
15
|
module Client
|
16
16
|
class PublicationTask < ::Rake::TaskLib
|
17
17
|
|
18
|
-
attr_accessor :pattern, :pact_broker_base_url, :consumer_version
|
18
|
+
attr_accessor :pattern, :pact_broker_base_url, :consumer_version, :pact_broker_basic_auth
|
19
19
|
|
20
20
|
def initialize name = nil, &block
|
21
21
|
@name = name
|
@@ -32,7 +32,8 @@ module PactBroker
|
|
32
32
|
task task_name do
|
33
33
|
block.call(self)
|
34
34
|
require 'pact_broker/client/publish_pacts'
|
35
|
-
|
35
|
+
pact_broker_client_options = pact_broker_basic_auth ? {basic_auth: pact_broker_basic_auth} :{}
|
36
|
+
success = PactBroker::Client::PublishPacts.new(pact_broker_base_url, FileList[pattern], consumer_version, pact_broker_client_options).call
|
36
37
|
raise "One or more pacts failed to be published" unless success
|
37
38
|
end
|
38
39
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'pact_broker/client/base_client'
|
2
|
+
module PactBroker
|
3
|
+
module Client
|
4
|
+
describe BaseClient do
|
5
|
+
describe '#initialize' do
|
6
|
+
let(:base_url) { 'http://pact_broker_base_url'}
|
7
|
+
let(:username) { 'pact_repo_username'}
|
8
|
+
let(:password) { 'pact_repo_password'}
|
9
|
+
let(:client_options) do
|
10
|
+
{
|
11
|
+
basic_auth: {
|
12
|
+
username: username,
|
13
|
+
password: password
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
context 'with basic url' do
|
18
|
+
it 'should set base url' do
|
19
|
+
base_client = BaseClient.new(base_url: base_url)
|
20
|
+
expect(base_client.base_url).to eq(base_url)
|
21
|
+
expect(BaseClient.base_uri).to eq(base_url)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with client options' do
|
26
|
+
subject { BaseClient.new(base_url: base_url, client_options: client_options) }
|
27
|
+
it 'should set client options ' do
|
28
|
+
expect(subject.client_options).to eq(client_options)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should set httpparty basic auth when client options contains basic auth' do
|
32
|
+
expect(BaseClient).to receive(:basic_auth).with(username, password)
|
33
|
+
subject
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'without client options' do
|
38
|
+
subject { BaseClient.new(base_url: base_url) }
|
39
|
+
it 'should set client options to empty hash ' do
|
40
|
+
expect(subject.client_options).to eq({})
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should not set httpparty basic auth' do
|
44
|
+
expect(BaseClient).to_not receive(:basic_auth).with(username, password)
|
45
|
+
subject
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -5,14 +5,41 @@ require 'pact_broker/client'
|
|
5
5
|
module PactBroker::Client
|
6
6
|
describe PactBrokerClient do
|
7
7
|
|
8
|
+
let(:client_options) do
|
9
|
+
{ some_option: 'option value'}
|
10
|
+
end
|
11
|
+
let(:base_url) { 'https://blah' }
|
12
|
+
|
8
13
|
describe 'initialize' do
|
9
14
|
subject { PactBrokerClient.new }
|
10
15
|
it 'sets the base_uri to http://pact-broker by default' do
|
11
16
|
expect(subject.base_url).to eq('http://pact-broker')
|
12
17
|
end
|
13
18
|
|
19
|
+
it 'sets the client options to empty hash by default' do
|
20
|
+
expect(subject.client_options).to eq({})
|
21
|
+
end
|
22
|
+
|
14
23
|
it 'allows configuration of the base_uri' do
|
15
|
-
expect(PactBrokerClient.new(base_url:
|
24
|
+
expect(PactBrokerClient.new(base_url: base_url).base_url).to eq(base_url)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'allows configuration of the client options' do
|
28
|
+
expect(PactBrokerClient.new(client_options: client_options).client_options).to eq(client_options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'pacticipants' do
|
33
|
+
it 'initializes pacticipants with base url and client options' do
|
34
|
+
expect(PactBroker::Client::Pacticipants).to receive(:new).with(base_url: base_url, client_options: client_options)
|
35
|
+
PactBrokerClient.new(base_url: base_url, client_options: client_options).pacticipants
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'pacts' do
|
40
|
+
it 'initializes [act] with base url and client options' do
|
41
|
+
expect(PactBroker::Client::Pacts).to receive(:new).with(base_url: base_url, client_options: client_options)
|
42
|
+
PactBrokerClient.new(base_url: base_url, client_options: client_options).pacts
|
16
43
|
end
|
17
44
|
end
|
18
45
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pact_broker/client/pacticipants'
|
2
|
+
module PactBroker
|
3
|
+
module Client
|
4
|
+
describe Pacticipants do
|
5
|
+
let(:client_options) do
|
6
|
+
{ some_option: 'option value'}
|
7
|
+
end
|
8
|
+
let(:base_url) { 'https://blah' }
|
9
|
+
|
10
|
+
describe 'versions' do
|
11
|
+
it 'initializes versions with base url and client options' do
|
12
|
+
expect(PactBroker::Client::Versions).to receive(:new).with(base_url: base_url, client_options: client_options)
|
13
|
+
Pacticipants.new(base_url: base_url, client_options: client_options).versions
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -9,22 +9,31 @@ module PactBroker
|
|
9
9
|
|
10
10
|
before do
|
11
11
|
FakeFS.activate!
|
12
|
-
pacts_client.stub(:publish)
|
13
|
-
PactBroker::Client::PactBrokerClient.stub(:new).with(base_url: pact_broker_base_url).and_return(pact_broker_client)
|
12
|
+
pacts_client.stub(:publish).and_return(latest_pact_url)
|
13
|
+
PactBroker::Client::PactBrokerClient.stub(:new).with(base_url: pact_broker_base_url, client_options: pact_broker_client_options).and_return(pact_broker_client)
|
14
14
|
end
|
15
15
|
|
16
16
|
after do
|
17
17
|
FakeFS.deactivate!
|
18
18
|
end
|
19
19
|
|
20
|
+
let(:latest_pact_url) { 'http://example.org/latest/pact' }
|
20
21
|
let(:pact_broker_client) { double("PactBroker::Client")}
|
21
22
|
let(:pact_files) { ['spec/pacts/consumer-provider.json']}
|
22
23
|
let(:consumer_version) { "1.2.3" }
|
23
24
|
let(:pact_hash) { {consumer: {name: 'Consumer'}, provider: {name: 'Provider'} } }
|
24
25
|
let(:pacts_client) { instance_double("PactBroker::ClientSupport::Pacts")}
|
25
26
|
let(:pact_broker_base_url) { 'http://some-host'}
|
27
|
+
let(:pact_broker_client_options) do
|
28
|
+
{
|
29
|
+
basic_auth: {
|
30
|
+
username: 'user',
|
31
|
+
password: 'pass'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
26
35
|
|
27
|
-
subject { PublishPacts.new(pact_broker_base_url, pact_files, consumer_version) }
|
36
|
+
subject { PublishPacts.new(pact_broker_base_url, pact_files, consumer_version, pact_broker_client_options) }
|
28
37
|
|
29
38
|
before do
|
30
39
|
FileUtils.mkdir_p "spec/pacts"
|
@@ -40,13 +49,20 @@ module PactBroker
|
|
40
49
|
end
|
41
50
|
|
42
51
|
context "when publishing is successful" do
|
52
|
+
|
53
|
+
it "puts the location of the latest pact" do
|
54
|
+
allow($stdout).to receive(:puts)
|
55
|
+
expect($stdout).to receive(:puts).with(/#{latest_pact_url}/)
|
56
|
+
subject.call
|
57
|
+
end
|
43
58
|
it "returns true" do
|
44
|
-
expect(subject.call).to
|
59
|
+
expect(subject.call).to be true
|
45
60
|
end
|
46
61
|
end
|
47
62
|
|
48
63
|
context "when publishing one or more pacts fails" do
|
49
64
|
let(:pact_files) { ['spec/pacts/doesnotexist.json','spec/pacts/consumer-provider.json']}
|
65
|
+
|
50
66
|
before do
|
51
67
|
$stderr.stub(:puts)
|
52
68
|
end
|
@@ -62,7 +78,7 @@ module PactBroker
|
|
62
78
|
end
|
63
79
|
|
64
80
|
it "returns false" do
|
65
|
-
expect(subject.call).to
|
81
|
+
expect(subject.call).to be false
|
66
82
|
end
|
67
83
|
end
|
68
84
|
|
@@ -86,6 +102,52 @@ module PactBroker
|
|
86
102
|
expect { subject.call }.to raise_error(/Please specify the pact_broker_base_url/)
|
87
103
|
end
|
88
104
|
end
|
105
|
+
|
106
|
+
context "when an error occurs every time while publishing a pact" do
|
107
|
+
|
108
|
+
before do
|
109
|
+
allow(Retry).to receive(:sleep)
|
110
|
+
allow(pacts_client).to receive(:publish).and_raise("an error")
|
111
|
+
allow($stderr).to receive(:puts)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "retries multiple times" do
|
115
|
+
expect(pacts_client).to receive(:publish).exactly(3).times
|
116
|
+
subject.call
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns false" do
|
120
|
+
expect(subject.call).to eq false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "when an error occurs less than the maximum number of retries" do
|
125
|
+
|
126
|
+
before do
|
127
|
+
allow(Retry).to receive(:sleep)
|
128
|
+
tries = 0
|
129
|
+
allow(pacts_client).to receive(:publish) do
|
130
|
+
if tries == 0
|
131
|
+
tries += 1
|
132
|
+
raise "an error"
|
133
|
+
else
|
134
|
+
latest_pact_url
|
135
|
+
end
|
136
|
+
end
|
137
|
+
allow($stderr).to receive(:puts)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "retries multiple times" do
|
141
|
+
expect(pacts_client).to receive(:publish).exactly(2).times
|
142
|
+
subject.call
|
143
|
+
end
|
144
|
+
|
145
|
+
it "returns true" do
|
146
|
+
expect(subject.call).to eq true
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
89
151
|
end
|
90
152
|
end
|
91
153
|
end
|