Skip to content

Commit e8d0fae

Browse files
committed
feat(dashboard api): include verification tags
1 parent d2a9e30 commit e8d0fae

14 files changed

+234
-16
lines changed

db/migrations/000050_create_latest_matrix.rb

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# latest verification for each provider version)
66
# Must include lines where verification_id is null so that we don't
77
# lose the unverified pacts.
8+
# In this view there will be one row for each consumer version/provider version
89
create_view(:latest_matrix,
910
"SELECT matrix.* FROM matrix
1011
INNER JOIN latest_verification_id_for_consumer_version_and_provider_version AS lv
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Sequel.migration do
2+
change do
3+
# the provider version order of the latest verification for each consumer/provider/tag
4+
create_view(:latest_tagged_verification_provider_version_orders,
5+
"
6+
select m.consumer_id, m.provider_id, t.name as tag_name, max(m.provider_version_order) as latest_provider_version_order
7+
from latest_matrix m
8+
inner join tags t
9+
on m.provider_version_id = t.version_id
10+
where m.provider_version_order is not null
11+
group by m.consumer_id, m.provider_id, t.name
12+
"
13+
)
14+
15+
=begin
16+
The tags for which the given verification is the latest of that tag
17+
Imagine that:
18+
19+
provider v1 has verification
20+
has tag dev
21+
has tag prod <- latest
22+
provider v2 has verification
23+
has tag dev <-latest
24+
provider v3 has tag dev
25+
26+
This table would contain the prod tag row for the v1 verification
27+
This table would contain the dev tag row for the v2 verification
28+
=end
29+
create_view(:latest_verification_tags,
30+
"
31+
select t.*, m.verification_id
32+
from latest_matrix m
33+
inner join latest_tagged_verification_provider_version_orders l
34+
on m.consumer_id = l.consumer_id
35+
and m.provider_id = l.provider_id
36+
and m.provider_version_order = l.latest_provider_version_order
37+
inner join tags t
38+
on l.tag_name = t.name
39+
and m.provider_version_id = t.version_id
40+
"
41+
)
42+
end
43+
end

lib/pact_broker/api/decorators/dashboard_decorator.rb

+16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def index_item_hash(consumer, provider, consumer_version, index_item, base_url)
3838
pact: pact_hash(index_item, base_url),
3939
pactTags: pact_tags(index_item, base_url),
4040
latestVerificationResult: verification_hash(index_item, base_url),
41+
latestVerificationResultTags: verification_tags(index_item, base_url),
4142
verificationStatus: index_item.verification_status.to_s,
4243
webhookStatus: index_item.webhook_status.to_s,
4344
latestWebhookExecution: latest_webhook_execution(index_item, base_url),
@@ -125,6 +126,21 @@ def pact_tags(index_item, base_url)
125126
end
126127
end
127128

129+
def verification_tags(index_item, base_url)
130+
index_item.latest_verification_latest_tags.collect do | tag |
131+
fake_tag = OpenStruct.new(name: tag.name, version: index_item.provider_version)
132+
{
133+
name: tag.name,
134+
latest: true,
135+
_links: {
136+
self: {
137+
href: tag_url(base_url, fake_tag)
138+
}
139+
}
140+
}
141+
end
142+
end
143+
128144
def latest_webhook_execution(index_item, base_url)
129145
if index_item.last_webhook_execution_date
130146
{

lib/pact_broker/domain/index_item.rb

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ module PactBroker
55
module Domain
66
class IndexItem
77

8-
attr_reader :consumer, :provider, :latest_pact, :latest_verification, :webhooks, :triggered_webhooks
8+
attr_reader :consumer, :provider, :latest_pact, :latest_verification, :webhooks, :triggered_webhooks, :latest_verification_latest_tags
99

10-
def initialize consumer, provider, latest_pact = nil, latest = true, latest_verification = nil, webhooks = [], triggered_webhooks = [], tags = []
10+
def initialize consumer, provider, latest_pact = nil, latest = true, latest_verification = nil, webhooks = [], triggered_webhooks = [], tags = [], latest_verification_latest_tags = []
1111
@consumer = consumer
1212
@provider = provider
1313
@latest_pact = latest_pact
@@ -16,10 +16,11 @@ def initialize consumer, provider, latest_pact = nil, latest = true, latest_veri
1616
@webhooks = webhooks
1717
@triggered_webhooks = triggered_webhooks
1818
@tags = tags
19+
@latest_verification_latest_tags = latest_verification_latest_tags
1920
end
2021

21-
def self.create consumer, provider, latest_pact, latest, latest_verification, webhooks = [], triggered_webhooks = [], tags = []
22-
new consumer, provider, latest_pact, latest, latest_verification, webhooks, triggered_webhooks, tags
22+
def self.create consumer, provider, latest_pact, latest, latest_verification, webhooks = [], triggered_webhooks = [], tags = [], latest_verification_latest_tags = []
23+
new consumer, provider, latest_pact, latest, latest_verification, webhooks, triggered_webhooks, tags, latest_verification_latest_tags
2324
end
2425

2526
def eq? other

lib/pact_broker/index/service.rb

+13-4
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ def self.find_index_items options = {}
2929
if options[:tags]
3030
tagged_rows = PactBroker::Matrix::Row
3131
.select_all_qualified
32-
.select_append(:tag_name)
33-
.join(:head_pact_publications, {id: :pact_publication_id})
32+
.select_append(Sequel[:head_pact_publications][:tag_name])
33+
.join(:head_pact_publications, {consumer_id: :consumer_id, provider_id: :provider_id, consumer_version_order: :consumer_version_order})
3434
.eager(:latest_triggered_webhooks)
3535
.eager(:webhooks)
3636
.order(:consumer_name, :provider_name)
3737
.eager(:consumer_version_tags)
38+
.eager(:latest_verification_tags)
3839

3940
if options[:tags].is_a?(Array)
4041
tagged_rows = tagged_rows.where(Sequel[:head_pact_publications][:tag_name] => options[:tags]).or(Sequel[:head_pact_publications][:tag_name] => nil)
@@ -43,7 +44,7 @@ def self.find_index_items options = {}
4344
tagged_rows = tagged_rows.all
4445
.group_by(&:pact_publication_id)
4546
.values
46-
.collect{|group| [group.first, group.collect{|r| r[:tag_name]}.compact] }
47+
.collect{|group| [group.last, group.collect{|r| r[:tag_name]}.compact] }
4748
.collect{ |(row, tag_names)| row.consumer_head_tag_names = tag_names; row }
4849

4950
rows = tagged_rows
@@ -59,7 +60,15 @@ def self.find_index_items options = {}
5960
end
6061
end
6162
previous_index_item_for_same_consumer_and_provider = index_items.last && index_items.last.consumer_name == row.consumer_name && index_items.last.provider_name == row.provider_name
62-
index_items << PactBroker::Domain::IndexItem.create(row.consumer, row.provider, row.pact, !previous_index_item_for_same_consumer_and_provider, row.latest_verification, row.webhooks, row.latest_triggered_webhooks, tag_names)
63+
index_items << PactBroker::Domain::IndexItem.create(row.consumer, row.provider,
64+
row.pact,
65+
!previous_index_item_for_same_consumer_and_provider,
66+
row.latest_verification,
67+
row.webhooks,
68+
row.latest_triggered_webhooks,
69+
tag_names,
70+
row.latest_verification_tags
71+
)
6372
end
6473

6574
index_items

lib/pact_broker/matrix/row.rb

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'pact_broker/repositories/helpers'
22
require 'pact_broker/webhooks/latest_triggered_webhook'
3+
require 'pact_broker/tags/latest_verification_tag'
34

45
module PactBroker
56
module Matrix
@@ -13,6 +14,7 @@ class Row < Sequel::Model(:matrix)
1314
# TODO modify this to work with single pacticipant webhooks
1415
associate(:one_to_many, :webhooks, :class => "PactBroker::Webhooks::Webhook", primary_key: [:consumer_id, :provider_id], key: [:consumer_id, :provider_id])
1516
associate(:one_to_many, :consumer_version_tags, :class => "PactBroker::Domain::Tag", primary_key: :consumer_version_id, key: :version_id)
17+
associate(:one_to_many, :latest_verification_tags, :class => "PactBroker::Tags::LatestVerificationTag", primary_key: :verification_id, key: :verification_id)
1618

1719
dataset_module do
1820
include PactBroker::Repositories::Helpers
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
require 'pact_broker/db'
2+
require 'pact_broker/repositories/helpers'
3+
4+
module PactBroker
5+
module Tags
6+
# The tag associated with the latest verification for a given tag
7+
class LatestVerificationTag < Sequel::Model
8+
9+
dataset_module do
10+
include PactBroker::Repositories::Helpers
11+
end
12+
end
13+
end
14+
end

spec/fixtures/dashboard.json

+11
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@
4646
}
4747
}
4848
],
49+
"latestVerificationResultTags": [
50+
{
51+
"name": "dev",
52+
"latest": true,
53+
"_links": {
54+
"self": {
55+
"href": "verification_dev_tag_url"
56+
}
57+
}
58+
}
59+
],
4960
"pact": {
5061
"_links": {
5162
"self": {

spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb

+13-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ module Decorators
2020
verification_status: 'wiffle',
2121
provider_version_number: provider_version.number,
2222
consumer_version_number: consumer_version.number,
23-
tag_names: ['prod']
23+
tag_names: ['prod'],
24+
latest_verification_latest_tags: [double('tag', name: 'dev')]
2425
)
2526
end
2627
let(:consumer) { instance_double('PactBroker::Domain::Pacticipant', name: 'Foo') }
@@ -42,10 +43,17 @@ module Decorators
4243
allow_any_instance_of(DashboardDecorator).to receive(:version_url).with(base_url, consumer_version).and_return('consumer_version_url')
4344
allow_any_instance_of(DashboardDecorator).to receive(:webhooks_status_url).with(consumer, provider, base_url).and_return('webhooks_status_url')
4445
allow_any_instance_of(DashboardDecorator).to receive(:tag_url) do | instance, base_url, tag |
45-
expect(tag.name).to eq 'prod'
46-
expect(tag.version).to be consumer_version
47-
expect(base_url).to eq base_url
48-
'pact_prod_tag_url'
46+
if tag.version == consumer_version
47+
expect(tag.name).to eq 'prod'
48+
expect(tag.version).to be consumer_version
49+
expect(base_url).to eq base_url
50+
'pact_prod_tag_url'
51+
else
52+
expect(tag.name).to eq 'dev'
53+
expect(tag.version).to be provider_version
54+
expect(base_url).to eq base_url
55+
'verification_dev_tag_url'
56+
end
4957
end
5058
end
5159

spec/lib/pact_broker/index/service_spec.rb

+17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module Index
2424
.create_consumer_version_tag("also-ignored")
2525
.create_pact
2626
.create_verification(provider_version: "2.1.0")
27+
.use_provider_version("2.1.0")
2728
end
2829

2930
let(:rows) { subject.find_index_items(options) }
@@ -93,6 +94,22 @@ module Index
9394
expect(rows.first.latest_verification.provider_version_number).to eq '2.0.0'
9495
end
9596
end
97+
98+
context "when the verification is the latest for a given tag" do
99+
before do
100+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
101+
.create_verification(provider_version: "1.0.0", tag_names: ['dev', 'prod'])
102+
.create_verification(provider_version: "2.0.0", number: 2, tag_names: ['dev'])
103+
end
104+
105+
let(:rows) { subject.find_index_items(options) }
106+
let(:options) { { tags: true } }
107+
108+
it "includes the names of the tags for which the verification is the latest of that tag" do
109+
expect(rows.first.provider_version_number).to eq "2.0.0"
110+
expect(rows.first.latest_verification_latest_tags.collect(&:name)).to eq ['dev']
111+
end
112+
end
96113
end
97114
end
98115
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
describe 'latest tagged verifications', migration: true do
2+
before do
3+
PactBroker::Database.migrate(20180123)
4+
end
5+
6+
let(:now) { DateTime.new(2018, 2, 2) }
7+
let!(:consumer) { create(:pacticipants, {name: 'C', created_at: now, updated_at: now}) }
8+
let!(:provider) { create(:pacticipants, {name: 'P', created_at: now, updated_at: now}) }
9+
let!(:consumer_version_1) { create(:versions, {number: '1', order: 1, pacticipant_id: consumer[:id], created_at: now, updated_at: now}) }
10+
let!(:consumer_version_2) { create(:versions, {number: '2', order: 2, pacticipant_id: consumer[:id], created_at: now, updated_at: now}) }
11+
12+
let!(:provider_version_1) { create(:versions, {number: '1', order: 1, pacticipant_id: provider[:id], created_at: now, updated_at: now}) }
13+
let!(:provider_version_2) { create(:versions, {number: '2', order: 2, pacticipant_id: provider[:id], created_at: now, updated_at: now}) }
14+
let!(:provider_version_3) { create(:versions, {number: '3', order: 3, pacticipant_id: provider[:id], created_at: now, updated_at: now}) }
15+
16+
let!(:provider_version_1_prod_tag) { create(:tags, {version_id: provider_version_1[:id], name: 'prod', created_at: now, updated_at: now}, nil) }
17+
let!(:provider_version_1_dev_tag) { create(:tags, {version_id: provider_version_1[:id], name: 'dev', created_at: now, updated_at: now}, nil) }
18+
let!(:provider_version_2_dev_tag) { create(:tags, {version_id: provider_version_2[:id], name: 'dev', created_at: now, updated_at: now}, nil) }
19+
20+
let!(:pact_version_1) { create(:pact_versions, {content: {some: 'json'}.to_json, sha: '1', consumer_id: consumer[:id], provider_id: provider[:id], created_at: now}) }
21+
let!(:pact_version_2) { create(:pact_versions, {content: {some: 'json other'}.to_json, sha: '2', consumer_id: consumer[:id], provider_id: provider[:id], created_at: now}) }
22+
#let!(:pact_version_3) { create(:pact_versions, {content: {some: 'json more'}.to_json, sha: '3', consumer_id: consumer[:id], provider_id: provider[:id], created_at: now}) }
23+
let!(:pact_publication_1) do
24+
create(:pact_publications, {
25+
consumer_version_id: consumer_version_1[:id],
26+
provider_id: provider[:id],
27+
revision_number: 1,
28+
pact_version_id: pact_version_1[:id],
29+
created_at: now
30+
})
31+
end
32+
33+
let!(:pact_publication_2) do
34+
create(:pact_publications, {
35+
consumer_version_id: consumer_version_2[:id],
36+
provider_id: provider[:id],
37+
revision_number: 1,
38+
pact_version_id: pact_version_2[:id],
39+
created_at: now
40+
})
41+
end
42+
43+
# provider v1
44+
let!(:verification_1) do
45+
create(:verifications, {
46+
number: 1,
47+
success: true,
48+
provider_version_id: provider_version_1[:id],
49+
pact_version_id: pact_version_1[:id],
50+
execution_date: now,
51+
created_at: now
52+
})
53+
end
54+
55+
# provider v2
56+
let!(:verification_2) do
57+
create(:verifications, {
58+
number: 2,
59+
success: true,
60+
provider_version_id: provider_version_2[:id],
61+
pact_version_id: pact_version_1[:id],
62+
execution_date: now,
63+
created_at: now
64+
})
65+
end
66+
67+
# provider v2
68+
let!(:verification_3) do
69+
create(:verifications, {
70+
number: 3,
71+
success: true,
72+
provider_version_id: provider_version_2[:id],
73+
pact_version_id: pact_version_1[:id],
74+
execution_date: now,
75+
created_at: now
76+
})
77+
end
78+
79+
it "includes the tag rows for which the related verification is the latest of that tag" do
80+
rows = database[:latest_verification_tags].all
81+
expect(rows).to contain_hash(verification_id: verification_1[:id], name: 'prod')
82+
expect(rows).to contain_hash(verification_id: verification_3[:id], name: 'dev')
83+
expect(rows.size).to eq 2
84+
end
85+
end

spec/support/migration_helpers.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module MigrationHelpers
44
def create table_name, params, id_column_name = :id
55
database[table_name].insert(params);
6-
database[table_name].order(id_column_name).last
6+
database[table_name].order(id_column_name).last if id_column_name
77
end
88

99
def clean table_name

spec/support/rspec_match_hash.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88

99

1010
def contains_hash?(expected, actual)
11-
expected.all? do |key, value|
12-
unordered_match(actual[key], value)
11+
if actual.is_a?(Array)
12+
actual.any? && actual.any?{|actual_item| contains_hash?(expected, actual_item)}
13+
else
14+
expected.all? do |key, value|
15+
unordered_match(actual[key], value)
16+
end
1317
end
1418
end
1519

spec/support/test_data_builder.rb

+7
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,19 @@ def create_deprecated_webhook_execution params = {}
240240
end
241241

242242
def create_verification parameters = {}
243+
tag_names = [parameters.delete(:tag_names), parameters.delete(:tag_name)].flatten.compact
243244
provider_version_number = parameters[:provider_version] || '4.5.6'
244245
default_parameters = {success: true, number: 1, test_results: {some: 'results'}}
245246
parameters = default_parameters.merge(parameters)
246247
parameters.delete(:provider_version)
247248
verification = PactBroker::Domain::Verification.new(parameters)
248249
@verification = PactBroker::Verifications::Repository.new.create(verification, provider_version_number, @pact)
250+
if tag_names.any?
251+
provider_version = PactBroker::Domain::Version.where(pacticipant_id: @provider.id, number: provider_version_number).single_record
252+
tag_names.each do | tag_name |
253+
PactBroker::Domain::Tag.create(name: tag_name, version: provider_version)
254+
end
255+
end
249256
self
250257
end
251258

0 commit comments

Comments
 (0)