pact_broker-client 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/RELEASING.md +1 -1
- data/Rakefile +8 -2
- data/bin/pact-publish +4 -0
- data/gemfiles/default.gemfile.lock +11 -11
- data/gemfiles/ruby_under_22.gemfile.lock +11 -11
- data/lib/pact_broker/client/cli/custom_thor.rb +71 -0
- data/lib/pact_broker/client/cli/publish.rb +82 -0
- data/lib/pact_broker/client/error.rb +5 -0
- data/lib/pact_broker/client/merge_pacts.rb +57 -0
- data/lib/pact_broker/client/pact_file.rb +36 -0
- data/lib/pact_broker/client/pact_hash.rb +19 -0
- data/lib/pact_broker/client/pacts.rb +7 -8
- data/lib/pact_broker/client/publish_pacts.rb +35 -23
- data/lib/pact_broker/client/version.rb +1 -1
- data/pact-broker-client.gemspec +1 -1
- data/spec/lib/pact_broker/client/cli/custom_thor_spec.rb +105 -0
- data/spec/lib/pact_broker/client/cli/publish_spec.rb +128 -0
- data/spec/lib/pact_broker/client/merge_pacts_spec.rb +69 -0
- data/spec/lib/pact_broker/client/publish_pacts_spec.rb +38 -17
- data/spec/service_providers/pact_broker_client_publish_spec.rb +1 -1
- data/spec/support/cli_test_pacts/bar.json +0 -0
- data/spec/support/cli_test_pacts/foo.json +0 -0
- data/spec/support/shared_context.rb +2 -1
- metadata +35 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a630ec3051f4b51d5a8acb1ca7365bf47742eecd
|
|
4
|
+
data.tar.gz: 73f384f4e4609e169e54b4bcc464cc670c43b483
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7f0803e0421cf2499da988d58e6de8156fc2bfcd8c8ffab89e139431b51907c3c42d32293c754f98a64051c878dc942b17915038b6d563a155be5f3c5d5cbf90
|
|
7
|
+
data.tar.gz: 9ccc081095706def8781febb131ee1d85616e33eede87f554dc4c9d7e34728e427f4babe6f2f97b8ddb18a03e7cdac99259d93926d025c68d6fb288c1140343c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
<a name="v1.5.0"></a>
|
|
2
|
+
### v1.5.0 (2017-09-28)
|
|
3
|
+
|
|
4
|
+
#### Features
|
|
5
|
+
|
|
6
|
+
* **cli**
|
|
7
|
+
* add command line tool to publish pacts ([d031b98](/../../commit/d031b98))
|
|
8
|
+
|
|
9
|
+
* **publish pacts**
|
|
10
|
+
* merge pact files with same consumer/provider before publishing ([1c039a0](/../../commit/1c039a0))
|
|
11
|
+
|
|
1
12
|
<a name="v1.4.0"></a>
|
|
2
13
|
### v1.4.0 (2017-09-07)
|
|
3
14
|
|
data/RELEASING.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
4. Add files to git
|
|
10
10
|
|
|
11
|
-
$ git add CHANGELOG.md lib/pact_broker/client/version.rb
|
|
11
|
+
$ git add CHANGELOG.md lib/pact_broker/client/version.rb gemfiles
|
|
12
12
|
$ git commit -m "Releasing version $(ruby -r ./lib/pact_broker/client/version.rb -e "puts PactBroker::Client::VERSION")"
|
|
13
13
|
|
|
14
14
|
5. Release:
|
data/Rakefile
CHANGED
|
@@ -4,9 +4,15 @@ require 'conventional_changelog'
|
|
|
4
4
|
|
|
5
5
|
Dir.glob('lib/tasks/**/*.rake').each { |task| load "#{Dir.pwd}/#{task}" }
|
|
6
6
|
Dir.glob('tasks/**/*.rake').each { |task| load "#{Dir.pwd}/#{task}" }
|
|
7
|
-
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do | task |
|
|
8
|
+
task.rspec_opts = "--pattern spec/lib/**/*_spec.rb"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
RSpec::Core::RakeTask.new('spec:providers') do | task |
|
|
12
|
+
task.rspec_opts = "--pattern spec/service_providers/**/*_spec.rb"
|
|
13
|
+
end
|
|
8
14
|
|
|
9
|
-
task :default => [:spec]
|
|
15
|
+
task :default => [:spec, 'spec:providers']
|
|
10
16
|
|
|
11
17
|
task :generate_changelog do
|
|
12
18
|
require 'pact_broker/client/version'
|
data/bin/pact-publish
ADDED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
pact_broker-client (1.
|
|
4
|
+
pact_broker-client (1.5.0)
|
|
5
5
|
httparty
|
|
6
6
|
json
|
|
7
|
-
pact
|
|
8
7
|
term-ansicolor
|
|
9
8
|
|
|
10
9
|
GEM
|
|
@@ -18,21 +17,22 @@ GEM
|
|
|
18
17
|
thor (>= 0.14.0)
|
|
19
18
|
awesome_print (1.8.0)
|
|
20
19
|
coderay (1.1.2)
|
|
20
|
+
conventional-changelog (1.3.0)
|
|
21
21
|
crack (0.4.3)
|
|
22
22
|
safe_yaml (~> 1.0.0)
|
|
23
23
|
diff-lcs (1.3)
|
|
24
|
-
fakefs (0.11.
|
|
24
|
+
fakefs (0.11.2)
|
|
25
25
|
find_a_port (1.0.1)
|
|
26
26
|
hashdiff (0.3.6)
|
|
27
27
|
httparty (0.15.6)
|
|
28
28
|
multi_xml (>= 0.5.2)
|
|
29
29
|
json (2.1.0)
|
|
30
|
-
method_source (0.
|
|
30
|
+
method_source (0.9.0)
|
|
31
31
|
multi_xml (0.6.0)
|
|
32
|
-
pact (1.
|
|
32
|
+
pact (1.16.0)
|
|
33
33
|
json (> 1.8.5)
|
|
34
34
|
pact-mock_service (~> 2.0)
|
|
35
|
-
pact-support (~> 1.1)
|
|
35
|
+
pact-support (~> 1.1, >= 1.1.8)
|
|
36
36
|
rack-test (~> 0.6.2)
|
|
37
37
|
randexp (~> 0.1.7)
|
|
38
38
|
rspec (>= 2.14)
|
|
@@ -49,7 +49,7 @@ GEM
|
|
|
49
49
|
term-ansicolor (~> 1.0)
|
|
50
50
|
thor
|
|
51
51
|
webrick
|
|
52
|
-
pact-support (1.
|
|
52
|
+
pact-support (1.2.0)
|
|
53
53
|
awesome_print (~> 1.1)
|
|
54
54
|
find_a_port (~> 1.0.1)
|
|
55
55
|
json
|
|
@@ -58,10 +58,9 @@ GEM
|
|
|
58
58
|
rspec (>= 2.14)
|
|
59
59
|
term-ansicolor (~> 1.0)
|
|
60
60
|
thor
|
|
61
|
-
pry (0.
|
|
61
|
+
pry (0.11.1)
|
|
62
62
|
coderay (~> 1.1.0)
|
|
63
|
-
method_source (~> 0.
|
|
64
|
-
slop (~> 3.4)
|
|
63
|
+
method_source (~> 0.9.0)
|
|
65
64
|
public_suffix (3.0.0)
|
|
66
65
|
rack (2.0.3)
|
|
67
66
|
rack-test (0.6.3)
|
|
@@ -84,7 +83,6 @@ GEM
|
|
|
84
83
|
rspec-support (~> 3.6.0)
|
|
85
84
|
rspec-support (3.6.0)
|
|
86
85
|
safe_yaml (1.0.4)
|
|
87
|
-
slop (3.6.0)
|
|
88
86
|
term-ansicolor (1.6.0)
|
|
89
87
|
tins (~> 1.0)
|
|
90
88
|
thor (0.20.0)
|
|
@@ -100,7 +98,9 @@ PLATFORMS
|
|
|
100
98
|
|
|
101
99
|
DEPENDENCIES
|
|
102
100
|
appraisal
|
|
101
|
+
conventional-changelog
|
|
103
102
|
fakefs (~> 0.4)
|
|
103
|
+
pact (~> 1.16)
|
|
104
104
|
pact_broker-client!
|
|
105
105
|
pry
|
|
106
106
|
rake (~> 10.0.3)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
pact_broker-client (1.
|
|
4
|
+
pact_broker-client (1.5.0)
|
|
5
5
|
httparty
|
|
6
6
|
json
|
|
7
|
-
pact
|
|
8
7
|
term-ansicolor
|
|
9
8
|
|
|
10
9
|
GEM
|
|
@@ -18,21 +17,22 @@ GEM
|
|
|
18
17
|
thor (>= 0.14.0)
|
|
19
18
|
awesome_print (1.8.0)
|
|
20
19
|
coderay (1.1.2)
|
|
20
|
+
conventional-changelog (1.3.0)
|
|
21
21
|
crack (0.4.3)
|
|
22
22
|
safe_yaml (~> 1.0.0)
|
|
23
23
|
diff-lcs (1.3)
|
|
24
|
-
fakefs (0.11.
|
|
24
|
+
fakefs (0.11.2)
|
|
25
25
|
find_a_port (1.0.1)
|
|
26
26
|
hashdiff (0.3.6)
|
|
27
27
|
httparty (0.15.6)
|
|
28
28
|
multi_xml (>= 0.5.2)
|
|
29
29
|
json (2.1.0)
|
|
30
|
-
method_source (0.
|
|
30
|
+
method_source (0.9.0)
|
|
31
31
|
multi_xml (0.6.0)
|
|
32
|
-
pact (1.
|
|
32
|
+
pact (1.16.0)
|
|
33
33
|
json (> 1.8.5)
|
|
34
34
|
pact-mock_service (~> 2.0)
|
|
35
|
-
pact-support (~> 1.1)
|
|
35
|
+
pact-support (~> 1.1, >= 1.1.8)
|
|
36
36
|
rack-test (~> 0.6.2)
|
|
37
37
|
randexp (~> 0.1.7)
|
|
38
38
|
rspec (>= 2.14)
|
|
@@ -49,7 +49,7 @@ GEM
|
|
|
49
49
|
term-ansicolor (~> 1.0)
|
|
50
50
|
thor
|
|
51
51
|
webrick
|
|
52
|
-
pact-support (1.
|
|
52
|
+
pact-support (1.2.0)
|
|
53
53
|
awesome_print (~> 1.1)
|
|
54
54
|
find_a_port (~> 1.0.1)
|
|
55
55
|
json
|
|
@@ -58,10 +58,9 @@ GEM
|
|
|
58
58
|
rspec (>= 2.14)
|
|
59
59
|
term-ansicolor (~> 1.0)
|
|
60
60
|
thor
|
|
61
|
-
pry (0.
|
|
61
|
+
pry (0.11.1)
|
|
62
62
|
coderay (~> 1.1.0)
|
|
63
|
-
method_source (~> 0.
|
|
64
|
-
slop (~> 3.4)
|
|
63
|
+
method_source (~> 0.9.0)
|
|
65
64
|
public_suffix (3.0.0)
|
|
66
65
|
rack (1.6.8)
|
|
67
66
|
rack-test (0.6.3)
|
|
@@ -84,7 +83,6 @@ GEM
|
|
|
84
83
|
rspec-support (~> 3.6.0)
|
|
85
84
|
rspec-support (3.6.0)
|
|
86
85
|
safe_yaml (1.0.4)
|
|
87
|
-
slop (3.6.0)
|
|
88
86
|
term-ansicolor (1.6.0)
|
|
89
87
|
tins (~> 1.0)
|
|
90
88
|
thor (0.20.0)
|
|
@@ -100,7 +98,9 @@ PLATFORMS
|
|
|
100
98
|
|
|
101
99
|
DEPENDENCIES
|
|
102
100
|
appraisal
|
|
101
|
+
conventional-changelog
|
|
103
102
|
fakefs (~> 0.4)
|
|
103
|
+
pact (~> 1.16)
|
|
104
104
|
pact_broker-client!
|
|
105
105
|
pry
|
|
106
106
|
rack (< 2.0)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
|
|
3
|
+
module PactBroker
|
|
4
|
+
module Client
|
|
5
|
+
module CLI
|
|
6
|
+
##
|
|
7
|
+
# Custom Thor task allows the following:
|
|
8
|
+
#
|
|
9
|
+
# `script arg1 arg2` to be interpreted as `script <default_task> arg1 arg2`
|
|
10
|
+
# `--option 1 --option 2` to be interpreted as `--option 1 2` (the standard Thor format for multiple value options)
|
|
11
|
+
# `script --help` to display the help for the default task instead of the command list
|
|
12
|
+
#
|
|
13
|
+
class CustomThor < ::Thor
|
|
14
|
+
|
|
15
|
+
no_commands do
|
|
16
|
+
def self.start given_args = ARGV, config = {}
|
|
17
|
+
super(massage_args(given_args))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def help *args
|
|
21
|
+
if args.empty?
|
|
22
|
+
super(self.class.default_task)
|
|
23
|
+
else
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.massage_args argv
|
|
29
|
+
prepend_default_task_name(turn_muliple_tag_options_into_array(argv))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.prepend_default_task_name argv
|
|
33
|
+
if known_first_arguments.include?(argv[0])
|
|
34
|
+
argv
|
|
35
|
+
else
|
|
36
|
+
[default_command] + argv
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# other task names, help, and the help shortcuts
|
|
41
|
+
def self.known_first_arguments
|
|
42
|
+
@known_first_arguments ||= tasks.keys + ::Thor::HELP_MAPPINGS + ['help']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.turn_muliple_tag_options_into_array argv
|
|
46
|
+
new_argv = []
|
|
47
|
+
opt_name = nil
|
|
48
|
+
argv.each_with_index do | arg, i |
|
|
49
|
+
if arg.start_with?('-')
|
|
50
|
+
opt_name = arg
|
|
51
|
+
existing = new_argv.find { | a | a.first == opt_name }
|
|
52
|
+
if !existing
|
|
53
|
+
new_argv << [arg]
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
if opt_name
|
|
57
|
+
existing = new_argv.find { | a | a.first == opt_name }
|
|
58
|
+
existing << arg
|
|
59
|
+
opt_name = nil
|
|
60
|
+
else
|
|
61
|
+
new_argv << [arg]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
new_argv.flatten
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'pact_broker/client/cli/custom_thor'
|
|
2
|
+
require 'pact_broker/client/publish_pacts'
|
|
3
|
+
require 'pact_broker/client/version'
|
|
4
|
+
require 'rake/file_list'
|
|
5
|
+
|
|
6
|
+
module PactBroker
|
|
7
|
+
module Client
|
|
8
|
+
module CLI
|
|
9
|
+
|
|
10
|
+
# Thor::Error will have its backtrace hidden
|
|
11
|
+
class PactPublicationError < ::Thor::Error; end
|
|
12
|
+
|
|
13
|
+
class Publish < CustomThor
|
|
14
|
+
desc 'PACT_DIRS_OR_FILES ...', "Publish pacts to a Pact Broker."
|
|
15
|
+
method_option :consumer_version, required: true, aliases: "-v", desc: "The consumer application version"
|
|
16
|
+
method_option :broker_base_url, required: true, aliases: "-b", desc: "The base URL of the Pact Broker"
|
|
17
|
+
method_option :username, aliases: "-u", desc: "Basic auth username for Pact Broker"
|
|
18
|
+
method_option :password, aliases: "-p", desc: "Basic auth password for Pact Broker"
|
|
19
|
+
method_option :tag, aliases: "-t", type: :array, banner: "TAG", desc: "Tag name for consumer version. Can be specified multiple times."
|
|
20
|
+
|
|
21
|
+
def broker(*pact_files)
|
|
22
|
+
validate(pact_files)
|
|
23
|
+
success = publish_pacts(pact_files)
|
|
24
|
+
raise PactPublicationError, "One or more pacts failed to be published" unless success
|
|
25
|
+
rescue PactBroker::Client::Error => e
|
|
26
|
+
raise PactPublicationError, "#{e.class} - #{e.message}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
desc 'version', "Show the pact_broker-client gem version"
|
|
30
|
+
def version
|
|
31
|
+
$stdout.puts PactBroker::Client::VERSION
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
default_task :broker
|
|
35
|
+
|
|
36
|
+
no_commands do
|
|
37
|
+
|
|
38
|
+
def validate pact_files
|
|
39
|
+
unless pact_files && pact_files.any?
|
|
40
|
+
raise RequiredArgumentMissingError, "No value provided for required pact_files"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def publish_pacts pact_files
|
|
45
|
+
PactBroker::Client::PublishPacts.call(
|
|
46
|
+
options[:broker_base_url],
|
|
47
|
+
file_list(pact_files),
|
|
48
|
+
options[:consumer_version],
|
|
49
|
+
tags,
|
|
50
|
+
pact_broker_client_options
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def file_list pact_files
|
|
55
|
+
Rake::FileList[pact_files].collect do | path |
|
|
56
|
+
if File.directory?(path)
|
|
57
|
+
Rake::FileList[File.join(path, "*.json")]
|
|
58
|
+
else
|
|
59
|
+
path
|
|
60
|
+
end
|
|
61
|
+
end.flatten
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def tags
|
|
65
|
+
[*options[:tag]].compact
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def pact_broker_client_options
|
|
69
|
+
if options[:username]
|
|
70
|
+
{
|
|
71
|
+
username: options[:username],
|
|
72
|
+
password: options[:password]
|
|
73
|
+
}
|
|
74
|
+
else
|
|
75
|
+
{}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'pact_broker/client/error'
|
|
3
|
+
|
|
4
|
+
module PactBroker
|
|
5
|
+
module Client
|
|
6
|
+
|
|
7
|
+
class PactMergeError < PactBroker::Client::Error; end
|
|
8
|
+
|
|
9
|
+
module MergePacts
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
def call pact_hashes
|
|
13
|
+
pact_hashes.reduce{|p1, p2| merge(p1, p2) }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Accepts two hashes representing pacts, outputs a merged hash
|
|
17
|
+
# Does not make any guarantees about order of interactions
|
|
18
|
+
def merge original, additional
|
|
19
|
+
new_pact = JSON.parse(original.to_json, symbolize_names: true)
|
|
20
|
+
|
|
21
|
+
additional[:interactions].each do |new_interaction|
|
|
22
|
+
# check to see if this interaction matches an existing interaction
|
|
23
|
+
overwrite_index = original[:interactions].find_index do |original_interaction|
|
|
24
|
+
same_description_and_state?(original_interaction, new_interaction)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# overwrite existing interaction if a match is found, otherwise appends the new interaction
|
|
28
|
+
if overwrite_index
|
|
29
|
+
if new_interaction == original[:interactions][overwrite_index]
|
|
30
|
+
new_pact[:interactions][overwrite_index] = new_interaction
|
|
31
|
+
else
|
|
32
|
+
raise PactMergeError, almost_duplicate_message(original[:interactions][overwrite_index], new_interaction)
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
new_pact[:interactions] << new_interaction
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
new_pact
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def almost_duplicate_message(original, new_interaction)
|
|
45
|
+
"An interaction with same description (#{new_interaction[:description].inspect}) and provider state (#{new_interaction[:providerState].inspect}) but a different request or response has already been used. " +
|
|
46
|
+
"Please use a different description or provider state, or hard-code any random data.\n" +
|
|
47
|
+
original.to_json + "\n\n"
|
|
48
|
+
new_interaction.to_json
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def same_description_and_state? original, additional
|
|
52
|
+
original[:description] == additional[:description] &&
|
|
53
|
+
original[:providerState] == additional[:providerState]
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'pact_broker/client/pact_hash'
|
|
3
|
+
|
|
4
|
+
module PactBroker
|
|
5
|
+
module Client
|
|
6
|
+
class PactFile
|
|
7
|
+
def initialize path
|
|
8
|
+
@path = path
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def path
|
|
12
|
+
@path
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def pact_name
|
|
16
|
+
pact_hash.pact_name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def consumer_name
|
|
20
|
+
pact_hash.consumer_name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def provider_name
|
|
24
|
+
pact_hash.provider_name
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def pact_hash
|
|
28
|
+
@pact_hash ||= PactHash[JSON.parse(read, symbolize_names: true)]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def read
|
|
32
|
+
@read ||= File.read(@path)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module PactBroker
|
|
4
|
+
module Client
|
|
5
|
+
class PactHash < ::Hash
|
|
6
|
+
def pact_name
|
|
7
|
+
"#{consumer_name}/#{provider_name} pact"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def consumer_name
|
|
11
|
+
self[:consumer][:name]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def provider_name
|
|
15
|
+
self[:provider][:name]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
require 'pact/consumer_contract'
|
|
2
1
|
require_relative 'base_client'
|
|
3
|
-
|
|
2
|
+
require 'pact_broker/client/pact_hash'
|
|
4
3
|
|
|
5
4
|
module PactBroker
|
|
6
5
|
module Client
|
|
@@ -8,9 +7,9 @@ module PactBroker
|
|
|
8
7
|
|
|
9
8
|
def publish options
|
|
10
9
|
consumer_version = options[:consumer_version]
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
url = save_consumer_contract_url
|
|
10
|
+
pact_hash = options[:pact_hash]
|
|
11
|
+
pact_string = pact_hash.to_json
|
|
12
|
+
url = save_consumer_contract_url pact_hash, consumer_version
|
|
14
13
|
|
|
15
14
|
if @client_options[:write] == :merge
|
|
16
15
|
response = self.class.patch(url, body: pact_string, headers: default_patch_headers)
|
|
@@ -128,9 +127,9 @@ module PactBroker
|
|
|
128
127
|
"/pacts/provider/#{provider_name}/consumer/#{consumer_name}/version/#{consumer_version}"
|
|
129
128
|
end
|
|
130
129
|
|
|
131
|
-
def save_consumer_contract_url
|
|
132
|
-
consumer_name = encode_param(
|
|
133
|
-
provider_name = encode_param(
|
|
130
|
+
def save_consumer_contract_url pact_hash, consumer_version
|
|
131
|
+
consumer_name = encode_param(pact_hash.consumer_name)
|
|
132
|
+
provider_name = encode_param(pact_hash.provider_name)
|
|
134
133
|
version = encode_param(consumer_version)
|
|
135
134
|
"/pacts/provider/#{provider_name}/consumer/#{consumer_name}/version/#{version}"
|
|
136
135
|
end
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
require 'term/ansicolor'
|
|
2
2
|
require 'pact_broker/client'
|
|
3
3
|
require 'pact_broker/client/retry'
|
|
4
|
+
require 'pact_broker/client/pact_file'
|
|
5
|
+
require 'pact_broker/client/pact_hash'
|
|
6
|
+
require 'pact_broker/client/merge_pacts'
|
|
4
7
|
|
|
5
8
|
module PactBroker
|
|
6
9
|
module Client
|
|
7
10
|
class PublishPacts
|
|
8
11
|
|
|
9
|
-
def
|
|
12
|
+
def self.call(pact_broker_base_url, pact_file_paths, consumer_version, tags, pact_broker_client_options={})
|
|
13
|
+
new(pact_broker_base_url, pact_file_paths, consumer_version, tags, pact_broker_client_options).call
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize pact_broker_base_url, pact_file_paths, consumer_version, tags, pact_broker_client_options={}
|
|
10
17
|
@pact_broker_base_url = pact_broker_base_url
|
|
11
|
-
@
|
|
18
|
+
@pact_file_paths = pact_file_paths
|
|
12
19
|
@consumer_version = consumer_version
|
|
13
20
|
@tags = tags
|
|
14
21
|
@pact_broker_client_options = pact_broker_client_options
|
|
@@ -24,22 +31,33 @@ module PactBroker
|
|
|
24
31
|
|
|
25
32
|
private
|
|
26
33
|
|
|
27
|
-
attr_reader :pact_broker_base_url, :
|
|
34
|
+
attr_reader :pact_broker_base_url, :pact_file_paths, :consumer_version, :tags, :pact_broker_client_options
|
|
28
35
|
|
|
29
36
|
def pact_broker_client
|
|
30
37
|
@pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url, client_options: pact_broker_client_options)
|
|
31
38
|
end
|
|
32
39
|
|
|
33
40
|
def publish_pacts
|
|
34
|
-
pact_files.collect
|
|
41
|
+
pact_files.group_by(&:pact_name).collect do | pact_name, pact_files |
|
|
42
|
+
$stdout.puts "Merging #{pact_files.collect(&:path).join(", ")}" if pact_files.size > 1
|
|
43
|
+
publish_pact(PactHash[merge_contents(pact_files)])
|
|
44
|
+
end.all?
|
|
35
45
|
end
|
|
36
46
|
|
|
37
|
-
def
|
|
47
|
+
def merge_contents(pact_files)
|
|
48
|
+
MergePacts.call(pact_files.collect(&:pact_hash))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def pact_files
|
|
52
|
+
@pact_files ||= pact_file_paths.collect{ |pact_file_path| PactFile.new(pact_file_path) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def publish_pact pact
|
|
38
56
|
begin
|
|
39
|
-
$stdout.puts "
|
|
40
|
-
publish_pact_contents
|
|
57
|
+
$stdout.puts "Publishing #{pact.pact_name} to pact broker at #{pact_broker_base_url}"
|
|
58
|
+
publish_pact_contents pact
|
|
41
59
|
rescue => e
|
|
42
|
-
$stderr.puts "Failed to publish
|
|
60
|
+
$stderr.puts "Failed to publish #{pact.pact_name} due to error: #{e.class} - #{e}"
|
|
43
61
|
false
|
|
44
62
|
end
|
|
45
63
|
end
|
|
@@ -59,38 +77,32 @@ module PactBroker
|
|
|
59
77
|
true
|
|
60
78
|
end
|
|
61
79
|
rescue => e
|
|
62
|
-
$stderr.puts "Failed to tag version #{consumer_version} of #{consumer_name} due to error: #{e.
|
|
80
|
+
$stderr.puts "Failed to tag version #{consumer_version} of #{consumer_name} due to error: #{e.class} - #{e}}"
|
|
63
81
|
false
|
|
64
82
|
end
|
|
65
83
|
|
|
66
|
-
def publish_pact_contents(
|
|
84
|
+
def publish_pact_contents(pact)
|
|
67
85
|
Retry.until_true do
|
|
68
|
-
contract = contract_from_file(pact_file_contents)
|
|
69
86
|
pacts = pact_broker_client.pacticipants.versions.pacts
|
|
70
|
-
if pacts.version_published?(consumer:
|
|
71
|
-
$stdout.puts ::Term::ANSIColor.yellow("The given version of pact is already published.
|
|
87
|
+
if pacts.version_published?(consumer: pact.consumer_name, provider: pact.provider_name, consumer_version: consumer_version)
|
|
88
|
+
$stdout.puts ::Term::ANSIColor.yellow("The given version of pact is already published. Overwriting...")
|
|
72
89
|
end
|
|
73
90
|
|
|
74
|
-
latest_pact_url = pacts.publish(
|
|
91
|
+
latest_pact_url = pacts.publish(pact_hash: pact, consumer_version: consumer_version)
|
|
75
92
|
$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}"
|
|
76
93
|
true
|
|
77
94
|
end
|
|
78
95
|
end
|
|
79
96
|
|
|
80
97
|
def consumer_name
|
|
81
|
-
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def contract_from_file pact_file_contents
|
|
85
|
-
::Pact::ConsumerContract.from_json(pact_file_contents)
|
|
98
|
+
pact_files.first.consumer_name
|
|
86
99
|
end
|
|
87
100
|
|
|
88
101
|
def validate
|
|
89
|
-
raise "Please specify the consumer_version" unless (consumer_version && consumer_version.to_s.strip.size > 0)
|
|
90
|
-
raise "Please specify the pact_broker_base_url" unless (pact_broker_base_url && pact_broker_base_url.to_s.strip.size > 0)
|
|
91
|
-
raise "No pact files found" unless (
|
|
102
|
+
raise PactBroker::Client::Error.new("Please specify the consumer_version") unless (consumer_version && consumer_version.to_s.strip.size > 0)
|
|
103
|
+
raise PactBroker::Client::Error.new("Please specify the pact_broker_base_url") unless (pact_broker_base_url && pact_broker_base_url.to_s.strip.size > 0)
|
|
104
|
+
raise PactBroker::Client::Error.new("No pact files found") unless (pact_file_paths && pact_file_paths.any?)
|
|
92
105
|
end
|
|
93
|
-
|
|
94
106
|
end
|
|
95
107
|
end
|
|
96
108
|
end
|
data/pact-broker-client.gemspec
CHANGED
|
@@ -21,7 +21,6 @@ Gem::Specification.new do |gem|
|
|
|
21
21
|
gem.require_paths = ["lib"]
|
|
22
22
|
gem.license = 'MIT'
|
|
23
23
|
|
|
24
|
-
gem.add_runtime_dependency 'pact'
|
|
25
24
|
gem.add_runtime_dependency 'httparty'
|
|
26
25
|
gem.add_runtime_dependency 'json'
|
|
27
26
|
gem.add_runtime_dependency 'term-ansicolor'
|
|
@@ -32,4 +31,5 @@ Gem::Specification.new do |gem|
|
|
|
32
31
|
gem.add_development_dependency 'appraisal'
|
|
33
32
|
gem.add_development_dependency 'webmock', '~> 3.0'
|
|
34
33
|
gem.add_development_dependency 'conventional-changelog'
|
|
34
|
+
gem.add_development_dependency 'pact', '~> 1.16'
|
|
35
35
|
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'pact_broker/client/cli/custom_thor'
|
|
2
|
+
|
|
3
|
+
module PactBroker::Client::CLI
|
|
4
|
+
|
|
5
|
+
class Delegate
|
|
6
|
+
def self.call options; end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class TestThor < CustomThor
|
|
10
|
+
desc 'ARGUMENT', 'This is the description'
|
|
11
|
+
def test_default(argument)
|
|
12
|
+
Delegate.call(argument: argument)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc '', ''
|
|
16
|
+
method_option :multi, type: :array
|
|
17
|
+
def test_multiple_options
|
|
18
|
+
Delegate.call(options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
default_command :test_default
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe CustomThor do
|
|
25
|
+
subject { TestThor.new }
|
|
26
|
+
|
|
27
|
+
it "invokes the default task when aguments are given without specifying a task" do
|
|
28
|
+
expect(Delegate).to receive(:call).with(argument: 'foo')
|
|
29
|
+
TestThor.start(%w{foo})
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "converts options that are specified multiple times into a single array" do
|
|
33
|
+
expect(Delegate).to receive(:call).with({'multi' => ['one', 'two']})
|
|
34
|
+
TestThor.start(%w{test_multiple_options --multi one --multi two})
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe ".prepend_default_task_name" do
|
|
38
|
+
let(:argv_with) { [TestThor.default_command, 'foo'] }
|
|
39
|
+
|
|
40
|
+
context "when the default task name is given" do
|
|
41
|
+
it "does not prepend the default task name" do
|
|
42
|
+
expect(TestThor.prepend_default_task_name(argv_with)).to eq(argv_with)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context "when the first argument is --help" do
|
|
47
|
+
let(:argv) { ['--help', 'foo'] }
|
|
48
|
+
|
|
49
|
+
it "does not prepend the default task name" do
|
|
50
|
+
expect(TestThor.prepend_default_task_name(argv)).to eq(argv)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when the default task name is not given" do
|
|
55
|
+
let(:argv) { ['foo'] }
|
|
56
|
+
|
|
57
|
+
it "prepends the default task name" do
|
|
58
|
+
expect(TestThor.prepend_default_task_name(argv)).to eq(argv_with)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe ".turn_muliple_tag_options_into_array" do
|
|
64
|
+
it "turns '--tag foo --tag bar' into '--tag foo bar'" do
|
|
65
|
+
input = %w{--ignore this --tag foo --tag bar --wiffle --that}
|
|
66
|
+
output = %w{--ignore this --tag foo bar --wiffle --that }
|
|
67
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "turns '--tag foo bar --tag meep' into '--tag foo meep bar'" do
|
|
71
|
+
input = %w{--ignore this --tag foo bar --tag meep --wiffle --that}
|
|
72
|
+
output = %w{--ignore this --tag foo meep bar --wiffle --that}
|
|
73
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "turns '--tag foo --tag bar wiffle' into '--tag foo bar wiffle' which is silly" do
|
|
77
|
+
input = %w{--ignore this --tag foo --tag bar wiffle}
|
|
78
|
+
output = %w{--ignore this --tag foo bar wiffle}
|
|
79
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "maintains '--tag foo bar wiffle'" do
|
|
83
|
+
input = %w{--ignore this --tag foo bar wiffle --meep}
|
|
84
|
+
output = %w{--ignore this --tag foo bar wiffle --meep}
|
|
85
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "turns '-t foo -t bar' into '-t foo bar'" do
|
|
89
|
+
input = %w{--ignore this -t foo -t bar --meep --that 1 2 3}
|
|
90
|
+
output = %w{--ignore this -t foo bar --meep --that 1 2 3}
|
|
91
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq output
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "doesn't change anything when there are no duplicate options" do
|
|
95
|
+
input = %w{--ignore this --taggy foo --blah bar --wiffle --that}
|
|
96
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq input
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "return an empty array when given an empty array" do
|
|
100
|
+
input = []
|
|
101
|
+
expect(TestThor.turn_muliple_tag_options_into_array(input)).to eq input
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
require 'pact_broker/client/cli/publish'
|
|
2
|
+
|
|
3
|
+
module PactBroker::Client::CLI
|
|
4
|
+
describe Publish do
|
|
5
|
+
describe ".broker" do
|
|
6
|
+
before do
|
|
7
|
+
allow(PactBroker::Client::PublishPacts).to receive(:call).and_return(true)
|
|
8
|
+
subject.options = minimum_valid_options
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
let(:file_list) { ["spec/support/cli_test_pacts/foo.json"] }
|
|
12
|
+
let(:minimum_valid_options) do
|
|
13
|
+
{
|
|
14
|
+
pact_dir: 'spec/pacts',
|
|
15
|
+
consumer_version: '1.2.3',
|
|
16
|
+
broker_base_url: 'http://pact-broker'
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
let(:invoke_broker) { subject.broker(*file_list) }
|
|
21
|
+
|
|
22
|
+
context "with minimum valid options" do
|
|
23
|
+
it "invokes the PublishPacts command" do
|
|
24
|
+
expect(PactBroker::Client::PublishPacts).to receive(:call).with(
|
|
25
|
+
"http://pact-broker",
|
|
26
|
+
["spec/support/cli_test_pacts/foo.json"],
|
|
27
|
+
"1.2.3",
|
|
28
|
+
[],
|
|
29
|
+
{}
|
|
30
|
+
)
|
|
31
|
+
invoke_broker
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "with a file pattern specified" do
|
|
36
|
+
let(:file_list) { ["spec/support/cli_test_pacts/*.json"] }
|
|
37
|
+
|
|
38
|
+
it "invokes the PublishPacts command with the expanded list of files" do
|
|
39
|
+
expect(PactBroker::Client::PublishPacts).to receive(:call).with(
|
|
40
|
+
anything,
|
|
41
|
+
["spec/support/cli_test_pacts/bar.json", "spec/support/cli_test_pacts/foo.json"],
|
|
42
|
+
anything,
|
|
43
|
+
anything,
|
|
44
|
+
anything
|
|
45
|
+
)
|
|
46
|
+
invoke_broker
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "with a pact directory specified" do
|
|
51
|
+
let(:file_list) { ["spec/support/cli_test_pacts"] }
|
|
52
|
+
|
|
53
|
+
it "invokes the PublishPacts command with the list of files in the directory" do
|
|
54
|
+
expect(PactBroker::Client::PublishPacts).to receive(:call).with(
|
|
55
|
+
anything,
|
|
56
|
+
["spec/support/cli_test_pacts/bar.json", "spec/support/cli_test_pacts/foo.json"],
|
|
57
|
+
anything,
|
|
58
|
+
anything,
|
|
59
|
+
anything
|
|
60
|
+
)
|
|
61
|
+
invoke_broker
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context "with a tag" do
|
|
66
|
+
before do
|
|
67
|
+
subject.options = minimum_valid_options.merge(tag: ['foo'])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "passes in the tag" do
|
|
71
|
+
expect(PactBroker::Client::PublishPacts).to receive(:call).with(
|
|
72
|
+
anything,
|
|
73
|
+
anything,
|
|
74
|
+
anything,
|
|
75
|
+
['foo'],
|
|
76
|
+
anything
|
|
77
|
+
)
|
|
78
|
+
invoke_broker
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context "with basic auth options specified" do
|
|
83
|
+
before do
|
|
84
|
+
subject.options = minimum_valid_options.merge(username: 'foo', password: 'bar')
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "passes in the basic auth options" do
|
|
88
|
+
expect(PactBroker::Client::PublishPacts).to receive(:call).with(
|
|
89
|
+
anything,
|
|
90
|
+
anything,
|
|
91
|
+
anything,
|
|
92
|
+
anything,
|
|
93
|
+
{username: 'foo', password: 'bar'}
|
|
94
|
+
)
|
|
95
|
+
invoke_broker
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context "when no pact files are specified" do
|
|
100
|
+
let(:file_list) { [] }
|
|
101
|
+
|
|
102
|
+
it "raises an error" do
|
|
103
|
+
expect { invoke_broker }.to raise_error ::Thor::RequiredArgumentMissingError, "No value provided for required pact_files"
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "when an error is raised publishing" do
|
|
108
|
+
before do
|
|
109
|
+
allow(PactBroker::Client::PublishPacts).to receive(:call).and_raise(PactBroker::Client::Error.new('foo'))
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "raises a PactPublicationError" do
|
|
113
|
+
expect { invoke_broker }.to raise_error PactPublicationError, /foo/
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context "when the publish command is not successful" do
|
|
118
|
+
before do
|
|
119
|
+
allow(PactBroker::Client::PublishPacts).to receive(:call).and_return(false)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "raises a PactPublicationError" do
|
|
123
|
+
expect { invoke_broker }.to raise_error PactPublicationError
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'pact_broker/client/merge_pacts'
|
|
2
|
+
|
|
3
|
+
module PactBroker
|
|
4
|
+
module Client
|
|
5
|
+
describe MergePacts do
|
|
6
|
+
describe ".call" do
|
|
7
|
+
let(:pact_hash_1) do
|
|
8
|
+
{
|
|
9
|
+
other: 'info',
|
|
10
|
+
interactions: [
|
|
11
|
+
{providerState: 1, description: 1, foo: 'bar' }
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
let(:pact_hash_2) do
|
|
17
|
+
{
|
|
18
|
+
interactions: [
|
|
19
|
+
{providerState: 2, description: 2, foo: 'wiffle' }
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
let(:pact_hash_3) do
|
|
25
|
+
{
|
|
26
|
+
interactions: [
|
|
27
|
+
{providerState: 3, description: 3, foo: 'meep' },
|
|
28
|
+
{providerState: 1, description: 1, foo: 'bar' }
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
let(:pact_hashes) { [pact_hash_1, pact_hash_2, pact_hash_3] }
|
|
34
|
+
|
|
35
|
+
let(:expected_merge) do
|
|
36
|
+
{
|
|
37
|
+
other: 'info',
|
|
38
|
+
interactions: [
|
|
39
|
+
{providerState: 1, description: 1, foo: 'bar' },
|
|
40
|
+
{providerState: 2, description: 2, foo: 'wiffle' },
|
|
41
|
+
{providerState: 3, description: 3, foo: 'meep' }
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
subject { MergePacts.call(pact_hashes) }
|
|
47
|
+
|
|
48
|
+
it "merges the interactions by consumer/provider" do
|
|
49
|
+
expect(subject).to eq expected_merge
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "when an interaction is found with the same state and description but has a difference elsewhere" do
|
|
53
|
+
let(:pact_hash_3) do
|
|
54
|
+
{
|
|
55
|
+
interactions: [
|
|
56
|
+
{providerState: 3, description: 3, foo: 'meep' },
|
|
57
|
+
{providerState: 1, description: 1, foo: 'different' }
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "raises an error" do
|
|
63
|
+
expect { subject }.to raise_error PactMergeError
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -7,11 +7,24 @@ module PactBroker
|
|
|
7
7
|
module Client
|
|
8
8
|
describe PublishPacts do
|
|
9
9
|
|
|
10
|
+
# The amount of stubbing that we have to do here indicates this class is doing
|
|
11
|
+
# TOO MUCH and needs to be split up!
|
|
10
12
|
before do
|
|
11
13
|
FakeFS.activate!
|
|
12
14
|
allow(pacts_client).to receive(:publish).and_return(latest_pact_url)
|
|
13
|
-
allow(PactBroker::Client::PactBrokerClient).to receive(:new)
|
|
15
|
+
allow(PactBroker::Client::PactBrokerClient).to receive(:new)
|
|
16
|
+
.with(base_url: pact_broker_base_url, client_options: pact_broker_client_options)
|
|
17
|
+
.and_return(pact_broker_client)
|
|
18
|
+
allow(pact_broker_client).to receive_message_chain(:pacticipants, :versions).and_return(pact_versions_client)
|
|
19
|
+
allow(pact_broker_client).to receive_message_chain(:pacticipants, :versions, :pacts).and_return(pacts_client)
|
|
20
|
+
allow(pacts_client).to receive(:version_published?).and_return(false)
|
|
14
21
|
allow($stdout).to receive(:puts)
|
|
22
|
+
allow(Retry).to receive(:sleep)
|
|
23
|
+
allow(MergePacts).to receive(:call) { | pact_hashes | pact_hashes[0] }
|
|
24
|
+
FileUtils.mkdir_p "spec/pacts"
|
|
25
|
+
File.open("spec/pacts/consumer-provider.json", "w") { |file| file << pact_hash.to_json }
|
|
26
|
+
File.open("spec/pacts/consumer-provider-2.json", "w") { |file| file << pact_hash.to_json }
|
|
27
|
+
File.open("spec/pacts/foo-bar.json", "w") { |file| file << pact_hash_2.to_json }
|
|
15
28
|
end
|
|
16
29
|
|
|
17
30
|
after do
|
|
@@ -20,10 +33,11 @@ module PactBroker
|
|
|
20
33
|
|
|
21
34
|
let(:latest_pact_url) { 'http://example.org/latest/pact' }
|
|
22
35
|
let(:pact_broker_client) { double("PactBroker::Client")}
|
|
23
|
-
let(:
|
|
36
|
+
let(:pact_file_paths) { ['spec/pacts/consumer-provider.json']}
|
|
24
37
|
let(:consumer_version) { "1.2.3" }
|
|
25
38
|
let(:tags) { nil }
|
|
26
39
|
let(:pact_hash) { {consumer: {name: 'Consumer'}, provider: {name: 'Provider'}, interactions: [] } }
|
|
40
|
+
let(:pact_hash_2) { {consumer: {name: 'Foo'}, provider: {name: 'Bar'}, interactions: [] } }
|
|
27
41
|
let(:pacts_client) { instance_double("PactBroker::ClientSupport::Pacts")}
|
|
28
42
|
let(:pact_versions_client) { instance_double("PactBroker::Client::Versions", tag: false) }
|
|
29
43
|
let(:pact_broker_base_url) { 'http://some-host'}
|
|
@@ -36,20 +50,12 @@ module PactBroker
|
|
|
36
50
|
}
|
|
37
51
|
end
|
|
38
52
|
|
|
39
|
-
subject { PublishPacts.new(pact_broker_base_url,
|
|
40
|
-
|
|
41
|
-
before do
|
|
42
|
-
FileUtils.mkdir_p "spec/pacts"
|
|
43
|
-
File.open("spec/pacts/consumer-provider.json", "w") { |file| file << pact_hash.to_json }
|
|
44
|
-
allow(pact_broker_client).to receive_message_chain(:pacticipants, :versions).and_return(pact_versions_client)
|
|
45
|
-
allow(pact_broker_client).to receive_message_chain(:pacticipants, :versions, :pacts).and_return(pacts_client)
|
|
46
|
-
allow(pacts_client).to receive(:version_published?).and_return(false)
|
|
47
|
-
end
|
|
53
|
+
subject { PublishPacts.new(pact_broker_base_url, pact_file_paths, consumer_version, tags, pact_broker_client_options) }
|
|
48
54
|
|
|
49
55
|
describe "call" do
|
|
50
56
|
|
|
51
57
|
it "uses the pact_broker client to publish the given pact" do
|
|
52
|
-
expect(pacts_client).to receive(:publish).with(
|
|
58
|
+
expect(pacts_client).to receive(:publish).with(pact_hash: pact_hash, consumer_version: consumer_version)
|
|
53
59
|
subject.call
|
|
54
60
|
end
|
|
55
61
|
|
|
@@ -65,20 +71,34 @@ module PactBroker
|
|
|
65
71
|
end
|
|
66
72
|
end
|
|
67
73
|
|
|
74
|
+
context "when publishing multiple files with the same consumer/provider" do
|
|
75
|
+
let(:pact_file_paths) { ['spec/pacts/consumer-provider.json','spec/pacts/consumer-provider-2.json']}
|
|
76
|
+
it "merges the files" do
|
|
77
|
+
expect(MergePacts).to receive(:call).with([pact_hash, pact_hash])
|
|
78
|
+
subject.call
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
68
82
|
context "when publishing one or more pacts fails" do
|
|
69
|
-
let(:
|
|
83
|
+
let(:pact_file_paths) { ['spec/pacts/consumer-provider.json','spec/pacts/foo-bar.json']}
|
|
70
84
|
|
|
71
85
|
before do
|
|
86
|
+
allow(pacts_client).to receive(:publish).with(
|
|
87
|
+
pact_hash: pact_hash,
|
|
88
|
+
consumer_version: consumer_version
|
|
89
|
+
).and_raise("an error")
|
|
90
|
+
|
|
72
91
|
allow($stderr).to receive(:puts)
|
|
73
92
|
end
|
|
74
93
|
|
|
75
94
|
it "logs an message to stderr" do
|
|
76
|
-
expect($stderr).to receive(:puts).with(/Failed to publish pact/)
|
|
95
|
+
expect($stderr).to receive(:puts).with(/Failed to publish Consumer\/Provider pact/)
|
|
77
96
|
subject.call
|
|
78
97
|
end
|
|
79
98
|
|
|
80
99
|
it "continues publishing the rest" do
|
|
81
|
-
expect(pacts_client).to receive(:publish).with(
|
|
100
|
+
expect(pacts_client).to receive(:publish).with(
|
|
101
|
+
pact_hash: pact_hash_2, consumer_version: consumer_version)
|
|
82
102
|
subject.call
|
|
83
103
|
end
|
|
84
104
|
|
|
@@ -88,7 +108,7 @@ module PactBroker
|
|
|
88
108
|
end
|
|
89
109
|
|
|
90
110
|
context "when no pact files are specified" do
|
|
91
|
-
let(:
|
|
111
|
+
let(:pact_file_paths) { [] }
|
|
92
112
|
it "raises a validation error" do
|
|
93
113
|
expect { subject.call }.to raise_error(/No pact files found/)
|
|
94
114
|
end
|
|
@@ -112,7 +132,8 @@ module PactBroker
|
|
|
112
132
|
let(:tags) { ["dev"] }
|
|
113
133
|
|
|
114
134
|
it "tags the consumer version" do
|
|
115
|
-
expect(pact_versions_client).to receive(:tag).with({pacticipant: "Consumer",
|
|
135
|
+
expect(pact_versions_client).to receive(:tag).with({pacticipant: "Consumer",
|
|
136
|
+
version: consumer_version, tag: "dev"})
|
|
116
137
|
subject.call
|
|
117
138
|
end
|
|
118
139
|
|
|
@@ -5,7 +5,7 @@ module PactBroker::Client
|
|
|
5
5
|
|
|
6
6
|
describe "publishing a pact" do
|
|
7
7
|
|
|
8
|
-
let(:options) { {
|
|
8
|
+
let(:options) { { pact_hash: pact_hash, consumer_version: consumer_version }}
|
|
9
9
|
let(:location) { 'http://example.org/pacts/provider/Pricing%20Service/consumer/Condor/latest' }
|
|
10
10
|
context "when the provider already exists in the pact-broker" do
|
|
11
11
|
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
require 'pact_broker/client/pact_hash'
|
|
1
2
|
shared_context "pact broker" do
|
|
2
3
|
|
|
3
|
-
let(:pact_hash) {
|
|
4
|
+
let(:pact_hash) { PactBroker::Client::PactHash[consumer: {name: 'Condor'}, provider: {name: 'Pricing Service'}, interactions: []] }
|
|
4
5
|
let(:consumer_contract) { Pact::ConsumerContract.from_hash pact_hash }
|
|
5
6
|
let(:pact_json) { pact_hash.to_json }
|
|
6
7
|
let(:pact_broker_client) { PactBroker::Client::PactBrokerClient.new(client_config) }
|
metadata
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pact_broker-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bethany Skurrie
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-09-
|
|
11
|
+
date: 2017-09-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: pact
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
20
|
-
type: :runtime
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
27
13
|
- !ruby/object:Gem::Dependency
|
|
28
14
|
name: httparty
|
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -150,10 +136,25 @@ dependencies:
|
|
|
150
136
|
- - ">="
|
|
151
137
|
- !ruby/object:Gem::Version
|
|
152
138
|
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: pact
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '1.16'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '1.16'
|
|
153
153
|
description: Publishes pacts to, and retrieves pacts from, the pact broker server.
|
|
154
154
|
email:
|
|
155
155
|
- bskurrie@dius.com.au
|
|
156
|
-
executables:
|
|
156
|
+
executables:
|
|
157
|
+
- pact-publish
|
|
157
158
|
extensions: []
|
|
158
159
|
extra_rdoc_files: []
|
|
159
160
|
files:
|
|
@@ -166,6 +167,7 @@ files:
|
|
|
166
167
|
- README.md
|
|
167
168
|
- RELEASING.md
|
|
168
169
|
- Rakefile
|
|
170
|
+
- bin/pact-publish
|
|
169
171
|
- ci.sh
|
|
170
172
|
- doc/markdown/Pact Broker Client - Pact Broker.md
|
|
171
173
|
- doc/markdown/README.md
|
|
@@ -175,7 +177,13 @@ files:
|
|
|
175
177
|
- gemfiles/ruby_under_22.gemfile.lock
|
|
176
178
|
- lib/pact_broker/client.rb
|
|
177
179
|
- lib/pact_broker/client/base_client.rb
|
|
180
|
+
- lib/pact_broker/client/cli/custom_thor.rb
|
|
181
|
+
- lib/pact_broker/client/cli/publish.rb
|
|
182
|
+
- lib/pact_broker/client/error.rb
|
|
183
|
+
- lib/pact_broker/client/merge_pacts.rb
|
|
178
184
|
- lib/pact_broker/client/pact_broker_client.rb
|
|
185
|
+
- lib/pact_broker/client/pact_file.rb
|
|
186
|
+
- lib/pact_broker/client/pact_hash.rb
|
|
179
187
|
- lib/pact_broker/client/pacticipants.rb
|
|
180
188
|
- lib/pact_broker/client/pacts.rb
|
|
181
189
|
- lib/pact_broker/client/publish_pacts.rb
|
|
@@ -187,6 +195,9 @@ files:
|
|
|
187
195
|
- lib/pact_broker_client.rb
|
|
188
196
|
- pact-broker-client.gemspec
|
|
189
197
|
- spec/lib/pact_broker/client/base_client_spec.rb
|
|
198
|
+
- spec/lib/pact_broker/client/cli/custom_thor_spec.rb
|
|
199
|
+
- spec/lib/pact_broker/client/cli/publish_spec.rb
|
|
200
|
+
- spec/lib/pact_broker/client/merge_pacts_spec.rb
|
|
190
201
|
- spec/lib/pact_broker/client/pact_broker_client_spec.rb
|
|
191
202
|
- spec/lib/pact_broker/client/pacticipants_spec.rb
|
|
192
203
|
- spec/lib/pact_broker/client/publish_pacts_spec.rb
|
|
@@ -202,6 +213,8 @@ files:
|
|
|
202
213
|
- spec/service_providers/pact_broker_client_tags_spec.rb
|
|
203
214
|
- spec/service_providers/pact_helper.rb
|
|
204
215
|
- spec/spec_helper.rb
|
|
216
|
+
- spec/support/cli_test_pacts/bar.json
|
|
217
|
+
- spec/support/cli_test_pacts/foo.json
|
|
205
218
|
- spec/support/latest_pacts_for_provider.json
|
|
206
219
|
- spec/support/pacticipant_get.json
|
|
207
220
|
- spec/support/pacticipants_list.json
|
|
@@ -234,6 +247,9 @@ specification_version: 4
|
|
|
234
247
|
summary: See description
|
|
235
248
|
test_files:
|
|
236
249
|
- spec/lib/pact_broker/client/base_client_spec.rb
|
|
250
|
+
- spec/lib/pact_broker/client/cli/custom_thor_spec.rb
|
|
251
|
+
- spec/lib/pact_broker/client/cli/publish_spec.rb
|
|
252
|
+
- spec/lib/pact_broker/client/merge_pacts_spec.rb
|
|
237
253
|
- spec/lib/pact_broker/client/pact_broker_client_spec.rb
|
|
238
254
|
- spec/lib/pact_broker/client/pacticipants_spec.rb
|
|
239
255
|
- spec/lib/pact_broker/client/publish_pacts_spec.rb
|
|
@@ -249,6 +265,8 @@ test_files:
|
|
|
249
265
|
- spec/service_providers/pact_broker_client_tags_spec.rb
|
|
250
266
|
- spec/service_providers/pact_helper.rb
|
|
251
267
|
- spec/spec_helper.rb
|
|
268
|
+
- spec/support/cli_test_pacts/bar.json
|
|
269
|
+
- spec/support/cli_test_pacts/foo.json
|
|
252
270
|
- spec/support/latest_pacts_for_provider.json
|
|
253
271
|
- spec/support/pacticipant_get.json
|
|
254
272
|
- spec/support/pacticipants_list.json
|