pact_broker-client 1.35.0 → 1.36.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1bf1176c39519652e60c6aab383a941a2dd5a1c8e968b746741a290e68c736e9
4
- data.tar.gz: 04b1f3aa9f25b353e61eb558d393d108750cd97b4645fe81313b1d04dca33ba5
3
+ metadata.gz: d55a0e281744620059c94153234610bf5368b178eff81765250a1b31b00ef124
4
+ data.tar.gz: 42edd3c93f27dc59e498e52f36628158ac79bb8d7aa72a4b469ac69ec5734e00
5
5
  SHA512:
6
- metadata.gz: cbb4fe27ce2979d3daea2c597ca7509b6d4136ac53d139a738fd672f30d114fcce23ce4f3ba3c108aef13ec88b9793715bf57ec05a2fda6255dfcd7ed9c99875
7
- data.tar.gz: 443c3e2e5fb75bcbfa3850ce1498f859c45872145f813c50b260a9a7d28a32f5aa7618c1f55b0c798b34975ec7b35d7e44b0937c6bd2575dea1b86356eb8ca5b
6
+ metadata.gz: af0ca16aa9d4f2732ac72b42a102d4567d5a0541510967bfa38a4b2d3302f6d40e17f81af6c444cf93c7710edc583da4715f39aebdb736e471d7cc26e67503d6
7
+ data.tar.gz: e276cb64d985c93dcb55185c6ed9b61fc8c392a90d28cf7fc4b49246f986503005d111c8f0802166364f316bf3bde100d2d71a36f533d899e32c00ff76681542
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ <a name="v1.36.0"></a>
2
+ ### v1.36.0 (2021-02-21)
3
+
4
+ #### Features
5
+
6
+ * **can-i-deploy**
7
+ * add --to-environment option ([05ae44c](/../../commit/05ae44c))
8
+
9
+ * support version branch and build URL when publishing pacts ([a75f7df](/../../commit/a75f7df))
10
+
1
11
  <a name="v1.35.0"></a>
2
12
  ### v1.35.0 (2021-01-21)
3
13
 
@@ -28,6 +28,8 @@
28
28
 
29
29
  * [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:latest-version_relation_exists_in_the_index_resource) given the pb:latest-version relation exists in the index resource
30
30
 
31
+ * [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:pacticipant-version_relation_exists_in_the_index_resource) given the pb:pacticipant-version relation exists in the index resource
32
+
31
33
  * [A request for the index resource with the webhook relation](#a_request_for_the_index_resource_with_the_webhook_relation)
32
34
 
33
35
  * [A request for the list of the latest pacts from all consumers for the Pricing Service'](#a_request_for_the_list_of_the_latest_pacts_from_all_consumers_for_the_Pricing_Service&#39;_given_a_latest_pact_between_Condor_and_the_Pricing_Service_exists) given a latest pact between Condor and the Pricing Service exists
@@ -42,6 +44,10 @@
42
44
 
43
45
  * [A request to create a pacticipant](#a_request_to_create_a_pacticipant)
44
46
 
47
+ * [A request to create a pacticipant version](#a_request_to_create_a_pacticipant_version_given_version_26f353580936ad3b9baddb17b00e84f33c69e7cb_of_pacticipant_Foo_does_exist) given version 26f353580936ad3b9baddb17b00e84f33c69e7cb of pacticipant Foo does exist
48
+
49
+ * [A request to create a pacticipant version](#a_request_to_create_a_pacticipant_version_given_version_26f353580936ad3b9baddb17b00e84f33c69e7cb_of_pacticipant_Foo_does_not_exist) given version 26f353580936ad3b9baddb17b00e84f33c69e7cb of pacticipant Foo does not exist
50
+
45
51
  * [A request to create a webhook for a consumer and provider](#a_request_to_create_a_webhook_for_a_consumer_and_provider_given_&#39;Condor&#39;_does_not_exist_in_the_pact-broker) given 'Condor' does not exist in the pact-broker
46
52
 
47
53
  * [A request to create a webhook with a JSON body and a uuid](#a_request_to_create_a_webhook_with_a_JSON_body_and_a_uuid_given_the_&#39;Pricing_Service&#39;_and_&#39;Condor&#39;_already_exist_in_the_pact-broker) given the 'Pricing Service' and 'Condor' already exist in the pact-broker
@@ -646,6 +652,33 @@ Pact Broker will respond with:
646
652
  }
647
653
  }
648
654
  ```
655
+ <a name="a_request_for_the_index_resource_given_the_pb:pacticipant-version_relation_exists_in_the_index_resource"></a>
656
+ Given **the pb:pacticipant-version relation exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client, with
657
+ ```json
658
+ {
659
+ "method": "get",
660
+ "path": "/",
661
+ "headers": {
662
+ "Accept": "application/hal+json"
663
+ }
664
+ }
665
+ ```
666
+ Pact Broker will respond with:
667
+ ```json
668
+ {
669
+ "status": 200,
670
+ "headers": {
671
+ "Content-Type": "application/hal+json;charset=utf-8"
672
+ },
673
+ "body": {
674
+ "_links": {
675
+ "pb:pacticipant-version": {
676
+ "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-INDEX-PB-PACTICIPANT-VERSION-{pacticipant}-{version}"
677
+ }
678
+ }
679
+ }
680
+ }
681
+ ```
649
682
  <a name="a_request_for_the_index_resource_with_the_webhook_relation"></a>
650
683
  Upon receiving **a request for the index resource with the webhook relation** from Pact Broker Client, with
651
684
  ```json
@@ -898,6 +931,76 @@ Pact Broker will respond with:
898
931
  }
899
932
  }
900
933
  ```
934
+ <a name="a_request_to_create_a_pacticipant_version_given_version_26f353580936ad3b9baddb17b00e84f33c69e7cb_of_pacticipant_Foo_does_exist"></a>
935
+ Given **version 26f353580936ad3b9baddb17b00e84f33c69e7cb of pacticipant Foo does exist**, upon receiving **a request to create a pacticipant version** from Pact Broker Client, with
936
+ ```json
937
+ {
938
+ "method": "put",
939
+ "path": "/HAL-REL-PLACEHOLDER-INDEX-PB-PACTICIPANT-VERSION-Foo-26f353580936ad3b9baddb17b00e84f33c69e7cb",
940
+ "headers": {
941
+ "Content-Type": "application/json",
942
+ "Accept": "application/hal+json"
943
+ },
944
+ "body": {
945
+ "branch": "main",
946
+ "buildUrl": "http://my-ci/builds/1"
947
+ }
948
+ }
949
+ ```
950
+ Pact Broker will respond with:
951
+ ```json
952
+ {
953
+ "status": 200,
954
+ "headers": {
955
+ "Content-Type": "application/hal+json;charset=utf-8"
956
+ },
957
+ "body": {
958
+ "number": "26f353580936ad3b9baddb17b00e84f33c69e7cb",
959
+ "branch": "main",
960
+ "buildUrl": "http://my-ci/builds/1",
961
+ "_links": {
962
+ "self": {
963
+ "href": "http://localhost:1234/some-url"
964
+ }
965
+ }
966
+ }
967
+ }
968
+ ```
969
+ <a name="a_request_to_create_a_pacticipant_version_given_version_26f353580936ad3b9baddb17b00e84f33c69e7cb_of_pacticipant_Foo_does_not_exist"></a>
970
+ Given **version 26f353580936ad3b9baddb17b00e84f33c69e7cb of pacticipant Foo does not exist**, upon receiving **a request to create a pacticipant version** from Pact Broker Client, with
971
+ ```json
972
+ {
973
+ "method": "put",
974
+ "path": "/HAL-REL-PLACEHOLDER-INDEX-PB-PACTICIPANT-VERSION-Foo-26f353580936ad3b9baddb17b00e84f33c69e7cb",
975
+ "headers": {
976
+ "Content-Type": "application/json",
977
+ "Accept": "application/hal+json"
978
+ },
979
+ "body": {
980
+ "branch": "main",
981
+ "buildUrl": "http://my-ci/builds/1"
982
+ }
983
+ }
984
+ ```
985
+ Pact Broker will respond with:
986
+ ```json
987
+ {
988
+ "status": 201,
989
+ "headers": {
990
+ "Content-Type": "application/hal+json;charset=utf-8"
991
+ },
992
+ "body": {
993
+ "number": "26f353580936ad3b9baddb17b00e84f33c69e7cb",
994
+ "branch": "main",
995
+ "buildUrl": "http://my-ci/builds/1",
996
+ "_links": {
997
+ "self": {
998
+ "href": "http://localhost:1234/some-url"
999
+ }
1000
+ }
1001
+ }
1002
+ }
1003
+ ```
901
1004
  <a name="a_request_to_create_a_webhook_for_a_consumer_and_provider_given_&#39;Condor&#39;_does_not_exist_in_the_pact-broker"></a>
902
1005
  Given **'Condor' does not exist in the pact-broker**, upon receiving **a request to create a webhook for a consumer and provider** from Pact Broker Client, with
903
1006
  ```json
@@ -18,6 +18,7 @@ module PactBroker
18
18
  method_option :version, required: false, aliases: "-e", desc: "The pacticipant version. Must be entered after the --pacticipant that it relates to."
19
19
  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."
20
20
  method_option :to, required: false, banner: 'TAG', desc: "This is too hard to explain in a short sentence. Look at the examples.", default: nil
21
+ method_option :to_environment, required: false, banner: 'ENVIRONMENT', desc: "The environment into which the pacticipant(s) are to be deployed", default: nil, hide: true
21
22
  method_option :broker_base_url, required: true, aliases: "-b", desc: "The base URL of the Pact Broker"
22
23
  method_option :broker_username, aliases: "-u", desc: "Pact Broker basic auth username"
23
24
  method_option :broker_password, aliases: "-p", desc: "Pact Broker basic auth password"
@@ -37,7 +38,7 @@ module PactBroker
37
38
  selectors = VersionSelectorOptionsParser.call(ARGV)
38
39
  validate_can_i_deploy_selectors(selectors)
39
40
  can_i_deploy_options = { output: options.output, retry_while_unknown: options.retry_while_unknown, retry_interval: options.retry_interval }
40
- result = CanIDeploy.call(options.broker_base_url, selectors, {to_tag: options.to, limit: options.limit}, can_i_deploy_options, pact_broker_client_options)
41
+ result = CanIDeploy.call(options.broker_base_url, selectors, { to_tag: options.to, to_environment: options.to_environment, limit: options.limit }, can_i_deploy_options, pact_broker_client_options)
41
42
  $stdout.puts result.message
42
43
  exit(1) unless result.success
43
44
  end
@@ -48,8 +49,11 @@ module PactBroker
48
49
  method_option :broker_username, aliases: "-u", desc: "Pact Broker basic auth username"
49
50
  method_option :broker_password, aliases: "-p", desc: "Pact Broker basic auth password"
50
51
  method_option :broker_token, aliases: "-k", desc: "Pact Broker bearer token"
52
+ method_option :branch, aliases: "-h", desc: "Repository branch of the consumer version"
53
+ method_option :auto_detect_version_properties, hidden: true, type: :boolean, default: false, desc: "Automatically detect the repository branch from known CI environment variables or git CLI."
51
54
  method_option :tag, aliases: "-t", type: :array, banner: "TAG", desc: "Tag name for consumer version. Can be specified multiple times."
52
55
  method_option :tag_with_git_branch, aliases: "-g", type: :boolean, default: false, required: false, desc: "Tag consumer version with the name of the current git branch. Default: false"
56
+ method_option :build_url, desc: "The build URL that created the pact"
53
57
  method_option :merge, type: :boolean, default: false, require: false, desc: "If a pact already exists for this consumer version and provider, merge the contents. Useful when running Pact tests concurrently on different build nodes."
54
58
  method_option :verbose, aliases: "-v", type: :boolean, default: false, required: false, desc: "Verbose output. Default: false"
55
59
 
@@ -211,12 +215,18 @@ module PactBroker
211
215
  def publish_pacts pact_files
212
216
  require 'pact_broker/client/publish_pacts'
213
217
  write_options = options[:merge] ? { write: :merge } : {}
218
+ consumer_version_params = {
219
+ number: options.consumer_app_version,
220
+ branch: branch,
221
+ tags: tags,
222
+ build_url: options.build_url,
223
+ version_required: (!!options.branch || !!options.build_url || explict_auto_detect_version_properties)
224
+ }.compact
214
225
 
215
226
  PactBroker::Client::PublishPacts.call(
216
227
  options.broker_base_url,
217
228
  file_list(pact_files),
218
- options.consumer_app_version,
219
- tags,
229
+ consumer_version_params,
220
230
  pact_broker_client_options.merge(write_options)
221
231
  )
222
232
  end
@@ -238,10 +248,24 @@ module PactBroker
238
248
  require 'pact_broker/client/git'
239
249
 
240
250
  t = [*options.tag]
241
- t << PactBroker::Client::Git.branch if options.tag_with_git_branch
251
+ t << PactBroker::Client::Git.branch(raise_error: true) if options.tag_with_git_branch
242
252
  t.compact.uniq
243
253
  end
244
254
 
255
+ def branch
256
+ require 'pact_broker/client/git'
257
+
258
+ if options.branch.nil? && options.auto_detect_version_properties
259
+ PactBroker::Client::Git.branch(raise_error: explict_auto_detect_version_properties)
260
+ else
261
+ options.branch
262
+ end
263
+ end
264
+
265
+ def explict_auto_detect_version_properties
266
+ @explict_auto_detect_version_properties ||= ARGV.include?("--auto-detect-version-properties")
267
+ end
268
+
245
269
  def pact_broker_client_options
246
270
  client_options = { verbose: options.verbose }
247
271
  client_options[:token] = options.broker_token if options.broker_token
@@ -19,17 +19,27 @@ Using a specific version is the easiest way to ensure you get an accurate respon
19
19
 
20
20
  #### Recommended usage - allowing the Pact Broker to automatically determine the dependencies
21
21
 
22
- Prerequisite: if you would like the Pact Broker to calculate the dependencies for you when you want to deploy an application into a given environment, you will need to let the Broker know which version of each application is in that environment. To do this, the relevant application version resource in the Broker will need to be "tagged" with the name of the environment during the deployment process:
22
+ Prerequisite: if you would like the Pact Broker to calculate the dependencies for you when you want to deploy an application into a given environment, you will need to let the Broker know which version of each application is in that environment.
23
+
24
+ How you do this depends on the version of the Pact Broker you are running.
25
+
26
+ If you are using a Broker version where deployment versions are supported, then you would notify the Broker of the deployment of this application version like so:
27
+
28
+ $ pact-broker record-deployment --pacticipant Foo --version 173153ae0 --environment test
29
+
30
+ This assumes that you have already set up an environment named "test" in the Broker.
31
+
32
+ If you are using a Broker version that does not support deployment environments, then you will need to use tags to notify the broker of the deployment of this application version, like so:
23
33
 
24
34
  $ pact-broker create-version-tag --pacticipant Foo --version 173153ae0 --tag test
25
35
 
26
- This allows you to use the following simple command to find out if you are safe to deploy:
36
+ Once you have configured your build to notify the Pact Broker of the successful deployment using either method describe above, you can use the following simple command to find out if you are safe to deploy (use either `--to` or `--to-environment` as supported):
27
37
 
28
- $ pact-broker can-i-deploy --pacticipant PACTICIPANT --version VERSION \
29
- --to ENVIRONMENT \
38
+ $ pact-broker can-i-deploy --pacticipant PACTICIPANT --version VERSION
39
+ [--to-environment ENVIRONMENT | --to ENVIRONMENT_TAG ]
30
40
  --broker-base-url BROKER_BASE_URL
31
41
 
32
- If the `--to` tag is omitted, then the query will return the compatiblity with the overall latest version of each of the other applications.
42
+ If the `--to` or `--to-environment` options are omitted, then the query will return the compatiblity with the overall latest version of each of the other applications.
33
43
 
34
44
  Examples:
35
45
 
@@ -38,7 +48,7 @@ Can I deploy version 173153ae0 of application Foo to the test environment?
38
48
 
39
49
 
40
50
  $ pact-broker can-i-deploy --pacticipant Foo --version 173153ae0 \
41
- --to test \
51
+ --to-environment test \
42
52
  --broker-base-url https://my-pact-broker
43
53
 
44
54
 
@@ -56,21 +66,20 @@ Can I deploy the latest version of the application Foo that has the tag "test" t
56
66
  --broker-base-url https://my-pact-broker
57
67
 
58
68
 
59
-
60
69
  #### Alternate usage - specifying dependencies explicitly
61
70
 
62
71
  If you are unable to use tags, or there is some other limitation that stops you from using the recommended approach, you can specify one or more of the dependencies explictly. You must also do this if you want to use the `--all TAG` option for any of the pacticipants.
63
72
 
64
73
  You can specify as many application versions as you like, and you can even specify multiple versions of the same application (repeat the `--pacticipant` name and supply a different version.)
65
74
 
66
- You can use explictly declared dependencies with or without the `--to ENVIRONMENT`. For example, if you declare two (or more) application versions with no `--to ENVIRONMENT`, then only the applications you specify will be taken into account when determining if it is safe to deploy. If you declare two (or more) application versions _as well as_ a `--to ENVIRONMENT`, then the Pact Broker will work out what integrations your declared applications will have in that environment when determining if it safe to deploy. When using this script for a production release, and you are using tags, it is always the most future-proof option to use the `--to` if possible, as it will catch any newly added consumers or providers.
75
+ You can use explictly declared dependencies with or without the `--to ENVIRONMENT_TAG`. For example, if you declare two (or more) application versions with no `--to ENVIRONMENT_TAG`, then only the applications you specify will be taken into account when determining if it is safe to deploy. If you declare two (or more) application versions _as well as_ a `--to ENVIRONMENT`, then the Pact Broker will work out what integrations your declared applications will have in that environment when determining if it safe to deploy. When using this script for a production release, and you are using tags, it is always the most future-proof option to use the `--to` if possible, as it will catch any newly added consumers or providers.
67
76
 
68
77
  If you are finding that your dependencies are not being automatically included when you supply multiple pacticipant versions, please upgrade to the latest version of the Pact Broker, as this is a more recently added feature.
69
78
 
70
79
 
71
80
  $ pact-broker can-i-deploy --pacticipant PACTICIPANT_1 [--version VERSION_1 | --latest [TAG_1] | --all TAG_1] \
72
81
  --pacticipant PACTICIPANT_2 [--version VERSION_2 | --latest [TAG_2] | --all TAG_2] \
73
- [--to ENVIRONMENT] \
82
+ [--to-environment ENVIRONMENT | --to ENVIRONMENT_TAG] \
74
83
  --broker-base-url BROKER_BASE_URL
75
84
 
76
85
  Examples:
@@ -16,19 +16,23 @@ BITBUCKET_BRANCH BITBUCKET_COMMIT https://confluence.atlassian.com/bitbucket/var
16
16
  =end
17
17
 
18
18
  # Keep in sync with pact-provider-verifier/lib/pact/provider_verifier/git.rb
19
+
20
+ # `git name-rev --name-only HEAD` provides "tags/v1.35.0^0"
19
21
  module PactBroker
20
22
  module Client
21
23
  module Git
22
- COMMAND = 'git name-rev --name-only HEAD'.freeze
24
+ COMMAND = 'git rev-parse --abbrev-ref HEAD'.freeze
23
25
  BRANCH_ENV_VAR_NAMES = %w{BUILDKITE_BRANCH CIRCLE_BRANCH TRAVIS_BRANCH GIT_BRANCH GIT_LOCAL_BRANCH APPVEYOR_REPO_BRANCH CI_COMMIT_REF_NAME BITBUCKET_BRANCH}.freeze
24
26
  COMMIT_ENV_VAR_NAMES = %w{BUILDKITE_COMMIT CIRCLE_SHA1 TRAVIS_COMMIT GIT_COMMIT APPVEYOR_REPO_COMMIT CI_COMMIT_ID BITBUCKET_COMMIT}
25
27
 
28
+ BUILD_URL_ENV_VAR_NAMES = %w{BUILDKITE_BUILD_URL CIRCLE_BUILD_URL TRAVIS_BUILD_WEB_URL BUILD_URL }
29
+
26
30
  def self.commit
27
31
  find_commit_from_env_vars
28
32
  end
29
33
 
30
- def self.branch
31
- find_branch_from_env_vars || branch_from_git_command
34
+ def self.branch(options)
35
+ find_branch_from_known_env_vars || find_branch_from_env_var_ending_with_branch || branch_from_git_command(options[:raise_error])
32
36
  end
33
37
 
34
38
  # private
@@ -37,10 +41,21 @@ module PactBroker
37
41
  COMMIT_ENV_VAR_NAMES.collect { |env_var_name| value_from_env_var(env_var_name) }.compact.first
38
42
  end
39
43
 
40
- def self.find_branch_from_env_vars
44
+ def self.find_branch_from_known_env_vars
41
45
  BRANCH_ENV_VAR_NAMES.collect { |env_var_name| value_from_env_var(env_var_name) }.compact.first
42
46
  end
43
47
 
48
+ def self.find_branch_from_env_var_ending_with_branch
49
+ values = ENV.keys
50
+ .select{ |env_var_name| env_var_name.end_with?("_BRANCH") }
51
+ .collect{ |env_var_name| value_from_env_var(env_var_name) }.compact
52
+ if values.size == 1
53
+ values.first
54
+ else
55
+ nil
56
+ end
57
+ end
58
+
44
59
  def self.value_from_env_var(env_var_name)
45
60
  val = ENV[env_var_name]
46
61
  if val && val.strip.size > 0
@@ -50,24 +65,10 @@ module PactBroker
50
65
  end
51
66
  end
52
67
 
53
- def self.branch_from_git_command
54
- branch_names = nil
55
- begin
56
- branch_names = execute_git_command
57
- .split("\n")
58
- .collect(&:strip)
59
- .reject(&:empty?)
60
- .collect(&:split)
61
- .collect(&:first)
62
- .collect{ |line| line.gsub(/^origin\//, '') }
63
- .reject{ |line| line == "HEAD" }
64
-
65
- rescue StandardError => e
66
- raise PactBroker::Client::Error, "Could not determine current git branch using command `#{COMMAND}`. #{e.class} #{e.message}"
67
- end
68
-
69
- validate_branch_names(branch_names)
70
- branch_names[0]
68
+ def self.branch_from_git_command(raise_error)
69
+ branch_names = execute_and_parse_command(raise_error)
70
+ validate_branch_names(branch_names) if raise_error
71
+ branch_names.size == 1 ? branch_names[0] : nil
71
72
  end
72
73
 
73
74
  def self.validate_branch_names(branch_names)
@@ -83,6 +84,23 @@ module PactBroker
83
84
  def self.execute_git_command
84
85
  `#{COMMAND}`
85
86
  end
87
+
88
+ def self.execute_and_parse_command(raise_error)
89
+ execute_git_command
90
+ .split("\n")
91
+ .collect(&:strip)
92
+ .reject(&:empty?)
93
+ .collect(&:split)
94
+ .collect(&:first)
95
+ .collect{ |line| line.gsub(/^origin\//, '') }
96
+ .reject{ |line| line == "HEAD" }
97
+ rescue StandardError => e
98
+ if raise_error
99
+ raise PactBroker::Client::Error, "Could not determine current git branch using command `#{COMMAND}`. #{e.class} #{e.message}"
100
+ else
101
+ return []
102
+ end
103
+ end
86
104
  end
87
105
  end
88
106
  end
@@ -53,10 +53,11 @@ module PactBroker
53
53
  opts[:success] = [*options[:success]]
54
54
  end
55
55
  opts[:limit] = options[:limit] if options[:limit]
56
+ opts[:environment] = options[:to_environment] if options[:to_environment]
56
57
  if options[:to_tag]
57
58
  opts[:latest] = 'true'
58
59
  opts[:tag] = options[:to_tag]
59
- elsif selectors.size == 1
60
+ elsif selectors.size == 1 && !options[:to_environment]
60
61
  opts[:latest] = 'true'
61
62
  end
62
63
  opts
@@ -4,39 +4,59 @@ require 'pact_broker/client/retry'
4
4
  require 'pact_broker/client/pact_file'
5
5
  require 'pact_broker/client/pact_hash'
6
6
  require 'pact_broker/client/merge_pacts'
7
+ require 'pact_broker/client/hal_client_methods'
7
8
 
8
9
  module PactBroker
9
10
  module Client
10
11
  class PublishPacts
11
12
 
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
13
+ include HalClientMethods
14
+
15
+ def self.call(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options={})
16
+ new(pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options).call
14
17
  end
15
18
 
16
- def initialize pact_broker_base_url, pact_file_paths, consumer_version, tags, pact_broker_client_options={}
19
+ def initialize pact_broker_base_url, pact_file_paths, consumer_version_params, pact_broker_client_options={}
17
20
  @pact_broker_base_url = pact_broker_base_url
18
21
  @pact_file_paths = pact_file_paths
19
- @consumer_version = consumer_version.respond_to?(:strip) ? consumer_version.strip : consumer_version
20
- @tags = tags ? tags.collect{ |tag| tag.respond_to?(:strip) ? tag.strip : tag } : tags
22
+ @consumer_version_number = consumer_version_params[:number].respond_to?(:strip) ? consumer_version_params[:number].strip : consumer_version_params[:number]
23
+ @branch = consumer_version_params[:branch]
24
+ @build_url = consumer_version_params[:build_url]
25
+ @tags = consumer_version_params[:tags] ? consumer_version_params[:tags].collect{ |tag| tag.respond_to?(:strip) ? tag.strip : tag } : []
26
+ @version_required = consumer_version_params[:version_required]
21
27
  @pact_broker_client_options = pact_broker_client_options
22
28
  end
23
29
 
24
30
  def call
25
31
  validate
26
32
  $stdout.puts("")
27
- result = apply_tags && publish_pacts
33
+ result = create_consumer_versions && apply_tags && publish_pacts
28
34
  $stdout.puts("")
29
35
  result
30
36
  end
31
37
 
32
38
  private
33
39
 
34
- attr_reader :pact_broker_base_url, :pact_file_paths, :consumer_version, :tags, :pact_broker_client_options
40
+ attr_reader :pact_broker_base_url, :pact_file_paths, :consumer_version_number, :branch, :tags, :build_url, :pact_broker_client_options, :version_required
35
41
 
36
42
  def pact_broker_client
37
43
  @pact_broker_client ||= PactBroker::Client::PactBrokerClient.new(base_url: pact_broker_base_url, client_options: pact_broker_client_options)
38
44
  end
39
45
 
46
+ def index_entry_point
47
+ @index_entry_point ||= create_index_entry_point(pact_broker_base_url, pact_broker_client_options)
48
+ end
49
+
50
+ def index_resource
51
+ @index_resource ||= Retry.while_error do
52
+ index_entry_point.get!
53
+ end
54
+ end
55
+
56
+ def can_create_version_with_branch?
57
+ @can_create_version_with_branch ||= index_resource.can?('pb:pacticipant-version')
58
+ end
59
+
40
60
  def merge_on_server?
41
61
  pact_broker_client_options[:write] == :merge
42
62
  end
@@ -70,8 +90,58 @@ module PactBroker
70
90
  end
71
91
  end
72
92
 
93
+ def create_consumer_versions
94
+ if create_versions?
95
+ consumer_names.collect do | consumer_name |
96
+ create_version(index_resource, consumer_name)
97
+ end
98
+ true
99
+ else
100
+ true
101
+ end
102
+ end
103
+
104
+ def create_versions?
105
+ if version_required
106
+ if can_create_version_with_branch?
107
+ true
108
+ else
109
+ raise PactBroker::Client::Error.new("This version of the Pact Broker does not support versions with branches or build URLs. Please upgrade your broker to 2.76.2 or later.")
110
+ end
111
+ elsif (branch || build_url) && can_create_version_with_branch?
112
+ true
113
+ else
114
+ false
115
+ end
116
+ end
117
+
118
+ def create_version(index_resource, consumer_name)
119
+ Retry.while_error do
120
+ version_resource = index_resource._link('pb:pacticipant-version').expand(version: consumer_version_number, pacticipant: consumer_name).put(version_body).assert_success!
121
+ message = if version_resource.response.status == 200
122
+ "Replaced version #{consumer_version_number} of #{consumer_name}"
123
+ else
124
+ "Created version #{consumer_version_number} of #{consumer_name}"
125
+ end
126
+
127
+ message = message + " (branch #{branch})" if branch
128
+ $stdout.puts message
129
+ if version_resource.response.status == 200
130
+ $stdout.puts ::Term::ANSIColor.yellow("Replacing the version resource is not recommended under normal circumstances and may indicate that you have not configured your Pact pipeline correctly (unless you are just re-running a build for a particular commit). For more information see https://docs.pact.io/versioning")
131
+ end
132
+ true
133
+ end
134
+ end
135
+
136
+ def version_body
137
+ {
138
+ branch: branch,
139
+ buildUrl: build_url
140
+ }.compact
141
+ end
142
+
73
143
  def apply_tags
74
- return true if tags.nil? || tags.empty?
144
+ return true if tags.empty?
75
145
  tags.all? do | tag |
76
146
  tag_consumer_version tag
77
147
  end
@@ -81,8 +151,8 @@ module PactBroker
81
151
  versions = pact_broker_client.pacticipants.versions
82
152
  Retry.while_error do
83
153
  consumer_names.collect do | consumer_name |
84
- versions.tag(pacticipant: consumer_name, version: consumer_version, tag: tag)
85
- $stdout.puts "Tagged version #{consumer_version} of #{consumer_name} as #{tag.inspect}"
154
+ versions.tag(pacticipant: consumer_name, version: consumer_version_number, tag: tag)
155
+ $stdout.puts "Tagged version #{consumer_version_number} of #{consumer_name} as #{tag.inspect}"
86
156
  true
87
157
  end
88
158
  end
@@ -94,22 +164,22 @@ module PactBroker
94
164
  def publish_pact_contents(pact)
95
165
  Retry.while_error do
96
166
  pacts = pact_broker_client.pacticipants.versions.pacts
97
- if pacts.version_published?(consumer: pact.consumer_name, provider: pact.provider_name, consumer_version: consumer_version)
167
+ if pacts.version_published?(consumer: pact.consumer_name, provider: pact.provider_name, consumer_version: consumer_version_number)
98
168
  if merge_on_server?
99
169
  $stdout.puts "A pact for this consumer version is already published. Merging contents."
100
170
  else
101
- $stdout.puts ::Term::ANSIColor.yellow("A pact for this consumer version is already published. Overwriting. (Note: Overwriting pacts is not recommended as it can lead to race conditions. Best practice is to provide a unique consumer version number for each publication.)")
171
+ $stdout.puts ::Term::ANSIColor.yellow("A pact for this consumer version is already published. Overwriting. (Note: Overwriting pacts is not recommended as it can lead to race conditions. Best practice is to provide a unique consumer version number for each publication. For more information, see https://docs.pact.io/versioning)")
102
172
  end
103
173
  end
104
174
 
105
- latest_pact_url = pacts.publish(pact_hash: pact, consumer_version: consumer_version)
175
+ latest_pact_url = pacts.publish(pact_hash: pact, consumer_version: consumer_version_number)
106
176
  $stdout.puts "The latest version of this pact can be accessed at the following URL:\n#{latest_pact_url}"
107
177
  true
108
178
  end
109
179
  end
110
180
 
111
181
  def validate
112
- raise PactBroker::Client::Error.new("Please specify the consumer_version") unless (consumer_version && consumer_version.to_s.strip.size > 0)
182
+ raise PactBroker::Client::Error.new("Please specify the consumer_version_number") unless (consumer_version_number && consumer_version_number.to_s.strip.size > 0)
113
183
  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)
114
184
  raise PactBroker::Client::Error.new("No pact files found") unless (pact_file_paths && pact_file_paths.any?)
115
185
  end