pact_broker 2.47.1 → 2.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/Dockerfile +0 -1
  4. data/README.md +1 -1
  5. data/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema.rb +11 -0
  6. data/lib/pact_broker/api/contracts/verifiable_pacts_query_schema.rb +1 -0
  7. data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +4 -39
  8. data/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator.rb +9 -2
  9. data/lib/pact_broker/api/decorators/version_decorator.rb +1 -1
  10. data/lib/pact_broker/api/resources/verification.rb +6 -1
  11. data/lib/pact_broker/pacts/build_verifiable_pact_notices.rb +35 -0
  12. data/lib/pact_broker/pacts/repository.rb +71 -17
  13. data/lib/pact_broker/pacts/selected_pact.rb +9 -18
  14. data/lib/pact_broker/pacts/selector.rb +66 -10
  15. data/lib/pact_broker/pacts/selectors.rb +44 -0
  16. data/lib/pact_broker/pacts/service.rb +2 -2
  17. data/lib/pact_broker/pacts/squash_pacts_for_verification.rb +4 -6
  18. data/lib/pact_broker/pacts/verifiable_pact.rb +3 -12
  19. data/lib/pact_broker/pacts/verifiable_pact_messages.rb +63 -11
  20. data/lib/pact_broker/test/test_data_builder.rb +6 -0
  21. data/lib/pact_broker/verifications/repository.rb +4 -0
  22. data/lib/pact_broker/verifications/service.rb +5 -0
  23. data/lib/pact_broker/version.rb +1 -1
  24. data/lib/pact_broker/webhooks/service.rb +4 -0
  25. data/spec/features/delete_verification_spec.rb +29 -0
  26. data/spec/lib/pact_broker/api/contracts/verifiable_pacts_json_query_schema_spec.rb +29 -0
  27. data/spec/lib/pact_broker/api/decorators/verifiable_pact_decorator_spec.rb +18 -40
  28. data/spec/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator_spec.rb +20 -6
  29. data/spec/lib/pact_broker/api/decorators/version_decorator_spec.rb +4 -0
  30. data/spec/lib/pact_broker/api/resources/provider_pacts_for_verification_spec.rb +2 -2
  31. data/spec/lib/pact_broker/pacts/build_verifiable_pact_notices_spec.rb +76 -0
  32. data/spec/lib/pact_broker/pacts/repository_find_for_verification_fallback_spec.rb +73 -0
  33. data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +10 -12
  34. data/spec/lib/pact_broker/pacts/selector_spec.rb +28 -0
  35. data/spec/lib/pact_broker/pacts/selectors_spec.rb +30 -0
  36. data/spec/lib/pact_broker/pacts/service_spec.rb +2 -2
  37. data/spec/lib/pact_broker/pacts/squash_pacts_for_verification_spec.rb +2 -5
  38. data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +32 -24
  39. data/spec/support/verification_job.rb +1 -0
  40. metadata +14 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e05cc047cbfe572f654468283eabb11b7adc91da8b802b6955ddb10b3114a3ec
4
- data.tar.gz: 2a70640b544c8ac35f82bfc1612c9285506691ebe4e71c7e8629f3bd64ca3882
3
+ metadata.gz: bdda99358c4d4d8ca43f6e53e0e314fd24f475f1ff85fd0511743d8982224bca
4
+ data.tar.gz: 4f61ab3a051164ac3db85d7eef44fa088053873b2381f4c4104f4822c47bd651
5
5
  SHA512:
6
- metadata.gz: ad822d40451b9821921ea72fd8363625197524c1aed51ecefcfeb7d69b0d3b5382a9b45147fa2bf11baef50e77fc798e4eb55b58d4cbb9490d583a7d85399e4f
7
- data.tar.gz: 946de38bcbf4e0d96fa54cbd8466bdbb49cc44a74a4e89d11b4ed8b1c4db2778594450b6599e11adfbcdbd6dd5b84893c19389a5b92f163dfefa6d716f949313
6
+ metadata.gz: e3d9f86596a6d4aa776c13f28e84af1976485dc9eff3bef98accf6e372d379cb591270354a252c88a6b2c08ac928391e2ddcf8ee19d3db6f9832a667b4a81184
7
+ data.tar.gz: d4b2273ab789165a3f0ca7ce8f5fdb2220814d222ea172fa02fe77d19ce6e9e251277a6c621483a41b6b9911ab207b6d59861a39d2168ecdf5b0db64d1477d9f
@@ -1,3 +1,24 @@
1
+ <a name="v2.48.0"></a>
2
+ ### v2.48.0 (2020-02-07)
3
+
4
+
5
+ #### Features
6
+
7
+ * **pacts for verification**
8
+ * include a short description of the pact's selectors in the response ([41c6d91f](/../../commit/41c6d91f))
9
+ * update inclusion reason to support fallback tag explanation ([43081170](/../../commit/43081170))
10
+ * allow a fallback tag to be specified ([113180c1](/../../commit/113180c1))
11
+ * update the inclusion notice text to handle 'all pacts for tag' ([59ec8c8a](/../../commit/59ec8c8a))
12
+
13
+ * support DELETE for verification results ([70392e53](/../../commit/70392e53))
14
+
15
+
16
+ #### Bug Fixes
17
+
18
+ * a url typo (#328) ([482264fa](/../../commit/482264fa))
19
+ * correct URL of tag relation in pacticipant version resource ([ec24e999](/../../commit/ec24e999))
20
+
21
+
1
22
  <a name="v2.47.1"></a>
2
23
  ### v2.47.1 (2020-02-01)
3
24
 
data/Dockerfile CHANGED
@@ -12,7 +12,6 @@ RUN apk update \
12
12
  "sqlite>=3.28" \
13
13
  "tzdata>=2019" \
14
14
  "mariadb-dev>=10.3" \
15
- "git" \
16
15
  && rm -rf /var/cache/apk/*
17
16
 
18
17
  WORKDIR /app
data/README.md CHANGED
@@ -12,7 +12,7 @@ The Pact Broker is an application for sharing for consumer driven contracts and
12
12
  <a href="https:/pactflow.io/?utm_source=github&utm_campaign=pact_broker_intro"><img src="docs/images/Pactflow logo - black small.png"></a>
13
13
  <br/>
14
14
 
15
- You can try out a Pact Broker for free at <a href="https:/pactflow.io/?utm_source=github&utm_campaign=pact_broker_intro"/>pactflow.io</a>. Built by a group of core Pact maintainers, Pactflow is a fork of the OSS Pact Broker with extra goodies like an improved UI, field level verification results and federated login.
15
+ You can try out a Pact Broker for free at <a href="https://pactflow.io/?utm_source=github&utm_campaign=pact_broker_intro"/>pactflow.io</a>. Built by a group of core Pact maintainers, Pactflow is a fork of the OSS Pact Broker with extra goodies like an improved UI, field level verification results and federated login.
16
16
 
17
17
  **Why do I need a Pact Broker?**
18
18
 
@@ -17,8 +17,19 @@ module PactBroker
17
17
  optional(:providerVersionTags).maybe(:array?)
18
18
  optional(:consumerVersionSelectors).each do
19
19
  schema do
20
+ # configure do
21
+ # def self.messages
22
+ # super.merge(en: { errors: { fallbackTagMustBeForLatest: 'can only be set if latest=true' }})
23
+ # end
24
+ # end
25
+
20
26
  required(:tag).filled(:str?)
21
27
  optional(:latest).filled(included_in?: [true, false])
28
+ optional(:fallbackTag).filled(:str?)
29
+
30
+ # rule(fallbackTagMustBeForLatest: [:fallbackTag, :latest]) do | fallback_tag, latest |
31
+ # fallback_tag.filled?.then(latest.eql?(true))
32
+ # end
22
33
  end
23
34
  end
24
35
  optional(:includePendingStatus).filled(included_in?: [true, false])
@@ -18,6 +18,7 @@ module PactBroker
18
18
  schema do
19
19
  required(:tag).filled(:str?)
20
20
  optional(:latest).filled(included_in?: ["true", "false"])
21
+ optional(:fallback_tag).filled(:str?)
21
22
  end
22
23
  end
23
24
  optional(:include_pending_status).filled(included_in?: ["true", "false"])
@@ -1,26 +1,15 @@
1
1
  require_relative 'base_decorator'
2
2
  require 'pact_broker/api/pact_broker_urls'
3
- require 'delegate'
4
- require 'pact_broker/pacts/verifiable_pact_messages'
3
+ require 'pact_broker/pacts/build_verifiable_pact_notices'
5
4
 
6
5
  module PactBroker
7
6
  module Api
8
7
  module Decorators
9
8
  class VerifiablePactDecorator < BaseDecorator
10
9
 
11
- # Allows a "flat" VerifiablePact to look like it has
12
- # a nested verification_properties object for Reform
13
- class Reshaper < SimpleDelegator
14
- def verification_properties
15
- __getobj__()
16
- end
17
- end
18
-
19
- def initialize(verifiable_pact)
20
- super(Reshaper.new(verifiable_pact))
21
- end
10
+ property :shortDescription, getter: -> (context) { PactBroker::Pacts::VerifiablePactMessages.new(context[:represented], nil).pact_version_short_description }
22
11
 
23
- property :verification_properties, as: :verificationProperties do
12
+ nested :verificationProperties do
24
13
  include PactBroker::Api::PactBrokerUrls
25
14
 
26
15
  property :pending,
@@ -31,32 +20,8 @@ module PactBroker
31
20
  property :noteToDevelopers, getter: -> (_) { "Please print out the text from the 'notices' rather than using the inclusionReason and the pendingReason fields. These will be removed when this API moves out of beta."}
32
21
 
33
22
  def notices(user_options)
34
- # TODO move this out of the decorator
35
23
  pact_url = pact_version_url(represented, user_options[:base_url])
36
- messages = PactBroker::Pacts::VerifiablePactMessages.new(represented, pact_url)
37
-
38
- the_notices = [{
39
- when: 'before_verification',
40
- text: messages.inclusion_reason
41
- }]
42
-
43
- if user_options[:include_pending_status]
44
- append_notice(the_notices, 'before_verification', messages.pending_reason)
45
- append_notice(the_notices, 'after_verification:success_true_published_false', messages.verification_success_true_published_false)
46
- append_notice(the_notices, 'after_verification:success_false_published_false', messages.verification_success_false_published_false)
47
- append_notice(the_notices, 'after_verification:success_true_published_true', messages.verification_success_true_published_true)
48
- append_notice(the_notices, 'after_verification:success_false_published_true', messages.verification_success_false_published_true)
49
- end
50
- the_notices
51
- end
52
-
53
- def append_notice the_notices, the_when, text
54
- if text
55
- the_notices << {
56
- when: the_when,
57
- text: text
58
- }
59
- end
24
+ PactBroker::Pacts::BuildVerifiablePactNotices.call(represented, pact_url, include_pending_status: user_options[:include_pending_status])
60
25
  end
61
26
  end
62
27
 
@@ -2,6 +2,8 @@ require_relative 'base_decorator'
2
2
  require_relative 'verifiable_pact_decorator'
3
3
  require 'pact_broker/api/pact_broker_urls'
4
4
  require 'pact_broker/hash_refinements'
5
+ require 'pact_broker/pacts/selector'
6
+ require 'pact_broker/pacts/selectors'
5
7
 
6
8
  module PactBroker
7
9
  module Api
@@ -11,12 +13,13 @@ module PactBroker
11
13
 
12
14
  collection :provider_version_tags, default: []
13
15
 
14
- collection :consumer_version_selectors, default: [], class: OpenStruct do
16
+ collection :consumer_version_selectors, default: PactBroker::Pacts::Selectors.new, class: PactBroker::Pacts::Selector do
15
17
  property :tag
16
18
  property :latest,
17
19
  setter: ->(fragment:, represented:, **) {
18
20
  represented.latest = (fragment == 'true' || fragment == true)
19
21
  }
22
+ property :fallback_tag
20
23
  end
21
24
 
22
25
  property :include_pending_status, default: false,
@@ -31,7 +34,11 @@ module PactBroker
31
34
 
32
35
  def from_hash(hash)
33
36
  # This handles both the snakecase keys from the GET query and the camelcase JSON POST body
34
- super(hash&.snakecase_keys)
37
+ result = super(hash&.snakecase_keys)
38
+ if result.consumer_version_selectors && !result.consumer_version_selectors.is_a?(PactBroker::Pacts::Selectors)
39
+ result.consumer_version_selectors = PactBroker::Pacts::Selectors.new(result.consumer_version_selectors)
40
+ end
41
+ result
35
42
  end
36
43
  end
37
44
  end
@@ -28,7 +28,7 @@ module PactBroker
28
28
 
29
29
  link :'pb:tag' do | options |
30
30
  {
31
- href: pacticipant_url(options.fetch(:base_url), represented.pacticipant) + '/tags/{tag}',
31
+ href: version_url(options.fetch(:base_url), represented) + '/tags/{tag}',
32
32
  title: "Get, create or delete a tag for this pacticipant version",
33
33
  templated: true
34
34
  }
@@ -20,7 +20,7 @@ module PactBroker
20
20
  # Remember to update latest_verification_id_for_pact_version_and_provider_version
21
21
  # if/when DELETE is implemented
22
22
  def allowed_methods
23
- ["GET", "OPTIONS"]
23
+ ["GET", "OPTIONS", "DELETE"]
24
24
  end
25
25
 
26
26
  def resource_exists?
@@ -40,6 +40,11 @@ module PactBroker
40
40
  extended_decorator_for(verification).to_json(user_options: { base_url: base_url })
41
41
  end
42
42
 
43
+ def delete_resource
44
+ verification_service.delete(verification)
45
+ true
46
+ end
47
+
43
48
  private
44
49
 
45
50
  def verification
@@ -0,0 +1,35 @@
1
+ require 'pact_broker/pacts/verifiable_pact_messages'
2
+
3
+ module PactBroker
4
+ module Pacts
5
+ class BuildVerifiablePactNotices
6
+
7
+ def self.call(verifiable_pact, pact_url, options)
8
+ messages = VerifiablePactMessages.new(verifiable_pact, pact_url)
9
+
10
+ notices = [{
11
+ when: 'before_verification',
12
+ text: messages.inclusion_reason
13
+ }]
14
+
15
+ if options[:include_pending_status]
16
+ append_notice(notices, 'before_verification', messages.pending_reason)
17
+ append_notice(notices, 'after_verification:success_true_published_false', messages.verification_success_true_published_false)
18
+ append_notice(notices, 'after_verification:success_false_published_false', messages.verification_success_false_published_false)
19
+ append_notice(notices, 'after_verification:success_true_published_true', messages.verification_success_true_published_true)
20
+ append_notice(notices, 'after_verification:success_false_published_true', messages.verification_success_false_published_true)
21
+ end
22
+ notices
23
+ end
24
+
25
+ def self.append_notice notices, the_when, text
26
+ if text
27
+ notices << {
28
+ when: the_when,
29
+ text: text
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -16,6 +16,7 @@ require 'pact_broker/pacts/verifiable_pact'
16
16
  require 'pact_broker/repositories/helpers'
17
17
  require 'pact_broker/pacts/selected_pact'
18
18
  require 'pact_broker/pacts/selector'
19
+ require 'pact_broker/pacts/selectors'
19
20
 
20
21
  module PactBroker
21
22
  module Pacts
@@ -150,7 +151,7 @@ module PactBroker
150
151
  .collect do | pact_publications |
151
152
  selector_tag_names = pact_publications.collect{ | p| p.values.fetch(:consumer_version_tag_name) }
152
153
  latest_pact_publication = pact_publications.sort_by{ |p| p.values.fetch(:consumer_version_order) }.last
153
- selectors = selector_tag_names.collect{ | tag_name | Selector.one_of_tag(tag_name) }
154
+ selectors = Selectors.create_for_all_of_each_tag(selector_tag_names)
154
155
  SelectedPact.new(latest_pact_publication.to_domain, selectors)
155
156
  end
156
157
  end
@@ -206,7 +207,8 @@ module PactBroker
206
207
  pre_existing_pending_tags = pending_tag_names & pre_existing_tag_names
207
208
 
208
209
  if pre_existing_pending_tags.any?
209
- VerifiablePact.new(pact.to_domain, true, pre_existing_pending_tags, [], pact.head_tag_names, nil, true)
210
+ selectors = Selectors.create_for_latest_of_each_tag(pact.head_tag_names)
211
+ VerifiablePact.new(pact.to_domain, selectors, true, pre_existing_pending_tags, [], true)
210
212
  end
211
213
  end.compact
212
214
  end
@@ -349,16 +351,36 @@ module PactBroker
349
351
  selected_pacts = find_pacts_for_which_the_latest_version_is_required(provider_name, consumer_version_selectors) +
350
352
  find_pacts_for_which_the_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors) +
351
353
  find_pacts_for_which_all_versions_for_the_tag_are_required(provider_name, consumer_version_selectors)
354
+
355
+ selected_pacts = selected_pacts + find_pacts_for_fallback_tags(selected_pacts, provider_name, consumer_version_selectors)
356
+
352
357
  selected_pacts
353
358
  .group_by(&:pact_version_sha)
354
359
  .values
355
360
  .collect do | selected_pacts_for_pact_version_id |
356
361
  SelectedPact.merge(selected_pacts_for_pact_version_id)
357
362
  end
363
+
358
364
  end
359
365
 
360
366
  private
361
367
 
368
+ def find_pacts_for_fallback_tags(selected_pacts, provider_name, consumer_version_selectors)
369
+ # TODO at the moment, the validation doesn't stop fallback being used with 'all' selectors
370
+ selectors_with_fallback_tags = consumer_version_selectors.select(&:fallback_tag?)
371
+ selectors_missing_a_pact = selectors_with_fallback_tags.reject do | selector |
372
+ selected_pacts.any? do | selected_pact |
373
+ selected_pact.latest_for_tag?(selector.tag)
374
+ end
375
+ end
376
+
377
+ if selectors_missing_a_pact.any?
378
+ find_pacts_for_which_the_latest_version_for_the_fallback_tag_is_required(provider_name, selectors_missing_a_pact)
379
+ else
380
+ []
381
+ end
382
+ end
383
+
362
384
  def find_pacts_for_which_the_latest_version_is_required(provider_name, consumer_version_selectors)
363
385
  if consumer_version_selectors.empty?
364
386
  LatestPactPublications
@@ -366,7 +388,7 @@ module PactBroker
366
388
  .order_ignore_case(:consumer_name)
367
389
  .collect do | latest_pact_publication |
368
390
  pact_publication = PactPublication.find(id: latest_pact_publication.id)
369
- SelectedPact.new(pact_publication.to_domain, [Selector.overall_latest])
391
+ SelectedPact.new(pact_publication.to_domain, Selectors.create_for_overall_latest)
370
392
  end
371
393
  else
372
394
  []
@@ -375,38 +397,70 @@ module PactBroker
375
397
 
376
398
  def find_pacts_for_which_the_latest_version_for_the_tag_is_required(provider_name, consumer_version_selectors)
377
399
  # The tags for which only the latest version is specified
378
- latest_tags = consumer_version_selectors.select(&:latest).collect(&:tag).compact.uniq
400
+ tag_names = consumer_version_selectors.tag_names_of_selectors_for_latest_pacts
379
401
 
380
402
  # TODO make this an efficient query!
381
403
  # These are not yet de-duped. Should make the behaviour consistent between this and find_pacts_for_which_all_versions_for_the_tag_are_required ?
382
- if latest_tags.any?
404
+ if tag_names.any?
383
405
  LatestTaggedPactPublications
384
406
  .provider(provider_name)
385
- .order_ignore_case(:consumer_name)
386
- .where(tag_name: latest_tags)
407
+ .where(tag_name: tag_names)
387
408
  .all
388
409
  .group_by(&:pact_version_id)
389
410
  .values
390
411
  .collect do | pact_publications |
391
- selector_tag_names = pact_publications.collect(&:tag_name)
392
- last_pact_publication = pact_publications.sort_by(&:consumer_version_order).last
393
- pact_publication = PactPublication.find(id: last_pact_publication.id)
394
- SelectedPact.new(
395
- pact_publication.to_domain,
396
- selector_tag_names.collect{ | tag_name| Selector.latest_for_tag(tag_name) }
397
- )
412
+ create_selected_pact(pact_publications)
398
413
  end
399
414
  else
400
415
  []
401
416
  end
402
417
  end
403
418
 
419
+ def create_selected_pact(pact_publications)
420
+ selector_tag_names = pact_publications.collect(&:tag_name)
421
+ selectors = Selectors.create_for_latest_of_each_tag(selector_tag_names)
422
+ last_pact_publication = pact_publications.sort_by(&:consumer_version_order).last
423
+ pact_publication = PactPublication.find(id: last_pact_publication.id)
424
+ SelectedPact.new(
425
+ pact_publication.to_domain,
426
+ selectors
427
+ )
428
+ end
429
+
430
+ def create_fallback_selected_pact(pact_publications, consumer_version_selectors)
431
+ selector_tag_names = pact_publications.collect(&:tag_name)
432
+ selectors = Selectors.create_for_latest_fallback_of_each_tag(selector_tag_names)
433
+ last_pact_publication = pact_publications.sort_by(&:consumer_version_order).last
434
+ pact_publication = PactPublication.find(id: last_pact_publication.id)
435
+ SelectedPact.new(
436
+ pact_publication.to_domain,
437
+ selectors
438
+ )
439
+ end
440
+
441
+ def find_pacts_for_which_the_latest_version_for_the_fallback_tag_is_required(provider_name, selectors)
442
+ selectors.collect do | selector |
443
+ LatestTaggedPactPublications
444
+ .provider(provider_name)
445
+ .where(tag_name: selector.fallback_tag)
446
+ .all
447
+ .collect do | latest_tagged_pact_publication |
448
+ pact_publication = PactPublication.find(id: latest_tagged_pact_publication.id)
449
+ SelectedPact.new(
450
+ pact_publication.to_domain,
451
+ Selectors.new(selector)
452
+ )
453
+ end
454
+ end.flatten
455
+ end
456
+
457
+
404
458
  def find_pacts_for_which_all_versions_for_the_tag_are_required(provider_name, consumer_version_selectors)
405
459
  # The tags for which all versions are specified
406
- all_tags = consumer_version_selectors.reject(&:latest).collect(&:tag)
460
+ tag_names = consumer_version_selectors.tag_names_of_selectors_for_all_pacts
407
461
 
408
- if all_tags.any?
409
- find_all_pact_versions_for_provider_with_consumer_version_tags(provider_name, all_tags)
462
+ if tag_names.any?
463
+ find_all_pact_versions_for_provider_with_consumer_version_tags(provider_name, tag_names)
410
464
  else
411
465
  []
412
466
  end
@@ -11,31 +11,22 @@ module PactBroker
11
11
  @selectors = selectors
12
12
  end
13
13
 
14
- # might actually be, but this code doesn't know it.
15
- def overall_latest?
16
- selectors.any?(&:overall_latest?)
17
- end
18
-
19
- def latest_for_tag?
20
- selectors.any?(&:latest_for_tag?)
21
- end
22
-
23
14
  def self.merge(selected_pacts)
24
15
  latest_selected_pact = selected_pacts.sort_by(&:consumer_version_order).last
25
- selectors = selected_pacts.collect(&:selectors).flatten.uniq
16
+ selectors = selected_pacts.collect(&:selectors).reduce(&:+)
26
17
  SelectedPact.new(latest_selected_pact.pact, selectors)
27
18
  end
28
19
 
29
- def merge(other)
30
- if pact_version_sha != other.pact_version_sha
31
- raise "These two pacts do not have the same pact_version_sha. They cannot be merged. #{pact_version_sha} and #{other.pact_version_sha}"
32
- else
33
- SelectedPact.new()
34
- end
20
+ def tag_names_of_selectors_for_latest_pacts
21
+ selectors.tag_names_of_selectors_for_latest_pacts
22
+ end
23
+
24
+ def overall_latest?
25
+ selectors.overall_latest?
35
26
  end
36
27
 
37
- def tag_names_for_selectors_for_latest_pacts
38
- selectors.select(&:latest_for_tag?).collect(&:tag)
28
+ def latest_for_tag? potential_tag = nil
29
+ selectors.latest_for_tag?(potential_tag)
39
30
  end
40
31
 
41
32
  def consumer_version_order