pact_broker-client 1.38.0 → 1.40.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +18 -0
  4. data/bin/pact-broker +6 -0
  5. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +100 -0
  6. data/example/scripts/publish-pact.sh +1 -1
  7. data/lib/pact_broker/client/base_client.rb +1 -1
  8. data/lib/pact_broker/client/cli/broker.rb +25 -8
  9. data/lib/pact_broker/client/cli/record_deployment_long_desc.txt +55 -0
  10. data/lib/pact_broker/client/hal/entity.rb +16 -0
  11. data/lib/pact_broker/client/hal/http_client.rb +37 -1
  12. data/lib/pact_broker/client/hal/link.rb +12 -0
  13. data/lib/pact_broker/client/hal/links.rb +15 -0
  14. data/lib/pact_broker/client/hal_client_methods.rb +8 -0
  15. data/lib/pact_broker/client/pacts.rb +0 -1
  16. data/lib/pact_broker/client/publish_pacts.rb +90 -128
  17. data/lib/pact_broker/client/publish_pacts_the_old_way.rb +194 -0
  18. data/lib/pact_broker/client/tasks/publication_task.rb +3 -3
  19. data/lib/pact_broker/client/version.rb +1 -1
  20. data/lib/pact_broker/client/versions/record_deployment.rb +4 -4
  21. data/lib/pact_broker/client/versions/record_undeployment.rb +45 -68
  22. data/script/publish-pact.sh +32 -4
  23. data/script/record-deployment.sh +1 -3
  24. data/script/record-undeployment.sh +4 -0
  25. data/spec/fixtures/foo-bar.json +31 -0
  26. data/spec/lib/pact_broker/client/cli/broker_can_i_deploy_spec.rb +1 -1
  27. data/spec/lib/pact_broker/client/cli/broker_publish_spec.rb +36 -7
  28. data/spec/lib/pact_broker/client/hal/http_client_spec.rb +64 -7
  29. data/spec/lib/pact_broker/client/pacticipants/create_spec.rb +3 -0
  30. data/spec/lib/pact_broker/client/{publish_pacts_spec.rb → publish_pacts_the_old_way_spec.rb} +10 -9
  31. data/spec/lib/pact_broker/client/tasks/publication_task_spec.rb +18 -12
  32. data/spec/lib/pact_broker/client/versions/record_deployment_spec.rb +4 -4
  33. data/spec/pacts/pact_broker_client-pact_broker.json +106 -0
  34. data/spec/service_providers/pact_broker_client_create_version_spec.rb +4 -4
  35. data/spec/service_providers/publish_pacts_spec.rb +115 -0
  36. data/spec/service_providers/record_deployment_spec.rb +5 -5
  37. data/spec/spec_helper.rb +1 -1
  38. metadata +12 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ff434f0cdc2c246e13875eb094bf057cada5e72e6049aace2387a344ba35aa2
4
- data.tar.gz: 508a60bac06506938f425a64eefe63d0fb56ca4b3f32df54bf8d41c9773e6fa5
3
+ metadata.gz: 71ffd6b9522aa3c9ccb2bff18e3fa9b0a723aa480e312be3aa659ff3d7f07e32
4
+ data.tar.gz: 4e6d7034e9bb8b1a85e64afda22fe1ee723842da63c5d67d5586c37b41a4c9a5
5
5
  SHA512:
6
- metadata.gz: 4150fdf1cc5cb1970b60d07f646b151bae9fc56f68422b22a1265d64bb9f99b559ca01d7c688e1fdd047a08fb69c1d0cb28c3cd2be3370285d739cd1a9f36b0d
7
- data.tar.gz: 91ee03c84a4ebec001ef2f2fb3c1dcc47e41a2f55b97e2b23101f99fa58a9114ffa199beb160deabc5f395ba8dc4a01cdd2901d73db2c4263ca444ec37d4b22e
6
+ metadata.gz: 9139f502e90e33eb8f617aac7f49a3ca0ee92f149bc7b81849530956fb861b88425bd63a1fb9f0a7fdc0ff687112dee2c8b297832083146d88266fc5e7c8608a
7
+ data.tar.gz: bff2cfc3be3e1032462afc67d34fcc1afbfdb42ceebd1c79abfe440f7f8f1f6c17e74a07b6cb9c6a0cc83df99d578cb0eb78afa99fab73871a4c23c7be24def9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,37 @@
1
+ <a name="v1.40.0"></a>
2
+ ### v1.40.0 (2021-04-26)
3
+
4
+ #### Features
5
+
6
+ * use the pb:publish-contracts relation and endpoint to publish pacts ([19f1b0b](/../../commit/19f1b0b))
7
+ * update publish pacts command to use new 'all in one' contract publishing endpoint ([50dfb11](/../../commit/50dfb11))
8
+
9
+ <a name="v1.39.0"></a>
10
+ ### v1.39.0 (2021-04-27)
11
+
12
+ #### Features
13
+
14
+ * publish pacts using the "all in one" endpoint (#86) ([3a1ea22](/../../commit/3a1ea22))
15
+ * provide a more helpful error message when the specified pact file does not exist ([29a7962](/../../commit/29a7962))
16
+
17
+ <a name="v1.38.3"></a>
18
+ ### v1.38.3 (2021-04-08)
19
+
20
+ #### Bug Fixes
21
+
22
+ * URL encode parameters for HAL templated URLs ([764a0fa](/../../commit/764a0fa))
23
+
24
+ <a name="v1.38.2"></a>
25
+ ### v1.38.2 (2021-04-01)
26
+
27
+ #### Features
28
+
29
+ * allow SSL verification to be disabled ([eb2125b](/../../commit/eb2125b))
30
+ * automatically retry at the http client level for 50x responses ([a7343f8](/../../commit/a7343f8))
31
+
32
+ <a name="v1.38.1"></a>
33
+ ### v1.38.1 (2021-03-22)
34
+
1
35
  <a name="v1.38.0"></a>
2
36
  ### v1.38.0 (2021-03-22)
3
37
 
data/README.md CHANGED
@@ -309,6 +309,24 @@ Description:
309
309
  the `generate-uuid` command.
310
310
  ```
311
311
 
312
+ ### create-or-update-pacticipant
313
+
314
+ ```
315
+ Usage:
316
+ pact-broker create-or-update-pacticipant --name=NAME -b, --broker-base-url=BROKER_BASE_URL
317
+
318
+ Options:
319
+ --name=NAME # Pacticipant name
320
+ [--repository-url=REPOSITORY_URL] # The repository URL of the pacticipant
321
+ -b, --broker-base-url=BROKER_BASE_URL # The base URL of the Pact Broker
322
+ -u, [--broker-username=BROKER_USERNAME] # Pact Broker basic auth username
323
+ -p, [--broker-password=BROKER_PASSWORD] # Pact Broker basic auth password
324
+ -k, [--broker-token=BROKER_TOKEN] # Pact Broker bearer token
325
+ -v, [--verbose], [--no-verbose] # Verbose output. Default: false
326
+
327
+ Create or update pacticipant by name
328
+ ```
329
+
312
330
  ### describe-version
313
331
 
314
332
  ```
data/bin/pact-broker CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'pact_broker/client/cli/broker'
3
3
 
4
+ if ENV['PACT_BROKER_DISABLE_SSL_VERIFICATION'] == 'true' || ENV['PACT_DISABLE_SSL_VERIFICATION'] == 'true'
5
+ require 'openssl'
6
+ OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
7
+ $stderr.puts "WARN: SSL verification has been disabled by a dodgy hack (reassigning the VERIFY_PEER constant to VERIFY_NONE). You acknowledge that you do this at your own risk!"
8
+ end
9
+
4
10
  PactBroker::Client::CLI::Broker.start
@@ -40,6 +40,8 @@
40
40
 
41
41
  * [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
42
42
 
43
+ * [A request for the index resource](#a_request_for_the_index_resource_given_the_pb:publish-contracts_relations_exists_in_the_index_resource) given the pb:publish-contracts relations exists in the index resource
44
+
43
45
  * [A request for the index resource with the webhook relation](#a_request_for_the_index_resource_with_the_webhook_relation)
44
46
 
45
47
  * [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
@@ -92,6 +94,8 @@
92
94
 
93
95
  * [A request to publish a pact with method put](#a_request_to_publish_a_pact_with_method_put_given_the_&#39;Pricing_Service&#39;_and_&#39;Condor&#39;_already_exist_in_the_pact-broker,_and_Condor_already_has_a_pact_published_for_version_1.3.0) given the 'Pricing Service' and 'Condor' already exist in the pact-broker, and Condor already has a pact published for version 1.3.0
94
96
 
97
+ * [A request to publish contracts](#a_request_to_publish_contracts)
98
+
95
99
  * [A request to record a deployment](#a_request_to_record_a_deployment_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment) given version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment
96
100
 
97
101
  * [A request to register the repository URL of a pacticipant](#a_request_to_register_the_repository_URL_of_a_pacticipant_given_the_&#39;Pricing_Service&#39;_already_exists_in_the_pact-broker) given the 'Pricing Service' already exists in the pact-broker
@@ -832,6 +836,33 @@ Pact Broker will respond with:
832
836
  }
833
837
  }
834
838
  ```
839
+ <a name="a_request_for_the_index_resource_given_the_pb:publish-contracts_relations_exists_in_the_index_resource"></a>
840
+ Given **the pb:publish-contracts relations exists in the index resource**, upon receiving **a request for the index resource** from Pact Broker Client, with
841
+ ```json
842
+ {
843
+ "method": "GET",
844
+ "path": "/",
845
+ "headers": {
846
+ "Accept": "application/hal+json"
847
+ }
848
+ }
849
+ ```
850
+ Pact Broker will respond with:
851
+ ```json
852
+ {
853
+ "status": 200,
854
+ "headers": {
855
+ "Content-Type": "application/hal+json;charset=utf-8"
856
+ },
857
+ "body": {
858
+ "_links": {
859
+ "pb:publish-contracts": {
860
+ "href": "http://localhost:1234/HAL-REL-PLACEHOLDER-PB-PUBLISH-CONTRACTS"
861
+ }
862
+ }
863
+ }
864
+ }
865
+ ```
835
866
  <a name="a_request_for_the_index_resource_with_the_webhook_relation"></a>
836
867
  Upon receiving **a request for the index resource with the webhook relation** from Pact Broker Client, with
837
868
  ```json
@@ -1928,6 +1959,75 @@ Pact Broker will respond with:
1928
1959
  }
1929
1960
  }
1930
1961
  ```
1962
+ <a name="a_request_to_publish_contracts"></a>
1963
+ Upon receiving **a request to publish contracts** from Pact Broker Client, with
1964
+ ```json
1965
+ {
1966
+ "method": "POST",
1967
+ "path": "/HAL-REL-PLACEHOLDER-PB-PUBLISH-CONTRACTS",
1968
+ "headers": {
1969
+ "Content-Type": "application/json",
1970
+ "Accept": "application/hal+json"
1971
+ },
1972
+ "body": {
1973
+ "pacticipantName": "Foo",
1974
+ "pacticipantVersionNumber": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
1975
+ "branch": "main",
1976
+ "tags": [
1977
+ "dev"
1978
+ ],
1979
+ "buildUrl": "http://build",
1980
+ "contracts": [
1981
+ {
1982
+ "consumerName": "Foo",
1983
+ "providerName": "Bar",
1984
+ "specification": "pact",
1985
+ "contentType": "application/json",
1986
+ "content": "eyJjb25zdW1lciI6eyJuYW1lIjoiRm9vIn0sInByb3ZpZGVyIjp7Im5hbWUiOiJCYXIifSwiaW50ZXJhY3Rpb25zIjpbeyJkZXNjcmlwdGlvbiI6ImFuIGV4YW1wbGUgcmVxdWVzdCIsInByb3ZpZGVyU3RhdGUiOiJhIHByb3ZpZGVyIHN0YXRlIiwicmVxdWVzdCI6eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiLyIsImhlYWRlcnMiOnt9fSwicmVzcG9uc2UiOnsic3RhdHVzIjoyMDAsImhlYWRlcnMiOnsiQ29udGVudC1UeXBlIjoiYXBwbGljYXRpb24vaGFsK2pzb24ifX19XSwibWV0YWRhdGEiOnsicGFjdFNwZWNpZmljYXRpb24iOnsidmVyc2lvbiI6IjIuMC4wIn19fQ==",
1987
+ "writeMode": "overwrite"
1988
+ }
1989
+ ]
1990
+ }
1991
+ }
1992
+ ```
1993
+ Pact Broker will respond with:
1994
+ ```json
1995
+ {
1996
+ "status": 200,
1997
+ "headers": {
1998
+ "Content-Type": "application/hal+json;charset=utf-8"
1999
+ },
2000
+ "body": {
2001
+ "_embedded": {
2002
+ "pacticipant": {
2003
+ "name": "Foo"
2004
+ },
2005
+ "version": {
2006
+ "number": "5556b8149bf8bac76bc30f50a8a2dd4c22c85f30",
2007
+ "buildUrl": "http://build"
2008
+ }
2009
+ },
2010
+ "logs": [
2011
+ {
2012
+ "level": "info",
2013
+ "message": "some message"
2014
+ }
2015
+ ],
2016
+ "_links": {
2017
+ "pb:pacticipant-version-tags": [
2018
+ {
2019
+ "name": "dev"
2020
+ }
2021
+ ],
2022
+ "pb:contracts": [
2023
+ {
2024
+ "href": "http://some-pact"
2025
+ }
2026
+ ]
2027
+ }
2028
+ }
2029
+ }
2030
+ ```
1931
2031
  <a name="a_request_to_record_a_deployment_given_version_5556b8149bf8bac76bc30f50a8a2dd4c22c85f30_of_pacticipant_Foo_exists_with_a_test_environment_available_for_deployment"></a>
1932
2032
  Given **version 5556b8149bf8bac76bc30f50a8a2dd4c22c85f30 of pacticipant Foo exists with a test environment available for deployment**, upon receiving **a request to record a deployment** from Pact Broker Client, with
1933
2033
  ```json
@@ -1,3 +1,3 @@
1
1
  # assumes you've set PACT_BROKER_BASE_URL, PACT_BROKER_USERNAME and PACT_BROKER_PASSWORD already
2
2
 
3
- bundle exec bin/pact-broker publish $(dirname "$0")/pact.json --consumer-app-version=1.0.0 --tag master
3
+ bundle exec bin/pact-broker publish $(dirname "$0")/pact.json --consumer-app-version=1.0.0 --tag master --verbose
@@ -119,7 +119,7 @@ module PactBroker
119
119
  if relation
120
120
  url = relation['href']
121
121
  params.each do | (key, value) |
122
- url = url.gsub("{#{key}}", value)
122
+ url = url.gsub("{#{key}}", encode_param(value))
123
123
  end
124
124
  url
125
125
  else
@@ -15,7 +15,7 @@ module PactBroker
15
15
  using PactBroker::Client::HashRefinements
16
16
 
17
17
  desc 'can-i-deploy', ''
18
- long_desc File.read(File.join(File.dirname(__FILE__), 'can_i_deploy_long_desc.txt'))
18
+ long_desc File.read(File.join(__dir__, 'can_i_deploy_long_desc.txt'))
19
19
 
20
20
  method_option :pacticipant, required: true, aliases: "-a", desc: "The pacticipant name. Use once for each pacticipant being checked."
21
21
  method_option :version, required: false, aliases: "-e", desc: "The pacticipant version. Must be entered after the --pacticipant that it relates to."
@@ -39,6 +39,7 @@ module PactBroker
39
39
  can_i_deploy_options = { output: options.output, retry_while_unknown: options.retry_while_unknown, retry_interval: options.retry_interval }
40
40
  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
41
  $stdout.puts result.message
42
+ $stdout.flush
42
43
  exit(can_i_deploy_exit_status) unless result.success
43
44
  end
44
45
 
@@ -50,14 +51,16 @@ module PactBroker
50
51
  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"
51
52
  method_option :build_url, desc: "The build URL that created the pact"
52
53
  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
+ method_option :output, aliases: "-o", desc: "json or text", default: 'text'
53
55
  shared_authentication_options
54
56
 
55
57
  def publish(*pact_files)
56
58
  require 'pact_broker/client/error'
57
59
  validate_credentials
58
60
  validate_pact_files(pact_files)
59
- success = publish_pacts(pact_files)
60
- raise PactPublicationError, "One or more pacts failed to be published" unless success
61
+ result = publish_pacts(pact_files)
62
+ $stdout.puts result.message
63
+ exit(1) unless result.success
61
64
  rescue PactBroker::Client::Error => e
62
65
  raise PactPublicationError, "#{e.class} - #{e.message}"
63
66
  end
@@ -172,10 +175,11 @@ module PactBroker
172
175
 
173
176
  ignored_and_hidden_potential_options_from_environment_variables
174
177
  desc "record-deployment", "Record deployment of a pacticipant version to an environment"
178
+ long_desc File.read(File.join(__dir__, 'record_deployment_long_desc.txt'))
175
179
  method_option :pacticipant, required: true, aliases: "-a", desc: "The name of the pacticipant that was deployed."
176
180
  method_option :version, required: true, aliases: "-e", desc: "The pacticipant version number that was deployed."
177
181
  method_option :environment, required: true, desc: "The name of the environment that the pacticipant version was deployed to."
178
- method_option :replaced_previous_deployed_version, type: :boolean, default: true, required: false, desc: "Whether or not this deployment replaced the previous deployed version. If it did, the previous deployed version of this pacticipant will be marked as undeployed in the Pact Broker."
182
+ method_option :target, default: nil, required: false, desc: "The target of the deployment - a logical identifer that represents where the application version was deployed to. See the usage docs for information on when to use this."
179
183
  method_option :output, aliases: "-o", desc: "json or text", default: 'text'
180
184
  shared_authentication_options
181
185
 
@@ -185,7 +189,7 @@ module PactBroker
185
189
  pacticipant_name: options.pacticipant,
186
190
  version_number: options.version,
187
191
  environment_name: options.environment,
188
- replaced_previous_deployed_version: options.replaced_previous_deployed_version,
192
+ target: options.target,
189
193
  output: options.output
190
194
  }
191
195
  result = PactBroker::Client::Versions::RecordDeployment.call(
@@ -239,7 +243,7 @@ module PactBroker
239
243
  end
240
244
 
241
245
  def can_i_deploy_exit_status
242
- exit_code_string = ENV.fetch('PACT_BROKER_CAN_I_DEPLOY_EXIT_STATUS_BETA', '')
246
+ exit_code_string = ENV.fetch('PACT_BROKER_CAN_I_DEPLOY_EXIT_CODE_BETA', '')
243
247
  if exit_code_string =~ /^\d+$/
244
248
  $stderr.puts "Exiting can-i-deploy with configured exit code #{exit_code_string}"
245
249
  exit_code_string.to_i
@@ -281,6 +285,7 @@ module PactBroker
281
285
  options.broker_base_url,
282
286
  file_list(pact_files),
283
287
  consumer_version_params,
288
+ { merge: options[:merge], output: options.output }.compact,
284
289
  pact_broker_client_options.merge(write_options)
285
290
  )
286
291
  end
@@ -289,13 +294,26 @@ module PactBroker
289
294
  require 'rake/file_list'
290
295
 
291
296
  correctly_separated_pact_files = pact_files.collect{ |path| path.gsub(/\\+/, '/') }
292
- Rake::FileList[correctly_separated_pact_files].collect do | path |
297
+ paths = Rake::FileList[correctly_separated_pact_files].collect do | path |
293
298
  if File.directory?(path)
294
299
  Rake::FileList[File.join(path, "*.json")]
295
300
  else
296
301
  path
297
302
  end
298
303
  end.flatten
304
+ validate_pact_path_list(paths)
305
+ end
306
+
307
+ def validate_pact_path_list(paths)
308
+ paths.collect do | path |
309
+ if File.exist?(path)
310
+ path
311
+ elsif path.start_with?("-")
312
+ raise Thor::Error.new("ERROR: pact-broker publish was called with invalid arguments #{[path]}")
313
+ else
314
+ raise Thor::Error.new("Specified pact file '#{path}' does not exist. This sometimes indicates one of the arguments has been specified with the wrong name and has been incorrectly identified as a file path.")
315
+ end
316
+ end
299
317
  end
300
318
 
301
319
  def tags
@@ -378,7 +396,6 @@ module PactBroker
378
396
  provider: options.provider,
379
397
  events: events
380
398
  }
381
-
382
399
  end
383
400
 
384
401
  def run_webhook_commands webhook_url
@@ -0,0 +1,55 @@
1
+ The record-deployment command is used to allow the Pact Broker to keep track of which version(s) of an application are currently deployed in each environment. It is used to keep track of applications that are deployed to known instances. If you are releasing a client library or mobile application to a repository or application store, please use record-release instead.
2
+
3
+ ## Examples
4
+
5
+
6
+ record-deployment --pacticipant Foo --version 6897aa95e --environment production
7
+ record-deployment --pacticipant Foo --version 6897aa95e --environment production --target blue
8
+ record-deployment --pacticipant Foo --version 6897aa95e --environment production --target green
9
+
10
+ ## Target
11
+
12
+ The "target" field is used to distinguish between deployed versions of an application within the same environment, and most importantly, to identify which previously deployed version has been replaced by the current deployment. The Pact Broker only allows one unique combination of pacticipant/environment/target to be considered the "currently deployed" one, and any call to record a deployment will cause the previously deployed version with the same pacticipant/environment/target to be automatically marked as undeployed (mimicking the real world process of "deploying over" a previous version).
13
+
14
+ ### Use cases
15
+
16
+ #### There is a single instance of an application deployed within an environment and deployments of integrated applications are NOT likely to happen during the deployment window of this application
17
+
18
+ eg.
19
+
20
+ * the window of time when there are multiple versions in prod is small
21
+ * or there aren't many other integrations
22
+ * or deployments happen rarely
23
+ * or the same team controls all the deployments and generally only runs one deployment at a time
24
+
25
+ In this case, there is no need to specify a target. The call to record deployment should be done at the end of the deployment and it will automatically mark the version of Foo that was previously the currently deployed version as undeployed. Only one version of the pacticipant is ever considered to be currently deployed at a time.
26
+
27
+ eg.
28
+
29
+ # actual call to deploy here...
30
+ record-deployment --pacticipant Foo --version 6897aa95e --environment production
31
+
32
+ #### There is a single instance of an application deployed within an environment and but deployments of integrated applications ARE likely to happen during the deployment window of this application
33
+
34
+ eg.
35
+ * the window of time when there are multiple versions in prod is large
36
+ * or there are many integrations
37
+ * or deployments happen often
38
+ * or there are many different teams deploying and deployments aren't coordinated
39
+
40
+ To allow multiple versions to be considered currently deployed at the same time, use two different targets, and call the first record-deployment at the start of the deployment process and a second one at the end.
41
+
42
+ eg.
43
+
44
+ This will use the targets "blue" and "green" to model stages of the deployment.
45
+
46
+ record-deployment --pacticipant Foo --version 6897aa95e --environment production --target blue
47
+ # actual call to deploy here...
48
+ record-deployment --pacticipant Foo --version 6897aa95e --environment production --target green
49
+
50
+ After the first call to record-deployment, there will be two versions considered currently deployed - the "blue" one that was just recorded, and the one from the previous "green" deployment. After the second call to record-deployment, there is only one version considered currently deployed - both "blue" and "green" targets will be have version 6897aa95e deployed to them.
51
+
52
+
53
+ #### There are multiple permanent application versions deployed to the same environment
54
+
55
+ TBC
@@ -23,18 +23,34 @@ module PactBroker
23
23
  _link(key).get(*args)
24
24
  end
25
25
 
26
+ def get!(key, *args)
27
+ get(key, *args).assert_success!
28
+ end
29
+
26
30
  def post(key, *args)
27
31
  _link(key).post(*args)
28
32
  end
29
33
 
34
+ def post!(key, *args)
35
+ post(key, *args).assert_success!
36
+ end
37
+
30
38
  def put(key, *args)
31
39
  _link(key).put(*args)
32
40
  end
33
41
 
42
+ def put!(key, *args)
43
+ put(key, *args).assert_success!
44
+ end
45
+
34
46
  def patch(key, *args)
35
47
  _link(key).patch(*args)
36
48
  end
37
49
 
50
+ def patch!(key, *args)
51
+ patch(key, *args).assert_success!
52
+ end
53
+
38
54
  def can?(key)
39
55
  @links.key? key.to_s
40
56
  end
@@ -7,6 +7,7 @@ module PactBroker
7
7
  module Client
8
8
  module Hal
9
9
  class HttpClient
10
+ RETRYABLE_ERRORS = [Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EHOSTUNREACH, Net::ReadTimeout]
10
11
  attr_accessor :username, :password, :verbose, :token
11
12
 
12
13
  def initialize options
@@ -53,7 +54,7 @@ module PactBroker
53
54
  end
54
55
 
55
56
  def perform_request request, uri
56
- response = Retry.until_truthy_or_max_times do
57
+ response = until_truthy_or_max_times(condition: ->(resp) { resp.code.to_i < 500 }) do
57
58
  http = Net::HTTP.new(uri.host, uri.port, :ENV)
58
59
  http.set_debug_output(output_stream) if verbose
59
60
  http.use_ssl = (uri.scheme == 'https')
@@ -69,6 +70,41 @@ module PactBroker
69
70
  Response.new(response)
70
71
  end
71
72
 
73
+ def until_truthy_or_max_times options = {}
74
+ max_tries = options.fetch(:times, default_max_tries)
75
+ tries = 0
76
+ sleep_interval = options.fetch(:sleep, 5)
77
+ sleep(sleep_interval) if options[:sleep_first]
78
+ while true
79
+ begin
80
+ result = yield
81
+ return result if max_tries < 2
82
+ if options[:condition]
83
+ condition_result = options[:condition].call(result)
84
+ return result if condition_result
85
+ else
86
+ return result if result
87
+ end
88
+ tries += 1
89
+ return result if max_tries == tries
90
+ sleep sleep_interval
91
+ rescue *RETRYABLE_ERRORS => e
92
+ tries += 1
93
+ $stderr.puts "ERROR: Error making request - #{e.class} #{e.message} #{e.backtrace.find{|l| l.include?('pact_broker-client')}}, attempt #{tries} of #{max_tries}"
94
+ raise e if max_tries == tries
95
+ sleep sleep_interval
96
+ end
97
+ end
98
+ end
99
+
100
+ def default_max_tries
101
+ 5
102
+ end
103
+
104
+ def sleep seconds
105
+ Kernel.sleep seconds
106
+ end
107
+
72
108
  def output_stream
73
109
  AuthorizationHeaderRedactor.new($stdout)
74
110
  end