Skip to content

Commit 924aaae

Browse files
committed
feat(dashboard api): fix query for displaying dashboard with tags
1 parent 9a24e2a commit 924aaae

File tree

11 files changed

+333
-43
lines changed

11 files changed

+333
-43
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Sequel.migration do
2+
up do
3+
# a row for each of the latest pact publications,
4+
# and a row for each of the latest tagged pact publications
5+
create_view(:head_matrix,
6+
"SELECT matrix.*, hpp.tag_name as consumer_tag_name
7+
FROM latest_matrix_for_consumer_version_and_provider_version matrix
8+
INNER JOIN head_pact_publications hpp
9+
ON matrix.consumer_id = hpp.consumer_id
10+
AND matrix.provider_id = hpp.provider_id
11+
AND matrix.consumer_version_order = hpp.consumer_version_order
12+
INNER JOIN latest_verification_id_for_consumer_version_and_provider AS lv
13+
ON ((matrix.consumer_version_id = lv.consumer_version_id)
14+
AND (matrix.provider_id = lv.provider_id)
15+
AND ((matrix.verification_id = lv.latest_verification_id)))
16+
17+
UNION
18+
19+
SELECT matrix.*, hpp.tag_name as consumer_tag_name
20+
FROM latest_matrix_for_consumer_version_and_provider_version matrix
21+
INNER JOIN head_pact_publications hpp
22+
ON matrix.consumer_id = hpp.consumer_id
23+
AND matrix.provider_id = hpp.provider_id
24+
AND matrix.consumer_version_order = hpp.consumer_version_order
25+
where verification_id is null
26+
"
27+
)
28+
end
29+
30+
down do
31+
drop_view(:head_matrix)
32+
end
33+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Sequel.migration do
2+
up do
3+
create_table(:materialized_head_matrix, charset: 'utf8') do
4+
Integer :consumer_id, null: false
5+
String :consumer_name, null: false
6+
Integer :consumer_version_id, null: false
7+
String :consumer_version_number, null: false
8+
Integer :consumer_version_order, null: false
9+
Integer :pact_publication_id, null: false
10+
Integer :pact_version_id, null: false
11+
String :pact_version_sha, null: false
12+
Integer :pact_revision_number, null: false
13+
DateTime :pact_created_at, null: false
14+
Integer :provider_id, null: false
15+
String :provider_name, null: false
16+
Integer :provider_version_id
17+
String :provider_version_number
18+
Integer :provider_version_order
19+
Integer :verification_id
20+
Boolean :success
21+
Integer :verification_number
22+
DateTime :verification_executed_at
23+
String :verification_build_url
24+
String :consumer_tag_name
25+
index [:consumer_id], name: 'ndx_mhm_consumer_id'
26+
index [:provider_id], name: 'ndx_mhm_provider_id'
27+
index [:consumer_version_order], name: 'ndx_mhm_cv_ord'
28+
end
29+
30+
from(:materialized_head_matrix).insert(from(:head_matrix).select_all)
31+
end
32+
33+
down do
34+
drop_table(:materialized_head_matrix)
35+
end
36+
end

lib/pact_broker/api/resources/dashboard.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def to_text
3030
private
3131

3232
def index_items
33-
index_service.find_index_items
33+
index_service.find_index_items(tags: true)
3434
end
3535
end
3636
end

lib/pact_broker/domain/index_item.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def <=> other
128128
end
129129

130130
def to_s
131-
"Pact between #{consumer_name} and #{provider_name}"
131+
"Pact between #{consumer_name} #{consumer_version_number} and #{provider_name} #{provider_version_number}"
132132
end
133133

134134
def to_a

lib/pact_broker/index/service.rb

+31-32
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'pact_broker/domain/index_item'
44
require 'pact_broker/matrix/latest_row'
55
require 'pact_broker/matrix/actual_latest_row'
6+
require 'pact_broker/matrix/head_row'
67

78
module PactBroker
89

@@ -13,63 +14,61 @@ class Service
1314
extend PactBroker::Services
1415
extend PactBroker::Logging
1516

17+
# Used when using table_print to output query results
18+
TP_COLS = [:consumer_name, :consumer_version_number, :consumer_version_id, :provider_name, :provider_id, :provider_version_number]
19+
1620
def self.find_index_items options = {}
1721
rows = []
22+
overall_latest_publication_ids = nil
1823

19-
if !options[:tags]
20-
rows = PactBroker::Matrix::ActualLatestRow
24+
rows = PactBroker::Matrix::HeadRow
2125
.select_all_qualified
2226
.eager(:latest_triggered_webhooks)
2327
.eager(:webhooks)
2428
.order(:consumer_name, :provider_name)
2529
.eager(:consumer_version_tags)
2630
.eager(:provider_version_tags)
27-
.all
31+
32+
if !options[:tags]
33+
rows = rows.where(consumer_tag_name: nil).all
34+
overall_latest_publication_ids = rows.collect(&:pact_publication_id)
2835
end
2936

3037
if options[:tags]
31-
tagged_rows = PactBroker::Matrix::Row
32-
.select_all_qualified
33-
.select_append(Sequel[:head_pact_publications][:tag_name])
34-
.join(:head_pact_publications, {consumer_id: :consumer_id, provider_id: :provider_id, consumer_version_order: :consumer_version_order})
35-
.eager(:latest_triggered_webhooks)
36-
.eager(:webhooks)
37-
.order(:consumer_name, :provider_name)
38-
.eager(:consumer_version_tags)
39-
.eager(:provider_version_tags)
40-
41-
if options[:tags].is_a?(Array)
42-
tagged_rows = tagged_rows.where(Sequel[:head_pact_publications][:tag_name] => options[:tags]).or(Sequel[:head_pact_publications][:tag_name] => nil)
43-
end
44-
45-
tagged_rows = tagged_rows.all
46-
.group_by(&:pact_publication_id)
47-
.values
48-
.collect{|group| [group.last, group.collect{|r| r[:tag_name]}.compact] }
49-
.collect{ |(row, tag_names)| row.consumer_head_tag_names = tag_names; row }
50-
51-
rows = tagged_rows
38+
if options[:tags].is_a?(Array)
39+
rows = rows.where(consumer_tag_name: options[:tags]).or(consumer_tag_name: nil)
40+
end
41+
42+
rows = rows.all
43+
overall_latest_publication_ids = rows.select{|r| !r[:consumer_tag_name] }.collect(&:pact_publication_id).uniq
44+
45+
# Smoosh all the rows with matching pact publications together
46+
# and collect their consumer_head_tag_names
47+
rows = rows
48+
.group_by(&:pact_publication_id)
49+
.values
50+
.collect{|group| [group.last, group.collect{|r| r[:consumer_tag_name]}.compact] }
51+
.collect{ |(row, tag_names)| row.consumer_head_tag_names = tag_names; row }
5252
end
5353

5454
index_items = []
5555
rows.sort.each do | row |
5656
tag_names = []
5757
if options[:tags]
5858
tag_names = row.consumer_version_tags.collect(&:name)
59-
if options[:tags].is_a?(Array)
60-
tag_names = tag_names & options[:tags]
61-
end
6259
end
63-
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
64-
index_items << PactBroker::Domain::IndexItem.create(row.consumer, row.provider,
60+
61+
index_items << PactBroker::Domain::IndexItem.create(
62+
row.consumer,
63+
row.provider,
6564
row.pact,
66-
!previous_index_item_for_same_consumer_and_provider,
65+
overall_latest_publication_ids.include?(row.pact_publication_id),
6766
row.latest_verification,
6867
row.webhooks,
6968
row.latest_triggered_webhooks,
70-
tag_names,
69+
row.consumer_head_tag_names,
7170
row.provider_version_tags.select(&:latest?)
72-
)
71+
)
7372
end
7473

7574
index_items

lib/pact_broker/matrix/head_row.rb

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
require 'pact_broker/matrix/row'
2+
3+
module PactBroker
4+
module Matrix
5+
# A row for each of the overall latest pacts, and a row for each of the latest tagged pacts
6+
class HeadRow < Row
7+
set_dataset(:materialized_head_matrix)
8+
end
9+
end
10+
end

lib/pact_broker/matrix/repository.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'pact_broker/repositories/helpers'
22
require 'pact_broker/matrix/row'
33
require 'pact_broker/matrix/latest_row'
4+
require 'pact_broker/matrix/head_row'
45
require 'pact_broker/error'
56

67
module PactBroker
@@ -19,8 +20,7 @@ class Repository
1920
GROUP_BY_PACT = [:consumer_name, :provider_name]
2021

2122
def refresh params
22-
PactBroker::Matrix::Row.refresh(params)
23-
PactBroker::Matrix::ActualLatestRow.refresh(params)
23+
PactBroker::Matrix::HeadRow.refresh(params)
2424
end
2525

2626
# Return the latest matrix row (pact/verification) for each consumer_version_number/provider_version_number

lib/pact_broker/matrix/row.rb

+14
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,20 @@ def compare_number_desc number1, number2
192192
-1
193193
end
194194
end
195+
196+
# For some reason, with MySQL, the success column value
197+
# comes back as an integer rather than a boolean
198+
# for the latest_matrix view (but not the matrix view!)
199+
# Maybe something to do with the union?
200+
# Haven't investigated as this is an easy enough fix.
201+
def success
202+
value = super
203+
value.nil? ? nil : value == true || value == 1
204+
end
205+
206+
def values
207+
super.merge(success: success)
208+
end
195209
end
196210
end
197211
end

spec/lib/pact_broker/index/service_spec.rb

+70-7
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,79 @@ module Index
113113
end
114114

115115
context "when there are multiple verifications for the latest consumer version" do
116-
before do
117-
td.create_pact_with_hierarchy("Foo", "1", "Bar")
118-
.create_verification(provider_version: "1.0.0")
119-
.create_verification(provider_version: "2.0.0", number: 2)
116+
117+
context "with no tags" do
118+
before do
119+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
120+
.create_verification(provider_version: "1.0.0")
121+
.create_verification(provider_version: "2.0.0", number: 2)
122+
end
123+
124+
let(:options) { {} }
125+
126+
it "only returns the row for the latest provider version" do
127+
expect(rows.count).to eq 1
128+
end
120129
end
121130

122-
let(:options) { {} }
131+
context "with tags=true" do
132+
before do
133+
td.create_pact_with_hierarchy("Foo", "1", "Bar")
134+
.create_consumer_version("2")
135+
.create_consumer_version_tag("prod")
136+
.create_consumer_version_tag("master")
137+
.create_pact
138+
.revise_pact
139+
.create_verification(provider_version: "1.0.0")
140+
.create_verification(provider_version: "2.0.0", number: 2)
141+
end
123142

124-
it "only returns the row for the latest provider version" do
125-
expect(rows.count).to eq 1
143+
let(:options) { {tags: true} }
144+
145+
it "only returns the row for the latest provider version" do
146+
expect(rows.size).to eq 1
147+
expect(rows.first.tag_names.sort).to eq ["master","prod"]
148+
expect(rows.first.provider_version_number).to eq "2.0.0"
149+
end
150+
end
151+
152+
context "with tags=true" do
153+
before do
154+
td.create_pact_with_hierarchy("Foo", "1.0.0", "Bar")
155+
.create_verification(provider_version: "4.5.6")
156+
.create_consumer_version("2.0.0")
157+
.create_consumer_version_tag("dev")
158+
.create_pact
159+
.revise_pact
160+
.create_consumer_version("2.1.0")
161+
.create_consumer_version_tag("prod")
162+
.create_pact
163+
.revise_pact
164+
.create_verification(provider_version: "4.5.6", number: 1)
165+
.create_verification(provider_version: "4.5.7", number: 2)
166+
.create_verification(provider_version: "4.5.8", number: 3)
167+
.create_verification(provider_version: "4.5.9", number: 4)
168+
.create_provider("Wiffle")
169+
.create_pact
170+
end
171+
172+
let(:options) { {tags: true} }
173+
174+
it "returns a row for each of the head pacts" do
175+
expect(rows.size).to eq 3
176+
177+
expect(rows[0].latest?).to be true
178+
expect(rows[0].provider_name).to eq "Bar"
179+
expect(rows[0].tag_names).to eq ["prod"]
180+
expect(rows[0].provider_version_number).to eq "4.5.9"
181+
182+
expect(rows[2].latest?).to be false
183+
expect(rows[2].provider_name).to eq "Bar"
184+
expect(rows[2].tag_names).to eq ["dev"]
185+
186+
expect(rows[1].latest?).to be true
187+
expect(rows[1].provider_name).to eq "Wiffle"
188+
end
126189
end
127190
end
128191
end

0 commit comments

Comments
 (0)