Skip to content

Commit cac3023

Browse files
committed
feat: allow matrix to be queried for _all_ versions with a given tag
Previously, only querying for the _latest_ version with a given tag was supported.
1 parent 7a81292 commit cac3023

File tree

9 files changed

+114
-55
lines changed

9 files changed

+114
-55
lines changed

lib/pact_broker/api/resources/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def delete_resource
3535

3636
def version
3737
if path_info[:tag]
38-
@version ||= version_service.find_by_pacticpant_name_and_latest_tag(path_info[:pacticipant_name], path_info[:tag])
38+
@version ||= version_service.find_by_pacticipant_name_and_latest_tag(path_info[:pacticipant_name], path_info[:tag])
3939
elsif path_info[:pacticipant_version_number]
4040
@version ||= version_service.find_by_pacticipant_name_and_number path_info
4141
else

lib/pact_broker/matrix/repository.rb

+39-26
Original file line numberDiff line numberDiff line change
@@ -134,21 +134,19 @@ def view_for(options)
134134
end
135135

136136
def resolve_selectors(selectors, options)
137-
selectors = look_up_versions_for_latest_and_tag(selectors, options)
138-
139-
if options[:latest]
140-
apply_latest_and_tag_to_inferred_selectors(selectors, options)
137+
resolved_selectors = look_up_version_numbers(selectors, options)
138+
if options[:latest] || options[:tag]
139+
apply_latest_and_tag_to_inferred_selectors(resolved_selectors, options)
141140
else
142-
selectors
141+
resolved_selectors
143142
end
144143
end
145144

146-
# Find the version number for selectors with the latest (tagged) version specified
147-
def look_up_versions_for_latest_and_tag(selectors, options)
145+
# Find the version number for selectors with the latest and/or tag specified
146+
def look_up_version_numbers(selectors, options)
148147
selectors.collect do | selector |
149-
# resource validation currently stops tag being specified without latest=true
150148
if selector[:tag] && selector[:latest]
151-
version = version_repository.find_by_pacticpant_name_and_latest_tag(selector[:pacticipant_name], selector[:tag])
149+
version = version_repository.find_by_pacticipant_name_and_latest_tag(selector[:pacticipant_name], selector[:tag])
152150
raise Error.new("Could not find version with tag #{selector[:tag].inspect} for #{selector[:pacticipant_name]}") unless version
153151
# validation in resource should ensure we always have a version
154152
{
@@ -161,25 +159,38 @@ def look_up_versions_for_latest_and_tag(selectors, options)
161159
pacticipant_name: selector[:pacticipant_name],
162160
pacticipant_version_number: version.number
163161
}
162+
elsif selector[:tag]
163+
# validation in resource should ensure we always have at least one version
164+
versions = version_repository.find_by_pacticipant_name_and_tag(selector[:pacticipant_name], selector[:tag])
165+
versions.collect do | version |
166+
{
167+
pacticipant_name: selector[:pacticipant_name],
168+
pacticipant_version_number: version.number
169+
}
170+
end
164171
else
165172
selector.dup
166173
end
167-
end.collect do | selector |
168-
if selector[:pacticipant_name]
169-
pacticipant = PactBroker::Domain::Pacticipant.find(name: selector[:pacticipant_name])
170-
selector[:pacticipant_id] = pacticipant ? pacticipant.id : nil
171-
end
174+
end.flatten.compact.collect do | selector |
175+
add_ids(selector)
176+
end
177+
end
172178

173-
if selector[:pacticipant_name] && selector[:pacticipant_version_number]
174-
version = version_repository.find_by_pacticipant_name_and_number(selector[:pacticipant_name], selector[:pacticipant_version_number])
175-
selector[:pacticipant_version_id] = version ? version.id : nil
176-
end
179+
def add_ids(selector)
180+
if selector[:pacticipant_name]
181+
pacticipant = PactBroker::Domain::Pacticipant.find(name: selector[:pacticipant_name])
182+
selector[:pacticipant_id] = pacticipant ? pacticipant.id : nil
183+
end
177184

178-
if selector[:pacticipant_version_number].nil?
179-
selector[:pacticipant_version_id] = nil
180-
end
181-
selector
185+
if selector[:pacticipant_name] && selector[:pacticipant_version_number]
186+
version = version_repository.find_by_pacticipant_name_and_number(selector[:pacticipant_name], selector[:pacticipant_version_number])
187+
selector[:pacticipant_version_id] = version ? version.id : nil
182188
end
189+
190+
if selector[:pacticipant_version_number].nil?
191+
selector[:pacticipant_version_id] = nil
192+
end
193+
selector
183194
end
184195

185196
# eg. when checking to see if Foo version 2 can be deployed to prod,
@@ -190,13 +201,15 @@ def apply_latest_and_tag_to_inferred_selectors(selectors, options)
190201
inferred_names = all_pacticipant_names - specified_names
191202

192203
inferred_selectors = inferred_names.collect do | pacticipant_name |
193-
{
204+
selector = {
194205
pacticipant_name: pacticipant_name,
195-
latest: options[:latest]
196-
}.tap { |it| it[:tag] = options[:tag] if options[:tag] }
206+
}
207+
selector[:tag] = options[:tag] if options[:tag]
208+
selector[:latest] = options[:latest] if options[:latest]
209+
selector
197210
end
198211

199-
selectors + look_up_versions_for_latest_and_tag(inferred_selectors, options)
212+
selectors + look_up_version_numbers(inferred_selectors, options)
200213
end
201214

202215
def all_pacticipant_names_in_specified_matrix(selectors, options)

lib/pact_broker/matrix/service.rb

+2-6
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,7 @@ def validate_selectors selectors
5757
error_messages << "Please specify the pacticipant name"
5858
else
5959
if s.key?(:pacticipant_version_number) && s.key?(:latest)
60-
error_messages << "A version and latest flag cannot both be specified for #{s[:pacticipant_name]}"
61-
end
62-
63-
if s.key?(:tag) && !s.key?(:latest)
64-
error_messages << "Querying for all versions with a tag is not currently supported. The latest=true flag must be specified when a tag is given."
60+
error_messages << "A version number and latest flag cannot both be specified for #{s[:pacticipant_name]}"
6561
end
6662
end
6763
end
@@ -78,7 +74,7 @@ def validate_selectors selectors
7874
version = version_service.find_by_pacticipant_name_and_number(pacticipant_name: s[:pacticipant_name], pacticipant_version_number: s[:pacticipant_version_number])
7975
error_messages << "No pact or verification found for #{s[:pacticipant_name]} version #{s[:pacticipant_version_number]}" if version.nil?
8076
elsif s[:tag]
81-
version = version_service.find_by_pacticpant_name_and_latest_tag(s[:pacticipant_name], s[:tag])
77+
version = version_service.find_by_pacticipant_name_and_latest_tag(s[:pacticipant_name], s[:tag])
8278
error_messages << "No version of #{s[:pacticipant_name]} found with tag #{s[:tag]}" if version.nil?
8379
end
8480
end

lib/pact_broker/versions/repository.rb

+11-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def find_by_pacticipant_id_and_number pacticipant_id, number
1212
PactBroker::Domain::Version.where(number: number, pacticipant_id: pacticipant_id).single_record
1313
end
1414

15-
def find_by_pacticpant_name_and_latest_tag pacticipant_name, tag
15+
def find_by_pacticipant_name_and_latest_tag pacticipant_name, tag
1616
PactBroker::Domain::Version
1717
.select_all_qualified
1818
.join(:pacticipants, {id: :pacticipant_id}, {implicit_qualifier: :versions})
@@ -23,6 +23,16 @@ def find_by_pacticpant_name_and_latest_tag pacticipant_name, tag
2323
.first
2424
end
2525

26+
def find_by_pacticipant_name_and_tag pacticipant_name, tag
27+
PactBroker::Domain::Version
28+
.select_all_qualified
29+
.join(:pacticipants, {id: :pacticipant_id}, {implicit_qualifier: :versions})
30+
.join(:tags, {version_id: :id}, {implicit_qualifier: :versions})
31+
.where(name_like(Sequel[:tags][:name], tag))
32+
.where(name_like(Sequel[:pacticipants][:name], pacticipant_name))
33+
.all
34+
end
35+
2636
def find_latest_by_pacticpant_name pacticipant_name
2737
PactBroker::Domain::Version
2838
.select_all_qualified

lib/pact_broker/versions/service.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ def self.find_by_pacticipant_name_and_number params
1515
version_repository.find_by_pacticipant_name_and_number params.fetch(:pacticipant_name), params.fetch(:pacticipant_version_number)
1616
end
1717

18-
def self.find_by_pacticpant_name_and_latest_tag(pacticipant_name, tag)
19-
version_repository.find_by_pacticpant_name_and_latest_tag(pacticipant_name, tag)
18+
def self.find_by_pacticipant_name_and_latest_tag(pacticipant_name, tag)
19+
version_repository.find_by_pacticipant_name_and_latest_tag(pacticipant_name, tag)
2020
end
2121

2222
def self.delete version

spec/lib/pact_broker/matrix/repository_spec.rb

+52
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,58 @@ def shorten_rows rows
479479
end
480480
end
481481

482+
context "when compability is required with all versions with a given tag" do
483+
before do
484+
td.create_pact_with_hierarchy("android app", "1", "BFF")
485+
.create_consumer_version_tag("prod")
486+
.create_verification(provider_version: "5", comment: "included")
487+
.create_consumer_version("2", tag_name: "prod")
488+
.create_pact
489+
.create_verification(provider_version: "5", comment: "included")
490+
.create_consumer_version("3")
491+
.create_pact
492+
.create_verification(provider_version: "5", comment: "not included")
493+
.create_consumer("ios app")
494+
.create_consumer_version("20", tag_name: "prod")
495+
.create_pact
496+
.create_verification(provider_version: "5", comment: "not included")
497+
end
498+
499+
context "when the other service is specifically named" do
500+
let(:selectors) do
501+
[
502+
{ pacticipant_name: "android app", tag: "prod" },
503+
{ pacticipant_name: "BFF", pacticipant_version_number: "5" }
504+
]
505+
end
506+
507+
let(:options) { {} }
508+
509+
it "returns the matrix for all of the versions for the specified pacticipants with the given tag" do
510+
expect(subject).to include_hash_matching(consumer_version_number: "1")
511+
expect(subject).to include_hash_matching(consumer_version_number: "2")
512+
expect(subject).to_not include_hash_matching(consumer_version_number: "3")
513+
expect(subject).to_not include_hash_matching(consumer_name: "ios app")
514+
end
515+
end
516+
517+
context "when the other service is not specifically named" do
518+
let(:selectors) do
519+
[
520+
{ pacticipant_name: "BFF", pacticipant_version_number: "5" }
521+
]
522+
end
523+
524+
let(:options) { { tag: "prod" } }
525+
526+
it "returns the matrix for all of the versions with the given tag" do
527+
expect(subject).to include_hash_matching(consumer_name: "android app", consumer_version_number: "1")
528+
expect(subject).to include_hash_matching(consumer_name: "android app", consumer_version_number: "2")
529+
expect(subject).to include_hash_matching(consumer_name: "ios app", consumer_version_number: "20")
530+
end
531+
end
532+
end
533+
482534
context "using the success option" do
483535
before do
484536
td.create_pact_with_hierarchy("A", "1.2.3", "B")

spec/lib/pact_broker/matrix/service_spec.rb

+1-17
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,7 @@ module Matrix
102102
let(:selectors) { [{ pacticipant_name: "Foo", pacticipant_version_number: "1", latest: true }, { pacticipant_name: "Bar", pacticipant_version_number: "2" }] }
103103

104104
it "returns an error message" do
105-
expect(subject).to eq ["A version and latest flag cannot both be specified for Foo"]
106-
end
107-
end
108-
109-
context "when a tag is specified without latest=true" do
110-
before do
111-
td.create_pacticipant("Foo")
112-
.create_version("1")
113-
.create_tag("prod")
114-
.create_pacticipant("Bar")
115-
.create_version("2")
116-
end
117-
118-
let(:selectors) { [{ pacticipant_name: "Foo", tag: "1"}] }
119-
120-
it "returns an error message" do
121-
expect(subject).to eq ["Querying for all versions with a tag is not currently supported. The latest=true flag must be specified when a tag is given."]
105+
expect(subject).to eq ["A version number and latest flag cannot both be specified for Foo"]
122106
end
123107
end
124108
end

spec/lib/pact_broker/versions/repository_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module Versions
1010
let(:version_number) { "1.2.3" }
1111

1212

13-
describe "#find_by_pacticpant_name_and_latest_tag" do
13+
describe "#find_by_pacticipant_name_and_latest_tag" do
1414
before do
1515
td.create_consumer("Bar")
1616
.create_consumer_version("2.3.4")
@@ -23,7 +23,7 @@ module Versions
2323
.create_consumer_version("5.6.7")
2424
end
2525

26-
subject { Repository.new.find_by_pacticpant_name_and_latest_tag("Foo", "prod") }
26+
subject { Repository.new.find_by_pacticipant_name_and_latest_tag("Foo", "prod") }
2727

2828
it "returns the most recent version that has the specified tag" do
2929

spec/support/test_data_builder.rb

+4
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,11 @@ def create_version version_number = "1.0.#{model_counter}", params = {}
168168

169169
def create_consumer_version version_number = "1.0.#{model_counter}", params = {}
170170
params.delete(:comment)
171+
tag_names = [params.delete(:tag_names), params.delete(:tag_name)].flatten.compact
171172
@consumer_version = PactBroker::Domain::Version.create(:number => version_number, :pacticipant => @consumer)
173+
tag_names.each do | tag_name |
174+
PactBroker::Domain::Tag.create(name: tag_name, version: @consumer_version)
175+
end
172176
self
173177
end
174178

0 commit comments

Comments
 (0)