pact_broker-client 1.34.0 → 1.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/release_gem.yml +1 -0
  3. data/.github/workflows/test.yml +23 -0
  4. data/CHANGELOG.md +39 -0
  5. data/README.md +15 -3
  6. data/Rakefile +2 -0
  7. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +331 -8
  8. data/lib/pact_broker/client.rb +1 -1
  9. data/lib/pact_broker/client/backports.rb +13 -0
  10. data/lib/pact_broker/client/cli/broker.rb +112 -34
  11. data/lib/pact_broker/client/cli/can_i_deploy_long_desc.txt +18 -9
  12. data/lib/pact_broker/client/cli/create_or_update_webhook_long_desc.txt +3 -1
  13. data/lib/pact_broker/client/cli/create_webhook_long_desc.txt +2 -0
  14. data/lib/pact_broker/client/cli/custom_thor.rb +11 -17
  15. data/lib/pact_broker/client/git.rb +43 -22
  16. data/lib/pact_broker/client/hal/entity.rb +44 -3
  17. data/lib/pact_broker/client/hal/http_client.rb +5 -1
  18. data/lib/pact_broker/client/hal/links.rb +39 -0
  19. data/lib/pact_broker/client/hal_client_methods.rb +11 -0
  20. data/lib/pact_broker/client/hash_refinements.rb +19 -0
  21. data/lib/pact_broker/client/matrix.rb +2 -1
  22. data/lib/pact_broker/client/matrix/text_formatter.rb +46 -11
  23. data/lib/pact_broker/client/publish_pacts.rb +85 -14
  24. data/lib/pact_broker/client/tasks/publication_task.rb +37 -6
  25. data/lib/pact_broker/client/version.rb +1 -1
  26. data/lib/pact_broker/client/versions/record_deployment.rb +109 -0
  27. data/lib/pact_broker/client/versions/record_undeployment.rb +125 -0
  28. data/pact-broker-client.gemspec +2 -1
  29. data/script/publish-pact.sh +7 -1
  30. data/script/record-deployment.sh +4 -0
  31. data/script/trigger-release.sh +1 -1
  32. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +51 -6
  33. data/spec/lib/pact_broker/client/cli/broker_publish_spec.rb +108 -12
  34. data/spec/lib/pact_broker/client/cli/custom_thor_spec.rb +1 -7
  35. data/spec/lib/pact_broker/client/git_spec.rb +39 -2
  36. data/spec/lib/pact_broker/client/hal/entity_spec.rb +4 -3
  37. data/spec/lib/pact_broker/client/matrix/text_formatter_spec.rb +29 -4
  38. data/spec/lib/pact_broker/client/publish_pacts_spec.rb +99 -6
  39. data/spec/lib/pact_broker/client/tasks/publication_task_spec.rb +88 -10
  40. data/spec/lib/pact_broker/client/versions/describe_spec.rb +0 -1
  41. data/spec/lib/pact_broker/client/versions/record_deployment_spec.rb +82 -0
  42. data/spec/pacts/pact_broker_client-pact_broker.json +335 -8
  43. data/spec/service_providers/pact_broker_client_create_version_spec.rb +89 -0
  44. data/spec/service_providers/pact_broker_client_matrix_spec.rb +4 -0
  45. data/spec/service_providers/pact_broker_client_versions_spec.rb +1 -2
  46. data/spec/service_providers/record_deployment_spec.rb +219 -0
  47. data/spec/spec_helper.rb +2 -0
  48. data/spec/support/matrix.json +6 -1
  49. data/spec/support/matrix.txt +3 -3
  50. data/spec/support/matrix_error.txt +3 -3
  51. data/spec/support/matrix_with_results.txt +10 -0
  52. data/tasks/pact.rake +2 -0
  53. metadata +36 -8
  54. data/.travis.yml +0 -11
@@ -1,5 +1,6 @@
1
1
  require 'rake/tasklib'
2
2
  require 'pact_broker/client/git'
3
+ require 'pact_broker/client/hash_refinements'
3
4
 
4
5
  =begin
5
6
  require pact_broker/client/tasks
@@ -17,31 +18,52 @@ end
17
18
  module PactBroker
18
19
  module Client
19
20
  class PublicationTask < ::Rake::TaskLib
21
+ using PactBroker::Client::HashRefinements
20
22
 
21
23
  attr_accessor :pattern, :pact_broker_base_url, :consumer_version, :tag, :write_method, :tag_with_git_branch, :pact_broker_basic_auth, :pact_broker_token
24
+ attr_reader :auto_detect_version_properties, :branch, :build_url
22
25
  alias_method :tags=, :tag=
23
26
  alias_method :tags, :tag
24
27
 
25
28
  def initialize name = nil, &block
26
29
  @name = name
30
+ @auto_detect_version_properties = nil
31
+ @version_required = false
27
32
  @pattern = 'spec/pacts/*.json'
28
33
  @pact_broker_base_url = 'http://pact-broker'
29
34
  rake_task &block
30
35
  end
31
36
 
37
+ def auto_detect_version_properties= auto_detect_version_properties
38
+ @version_required = version_required || auto_detect_version_properties
39
+ @auto_detect_version_properties = auto_detect_version_properties
40
+ end
41
+
42
+ def branch= branch
43
+ @version_required = version_required || !!branch
44
+ @branch = branch
45
+ end
46
+
47
+ def build_url= build_url
48
+ @version_required = version_required || !!build_url
49
+ @build_url = build_url
50
+ end
51
+
32
52
  private
33
53
 
54
+ attr_reader :version_required
55
+
34
56
  def rake_task &block
35
57
  namespace :pact do
36
58
  desc "Publish pacts to pact broker"
37
59
  task task_name do
38
60
  block.call(self)
39
61
  require 'pact_broker/client/publish_pacts'
40
- pact_broker_client_options = {}
41
- .merge( pact_broker_basic_auth ? { basic_auth: pact_broker_basic_auth } : {} )
42
- .merge( write_method ? { write: write_method } : {} )
43
- .merge( pact_broker_token ? { token: pact_broker_token } : {} )
44
- success = PactBroker::Client::PublishPacts.new(pact_broker_base_url, FileList[pattern], consumer_version, all_tags, pact_broker_client_options).call
62
+ pact_broker_client_options = { write: write_method, token: pact_broker_token }
63
+ pact_broker_client_options[:basic_auth] = pact_broker_basic_auth if pact_broker_basic_auth && pact_broker_basic_auth.any?
64
+ pact_broker_client_options.compact!
65
+ consumer_version_params = { number: consumer_version, branch: the_branch, build_url: build_url, tags: all_tags, version_required: version_required }.compact
66
+ success = PactBroker::Client::PublishPacts.new(pact_broker_base_url, FileList[pattern], consumer_version_params, pact_broker_client_options).call
45
67
  raise "One or more pacts failed to be published" unless success
46
68
  end
47
69
  end
@@ -53,9 +75,18 @@ module PactBroker
53
75
 
54
76
  def all_tags
55
77
  t = [*tags]
56
- t << PactBroker::Client::Git.branch if tag_with_git_branch
78
+ t << PactBroker::Client::Git.branch(raise_error: true) if tag_with_git_branch
57
79
  t.compact.uniq
58
80
  end
81
+
82
+ def the_branch
83
+ if branch.nil? && auto_detect_version_properties != false
84
+ PactBroker::Client::Git.branch(raise_error: auto_detect_version_properties == true)
85
+ else
86
+ branch
87
+ end
88
+ end
89
+
59
90
  end
60
91
  end
61
92
  end
@@ -1,5 +1,5 @@
1
1
  module PactBroker
2
2
  module Client
3
- VERSION = '1.34.0'
3
+ VERSION = '1.38.0'
4
4
  end
5
5
  end
@@ -0,0 +1,109 @@
1
+ require 'pact_broker/client/hal_client_methods'
2
+ require 'pact_broker/client/error'
3
+ require 'pact_broker/client/command_result'
4
+
5
+ module PactBroker
6
+ module Client
7
+ class Versions
8
+ class RecordDeployment
9
+ include PactBroker::Client::HalClientMethods
10
+
11
+ NOT_SUPPORTED_MESSAGE = "This version of the Pact Broker does not support recording deployments. Please upgrade to version 2.80.0 or later."
12
+
13
+ def self.call(params, pact_broker_base_url, pact_broker_client_options)
14
+ new(params, pact_broker_base_url, pact_broker_client_options).call
15
+ end
16
+
17
+ def initialize(params, pact_broker_base_url, pact_broker_client_options)
18
+ @pact_broker_base_url = pact_broker_base_url
19
+ @pacticipant_name = params.fetch(:pacticipant_name)
20
+ @version_number = params.fetch(:version_number)
21
+ @environment_name = params.fetch(:environment_name)
22
+ @replaced_previous_deployed_version = params.fetch(:replaced_previous_deployed_version)
23
+ @output = params.fetch(:output)
24
+ @pact_broker_client_options = pact_broker_client_options
25
+ end
26
+
27
+ def call
28
+ check_if_command_supported
29
+ record_deployment
30
+
31
+ PactBroker::Client::CommandResult.new(true, result_message)
32
+ rescue PactBroker::Client::Error => e
33
+ PactBroker::Client::CommandResult.new(false, e.message)
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :pact_broker_base_url, :pact_broker_client_options
39
+ attr_reader :pacticipant_name, :version_number, :environment_name, :replaced_previous_deployed_version, :output
40
+ attr_reader :deployed_version_resource
41
+
42
+ def check_environment_exists
43
+ index_resource
44
+ ._link!("pb:environments")
45
+ .get!
46
+ ._links("pb:environments")
47
+ .find!(environment_name, "No environment found with name '#{environment_name}'")
48
+ end
49
+
50
+ def record_deployment
51
+ @deployed_version_resource =
52
+ get_record_deployment_relation
53
+ .post(record_deployment_request_body)
54
+ .assert_success!
55
+ end
56
+
57
+ def get_record_deployment_relation
58
+ record_deployment_links = get_pacticipant_version._links!("pb:record-deployment")
59
+ link_for_environment = record_deployment_links.find(environment_name)
60
+ if link_for_environment
61
+ link_for_environment
62
+ else
63
+ check_environment_exists
64
+ # Force the exception to be raised
65
+ record_deployment_links.find!(environment_name, "Environment '#{environment_name}' is not an available option for recording a deployment of #{pacticipant_name}.")
66
+ end
67
+ end
68
+
69
+ def get_pacticipant_version
70
+ index_resource
71
+ ._link!("pb:pacticipant-version")
72
+ .expand(pacticipant: pacticipant_name, version: version_number)
73
+ .get
74
+ .assert_success!(404 => "#{pacticipant_name} version #{version_number} not found")
75
+ end
76
+
77
+ def record_deployment_request_body
78
+ { replacedPreviousDeployedVersion: replaced_previous_deployed_version }
79
+ end
80
+
81
+ def result_message
82
+ if output == "text"
83
+ message = "Recorded deployment of #{pacticipant_name} version #{version_number} to #{environment_name} in #{pact_broker_name}."
84
+ suffix = replaced_previous_deployed_version ? " Marked previous deployed version as undeployed." : ""
85
+ message + suffix
86
+ elsif output == "json"
87
+ deployed_version_resource.response.raw_body
88
+ else
89
+ ""
90
+ end
91
+ end
92
+
93
+ def pact_broker_name
94
+ is_pactflow? ? "Pactflow" : "the Pact Broker"
95
+ end
96
+
97
+ def is_pactflow?
98
+ deployed_version_resource.response.headers.keys.any?{ | header_name | header_name.downcase.include?("pactflow") }
99
+ end
100
+
101
+ def check_if_command_supported
102
+ unless index_resource.can?("pb:environments")
103
+ raise PactBroker::Client::Error.new(NOT_SUPPORTED_MESSAGE)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,125 @@
1
+ require 'pact_broker/client/hal_client_methods'
2
+ require 'pact_broker/client/error'
3
+ require 'pact_broker/client/command_result'
4
+
5
+ module PactBroker
6
+ module Client
7
+ class Versions
8
+ class RecordUndeployment
9
+ include PactBroker::Client::HalClientMethods
10
+
11
+ NOT_SUPPORTED_MESSAGE = "This version of the Pact Broker does not support recording undeployments. Please upgrade to version 2.80.0 or later."
12
+
13
+ def self.call(params, pact_broker_base_url, pact_broker_client_options)
14
+ new(params, pact_broker_base_url, pact_broker_client_options).call
15
+ end
16
+
17
+ def initialize(params, pact_broker_base_url, pact_broker_client_options)
18
+ @pact_broker_base_url = pact_broker_base_url
19
+ @pacticipant_name = params.fetch(:pacticipant_name)
20
+ @version_number = params.fetch(:version_number)
21
+ @environment_name = params.fetch(:environment_name)
22
+ @output = params.fetch(:output)
23
+ @pact_broker_client_options = pact_broker_client_options
24
+ end
25
+
26
+ def call
27
+ check_environment_exists
28
+ # record_undeployment
29
+
30
+ PactBroker::Client::CommandResult.new(true, result_message)
31
+ rescue PactBroker::Client::Error => e
32
+ PactBroker::Client::CommandResult.new(false, e.message)
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :pact_broker_base_url, :pact_broker_client_options
38
+ attr_reader :pacticipant_name, :version_number, :environment_name, :replaced_previous_deployed_version, :output
39
+ attr_reader :deployed_version_resource
40
+
41
+ def check_environment_exists
42
+ deployed_versions = currently_deployed_versions_for_pacticipant
43
+ .get(version: version_number)
44
+ .embedded_entities("deployedVersions")
45
+ deployed_versions
46
+ end
47
+
48
+ def currently_deployed_versions_for_pacticipant
49
+ @currently_deployed_versions_for_pacticipant ||= index_resource
50
+ ._link!("pb:environments")
51
+ .get!(name: environment_name)
52
+ .embedded_entities("environments")
53
+ .tap { |it| raise "Environment not found '#{environment_name}'" if it.empty? }
54
+ .first
55
+ ._link!("pb:currently-deployed-versions-for-pacticipant")
56
+ .expand(pacticipant: pacticipant_name)
57
+ end
58
+
59
+ def currently_deployed_versions_for_pacticipant_version
60
+ @currently_deployed_versions ||= currently_deployed_versions_for_pacticipant
61
+ .get(version: version_number)
62
+ .embedded_entities("deployedVersions")
63
+ end
64
+
65
+ # def record_deployment
66
+ # @deployed_version_resource =
67
+ # get_record_deployment_relation
68
+ # .post(record_deployment_request_body)
69
+ # .assert_success!
70
+ # end
71
+
72
+ # def get_record_deployment_relation
73
+ # record_deployment_links = get_pacticipant_version._links!("pb:record-deployment")
74
+ # link_for_environment = record_deployment_links.find(environment_name)
75
+ # if link_for_environment
76
+ # link_for_environment
77
+ # else
78
+ # check_environment_exists
79
+ # # Force the exception to be raised
80
+ # record_deployment_links.find!(environment_name, "Environment '#{environment_name}' is not an available option for recording a deployment of #{pacticipant_name}.")
81
+ # end
82
+ # end
83
+
84
+ # def get_pacticipant_version
85
+ # index_resource
86
+ # ._link!("pb:pacticipant-version")
87
+ # .expand(pacticipant: pacticipant_name, version: version_number)
88
+ # .get
89
+ # .assert_success!(404 => "#{pacticipant_name} version #{version_number} not found")
90
+ # end
91
+
92
+ # def record_deployment_request_body
93
+ # { replacedPreviousDeployedVersion: replaced_previous_deployed_version }
94
+ # end
95
+
96
+ def result_message
97
+ ""
98
+ # if output == "text"
99
+ # message = "Recorded deployment of #{pacticipant_name} version #{version_number} to #{environment_name} in #{pact_broker_name}."
100
+ # suffix = replaced_previous_deployed_version ? " Marked previous deployed version as undeployed." : ""
101
+ # message + suffix
102
+ # elsif output == "json"
103
+ # deployed_version_resource.response.raw_body
104
+ # else
105
+ # ""
106
+ # end
107
+ end
108
+
109
+ def pact_broker_name
110
+ is_pactflow? ? "Pactflow" : "the Pact Broker"
111
+ end
112
+
113
+ def is_pactflow?
114
+ deployed_version_resource.response.headers.keys.any?{ | header_name | header_name.downcase.include?("pactflow") }
115
+ end
116
+
117
+ def check_if_command_supported
118
+ unless index_resource.can?("pb:environments")
119
+ raise PactBroker::Client::Error.new(NOT_SUPPORTED_MESSAGE)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -26,10 +26,11 @@ Gem::Specification.new do |gem|
26
26
  gem.add_runtime_dependency 'table_print', '~> 1.5'
27
27
  gem.add_runtime_dependency 'thor', '>= 0.20', '< 2.0'
28
28
  gem.add_runtime_dependency 'rake', '~> 13.0' #For FileList
29
+ gem.add_runtime_dependency 'dig_rb', '~> 1.0'
29
30
 
30
31
  gem.add_development_dependency 'fakefs', '~> 0.4'
31
32
  gem.add_development_dependency 'webmock', '~> 3.0'
32
33
  gem.add_development_dependency 'conventional-changelog', '~>1.3'
33
34
  gem.add_development_dependency 'pact', '~> 1.16'
34
- gem.add_development_dependency 'pact-support', '1.15.0'
35
+ gem.add_development_dependency 'pact-support', '~> 1.16'
35
36
  end
@@ -1 +1,7 @@
1
- bundle exec bin/pact-broker publish spec/pacts/pact_broker_client-pact_broker.json --consumer-app-version 1.2.3 --broker-base-url http://localhost:9292 --tag-with-git-branch --broker-username localhost --broker-password localhost
1
+ bundle exec bin/pact-broker publish spec/pacts/pact_broker_client-pact_broker.json \
2
+ --consumer-app-version 1.2.7 \
3
+ --broker-base-url http://localhost:9292 \
4
+ --broker-username localhost --broker-password localhost \
5
+ --auto-detect-branch \
6
+ --build-url http://mybuild
7
+
@@ -0,0 +1,4 @@
1
+ PACT_BROKER_FEATURES=deployments bundle exec bin/pact-broker record-deployment \
2
+ --pacticipant Foo --version 1.0.0 --environment prod --broker-base-url http://localhost:9292
3
+
4
+
@@ -19,7 +19,7 @@ output=$(curl -v -X POST https://api.github.com/repos/${repository_slug}/dispatc
19
19
  -H "Authorization: Bearer $GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES" \
20
20
  -d "{\"event_type\": \"release-triggered\", \"client_payload\": {\"increment\": ${increment}}}" 2>&1)
21
21
 
22
- if ! echo "${output}" | grep "HTTP\/1.1 204" > /dev/null; then
22
+ if ! echo "${output}" | grep "HTTP\/.* 204" > /dev/null; then
23
23
  echo "$output" | sed "s/${GITHUB_ACCESS_TOKEN_FOR_PF_RELEASES}/********/g"
24
24
  echo "Failed to trigger release"
25
25
  exit 1
@@ -1,4 +1,6 @@
1
1
  require 'pact_broker/client/cli/broker'
2
+ require 'pact_broker/client/cli/version_selector_options_parser'
3
+ require 'pact_broker/client/can_i_deploy'
2
4
 
3
5
  module PactBroker
4
6
  module Client
@@ -35,7 +37,7 @@ module PactBroker
35
37
  end
36
38
 
37
39
  it "invokes the CanIDeploy service" do
38
- expect(CanIDeploy).to receive(:call).with('http://pact-broker', version_selectors, {to_tag: nil, limit: 1000}, {output: 'table', retry_while_unknown: 1, retry_interval: 2}, {verbose: 'verbose'})
40
+ expect(CanIDeploy).to receive(:call).with('http://pact-broker', version_selectors, {to_tag: nil, to_environment: nil, limit: 1000}, {output: 'table', retry_while_unknown: 1, retry_interval: 2}, {verbose: 'verbose'})
39
41
  invoke_can_i_deploy
40
42
  end
41
43
 
@@ -53,7 +55,18 @@ module PactBroker
53
55
  end
54
56
 
55
57
  it "passes the value as the matrix options" do
56
- expect(CanIDeploy).to receive(:call).with(anything, anything, {to_tag: 'prod', limit: 1000}, anything, anything)
58
+ expect(CanIDeploy).to receive(:call).with(anything, anything, {to_tag: 'prod', to_environment: nil, limit: 1000}, anything, anything)
59
+ invoke_can_i_deploy
60
+ end
61
+ end
62
+
63
+ context "with --to-environment" do
64
+ before do
65
+ subject.options.to_environment = 'prod'
66
+ end
67
+
68
+ it "passes the value as the matrix options" do
69
+ expect(CanIDeploy).to receive(:call).with(anything, anything, {to_tag: nil, to_environment: 'prod', limit: 1000}, anything, anything)
57
70
  invoke_can_i_deploy
58
71
  end
59
72
  end
@@ -100,13 +113,45 @@ module PactBroker
100
113
  end
101
114
 
102
115
  it "exits with code 1" do
103
- exited_with_error = false
116
+ exited_explicitly = false
117
+ exited_explicitlyerror = nil
104
118
  begin
105
119
  invoke_can_i_deploy
106
- rescue SystemExit
107
- exited_with_error = true
120
+ rescue SystemExit => e
121
+ exited_explicitly = true
122
+ error = e
123
+ end
124
+ expect(exited_explicitly).to be true
125
+ expect(error.status).to be 1
126
+ end
127
+
128
+ context "when an exit status is specified" do
129
+ before do
130
+ allow(ENV).to receive(:fetch).and_call_original
131
+ allow(ENV).to receive(:fetch).with('PACT_BROKER_CAN_I_DEPLOY_EXIT_STATUS_BETA', '').and_return("0")
132
+ end
133
+
134
+ it "exits with the specified code" do
135
+ exited_explicitly = false
136
+ error = nil
137
+ begin
138
+ invoke_can_i_deploy
139
+ rescue SystemExit => e
140
+ exited_explicitly = true
141
+ error = e
142
+ end
143
+ expect(exited_explicitly).to be true
144
+ expect(error.status).to be 0
145
+ end
146
+
147
+ it "prints the configured exit code" do
148
+ expect($stderr).to receive(:puts).with("Exiting can-i-deploy with configured exit code 0")
149
+ expect($stdout).to receive(:puts).with(message)
150
+ begin
151
+ invoke_can_i_deploy
152
+ rescue SystemExit
153
+ end
108
154
  end
109
- expect(exited_with_error).to be true
110
155
  end
111
156
  end
112
157
  end