pact_broker-client 1.38.3 → 1.39.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +18 -0
  4. data/doc/pacts/markdown/Pact Broker Client - Pact Broker.md +100 -0
  5. data/example/scripts/publish-pact.sh +1 -1
  6. data/lib/pact_broker/client/cli/broker.rb +23 -7
  7. data/lib/pact_broker/client/cli/record_deployment_long_desc.txt +55 -0
  8. data/lib/pact_broker/client/hal/entity.rb +16 -0
  9. data/lib/pact_broker/client/hal/http_client.rb +6 -2
  10. data/lib/pact_broker/client/hal/link.rb +12 -0
  11. data/lib/pact_broker/client/hal/links.rb +15 -0
  12. data/lib/pact_broker/client/hal_client_methods.rb +8 -0
  13. data/lib/pact_broker/client/pacts.rb +0 -1
  14. data/lib/pact_broker/client/publish_pacts.rb +90 -128
  15. data/lib/pact_broker/client/publish_pacts_the_old_way.rb +194 -0
  16. data/lib/pact_broker/client/tasks/publication_task.rb +3 -3
  17. data/lib/pact_broker/client/version.rb +1 -1
  18. data/lib/pact_broker/client/versions/record_deployment.rb +4 -4
  19. data/lib/pact_broker/client/versions/record_undeployment.rb +45 -68
  20. data/script/publish-pact.sh +17 -4
  21. data/script/record-deployment.sh +1 -3
  22. data/script/record-undeployment.sh +4 -0
  23. data/spec/fixtures/foo-bar.json +31 -0
  24. data/spec/lib/pact_broker/client/cli/broker_publish_spec.rb +36 -7
  25. data/spec/lib/pact_broker/client/pacticipants/create_spec.rb +3 -0
  26. data/spec/lib/pact_broker/client/{publish_pacts_spec.rb → publish_pacts_the_old_way_spec.rb} +10 -9
  27. data/spec/lib/pact_broker/client/tasks/publication_task_spec.rb +18 -12
  28. data/spec/lib/pact_broker/client/versions/record_deployment_spec.rb +4 -4
  29. data/spec/pacts/pact_broker_client-pact_broker.json +106 -0
  30. data/spec/service_providers/pact_broker_client_create_version_spec.rb +4 -4
  31. data/spec/service_providers/publish_pacts_spec.rb +115 -0
  32. data/spec/service_providers/record_deployment_spec.rb +5 -5
  33. metadata +12 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7e8fccfd3284da577d92cac60037f56d293b613ac0dd1d3b58a439027ef6401
4
- data.tar.gz: 806f879281896358482de7cd2a0dd880688fded9a7f29f9da2f41f783cd782b0
3
+ metadata.gz: 687ab091422717162f63b7fd2ee9dc336bd73f24c48b48f5e0a1299ab88dc036
4
+ data.tar.gz: 32fcd370558280287bf284ff4306f36ccfea94359278fd157a4db32ec5d7911f
5
5
  SHA512:
6
- metadata.gz: 81f3b06673555261c984203492523162b54ead2221701e1c5d474de22ec7e7a03cca95c0289f86532d739f0d4dbeac104e8abd55e315d262c84d6e847159e269
7
- data.tar.gz: 52d2a1c8ff9ed55a73b45991b459d11a9240f7eec1c9863d0625bb740a853ed7d811106537cf91ce5ffbe9581cb9cb26b94fdd4d61a797ba59e2aef37002f8c1
6
+ metadata.gz: 290ee48f43fffa0b48c467a37e8433ada2f1abfde564d0aad62e9eb3adf27bc3ac957decf233c0de6e6373b0c74183e76b2c709335fc3692d2932fcf7e4305e7
7
+ data.tar.gz: 9a64e0d22fbcb7e82fb586f5f463b41fc13df73e32be1ce64358b871dc41a1dbbd034c4971b411858537eb561063f66a8fee010b83e008170ea9a23e7559a0ba
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ <a name="v1.39.0"></a>
2
+ ### v1.39.0 (2021-04-27)
3
+
4
+ #### Features
5
+
6
+ * publish pacts using the "all in one" endpoint (#86) ([3a1ea22](/../../commit/3a1ea22))
7
+ * provide a more helpful error message when the specified pact file does not exist ([29a7962](/../../commit/29a7962))
8
+
1
9
  <a name="v1.38.3"></a>
2
10
  ### v1.38.3 (2021-04-08)
3
11
 
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
  ```
@@ -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
@@ -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."
@@ -51,14 +51,16 @@ module PactBroker
51
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"
52
52
  method_option :build_url, desc: "The build URL that created the pact"
53
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'
54
55
  shared_authentication_options
55
56
 
56
57
  def publish(*pact_files)
57
58
  require 'pact_broker/client/error'
58
59
  validate_credentials
59
60
  validate_pact_files(pact_files)
60
- success = publish_pacts(pact_files)
61
- 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
62
64
  rescue PactBroker::Client::Error => e
63
65
  raise PactPublicationError, "#{e.class} - #{e.message}"
64
66
  end
@@ -173,10 +175,11 @@ module PactBroker
173
175
 
174
176
  ignored_and_hidden_potential_options_from_environment_variables
175
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'))
176
179
  method_option :pacticipant, required: true, aliases: "-a", desc: "The name of the pacticipant that was deployed."
177
180
  method_option :version, required: true, aliases: "-e", desc: "The pacticipant version number that was deployed."
178
181
  method_option :environment, required: true, desc: "The name of the environment that the pacticipant version was deployed to."
179
- 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."
180
183
  method_option :output, aliases: "-o", desc: "json or text", default: 'text'
181
184
  shared_authentication_options
182
185
 
@@ -186,7 +189,7 @@ module PactBroker
186
189
  pacticipant_name: options.pacticipant,
187
190
  version_number: options.version,
188
191
  environment_name: options.environment,
189
- replaced_previous_deployed_version: options.replaced_previous_deployed_version,
192
+ target: options.target,
190
193
  output: options.output
191
194
  }
192
195
  result = PactBroker::Client::Versions::RecordDeployment.call(
@@ -282,6 +285,7 @@ module PactBroker
282
285
  options.broker_base_url,
283
286
  file_list(pact_files),
284
287
  consumer_version_params,
288
+ { merge: options[:merge], output: options.output }.compact,
285
289
  pact_broker_client_options.merge(write_options)
286
290
  )
287
291
  end
@@ -290,13 +294,26 @@ module PactBroker
290
294
  require 'rake/file_list'
291
295
 
292
296
  correctly_separated_pact_files = pact_files.collect{ |path| path.gsub(/\\+/, '/') }
293
- Rake::FileList[correctly_separated_pact_files].collect do | path |
297
+ paths = Rake::FileList[correctly_separated_pact_files].collect do | path |
294
298
  if File.directory?(path)
295
299
  Rake::FileList[File.join(path, "*.json")]
296
300
  else
297
301
  path
298
302
  end
299
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
300
317
  end
301
318
 
302
319
  def tags
@@ -379,7 +396,6 @@ module PactBroker
379
396
  provider: options.provider,
380
397
  events: events
381
398
  }
382
-
383
399
  end
384
400
 
385
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
@@ -54,7 +54,7 @@ module PactBroker
54
54
  end
55
55
 
56
56
  def perform_request request, uri
57
- response = until_truthy_or_max_times(times: 5, sleep: 5, condition: ->(resp) { resp.code.to_i < 500 }) do
57
+ response = until_truthy_or_max_times(condition: ->(resp) { resp.code.to_i < 500 }) do
58
58
  http = Net::HTTP.new(uri.host, uri.port, :ENV)
59
59
  http.set_debug_output(output_stream) if verbose
60
60
  http.use_ssl = (uri.scheme == 'https')
@@ -71,7 +71,7 @@ module PactBroker
71
71
  end
72
72
 
73
73
  def until_truthy_or_max_times options = {}
74
- max_tries = options.fetch(:times, 3)
74
+ max_tries = options.fetch(:times, default_max_tries)
75
75
  tries = 0
76
76
  sleep_interval = options.fetch(:sleep, 5)
77
77
  sleep(sleep_interval) if options[:sleep_first]
@@ -97,6 +97,10 @@ module PactBroker
97
97
  end
98
98
  end
99
99
 
100
+ def default_max_tries
101
+ 5
102
+ end
103
+
100
104
  def sleep seconds
101
105
  Kernel.sleep seconds
102
106
  end
@@ -49,14 +49,26 @@ module PactBroker
49
49
  wrap_response(href, @http_client.put(href, payload ? JSON.dump(payload) : nil, headers))
50
50
  end
51
51
 
52
+ def put!(*args)
53
+ put(*args).assert_success!
54
+ end
55
+
52
56
  def post(payload = nil, headers = {})
53
57
  wrap_response(href, @http_client.post(href, payload ? JSON.dump(payload) : nil, headers))
54
58
  end
55
59
 
60
+ def post!(*args)
61
+ post(*args).assert_success!
62
+ end
63
+
56
64
  def patch(payload = nil, headers = {})
57
65
  wrap_response(href, @http_client.patch(href, payload ? JSON.dump(payload) : nil, headers))
58
66
  end
59
67
 
68
+ def patch!(*args)
69
+ patch(*args).assert_success!
70
+ end
71
+
60
72
  def expand(params)
61
73
  expanded_url = expand_url(params, href)
62
74
  new_attrs = @attrs.merge('href' => expanded_url)
@@ -30,6 +30,21 @@ module PactBroker
30
30
  links.find{ | link | link.name == name }
31
31
  end
32
32
 
33
+ def select!(name, not_found_message = nil)
34
+ selected_links = select(name)
35
+ if selected_links.any?
36
+ selected_links
37
+ else
38
+ message = not_found_message || "Could not find relation '#{key}' with name '#{name}' in resource at #{href}."
39
+ available_options = names.any? ? names.join(", ") : "<none found>"
40
+ raise RelationNotFoundError.new(message.chomp(".") + ". Available options: #{available_options}")
41
+ end
42
+ end
43
+
44
+ def select(name)
45
+ links.select{ | link | link.name == name }
46
+ end
47
+
33
48
  private
34
49
 
35
50
  attr_reader :links, :key, :href