pact_broker 2.38.1 → 2.39.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +2 -2
- data/CHANGELOG.md +45 -0
- data/DEVELOPER_DOCUMENTATION.md +9 -0
- data/Dockerfile +2 -0
- data/Gemfile +1 -1
- data/README.md +10 -3
- data/config/database.yml +10 -2
- data/docs/images/Pactflow logo - black small.png +0 -0
- data/lib/pact_broker/api.rb +5 -2
- data/lib/pact_broker/api/contracts/verifiable_pacts_query_schema.rb +41 -0
- data/lib/pact_broker/api/decorators/dashboard_decorator.rb +1 -1
- data/lib/pact_broker/api/decorators/dashboard_text_decorator.rb +1 -1
- data/lib/pact_broker/api/decorators/integration_decorator.rb +2 -0
- data/lib/pact_broker/api/decorators/verifiable_pact_decorator.rb +34 -0
- data/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator.rb +27 -0
- data/lib/pact_broker/api/resources/badge.rb +4 -4
- data/lib/pact_broker/api/resources/can_i_deploy.rb +41 -0
- data/lib/pact_broker/api/resources/dashboard.rb +1 -1
- data/lib/pact_broker/api/resources/index.rb +15 -4
- data/lib/pact_broker/api/resources/latest_pact.rb +10 -4
- data/lib/pact_broker/api/resources/latest_verification_for_latest_pact.rb +19 -0
- data/lib/pact_broker/api/resources/pact.rb +5 -4
- data/lib/pact_broker/api/resources/provider_pacts_for_verification.rb +54 -0
- data/lib/pact_broker/api/resources/verification.rb +6 -1
- data/lib/pact_broker/badges/service.rb +11 -11
- data/lib/pact_broker/db/clean.rb +72 -12
- data/lib/pact_broker/doc/controllers/app.rb +3 -1
- data/lib/pact_broker/doc/views/can-i-deploy.markdown +14 -0
- data/lib/pact_broker/doc/views/index/pacticipant-version-tag.markdown +8 -0
- data/lib/pact_broker/doc/views/integrations.markdown +1 -1
- data/lib/pact_broker/doc/views/matrix.markdown +7 -0
- data/lib/pact_broker/doc/views/metrics.markdown +5 -0
- data/lib/pact_broker/domain/index_item.rb +3 -3
- data/lib/pact_broker/domain/pact.rb +28 -1
- data/lib/pact_broker/index/service.rb +38 -20
- data/lib/pact_broker/integrations/integration.rb +16 -0
- data/lib/pact_broker/integrations/service.rb +15 -1
- data/lib/pact_broker/matrix/can_i_deploy_query_schema.rb +25 -0
- data/lib/pact_broker/matrix/parse_can_i_deploy_query.rb +29 -0
- data/lib/pact_broker/matrix/quick_row.rb +255 -0
- data/lib/pact_broker/matrix/repository.rb +5 -17
- data/lib/pact_broker/matrix/row.rb +0 -1
- data/lib/pact_broker/metrics/service.rb +36 -2
- data/lib/pact_broker/pacts/all_pact_publications.rb +3 -2
- data/lib/pact_broker/pacts/head_pact.rb +30 -0
- data/lib/pact_broker/pacts/latest_pact_publications.rb +8 -1
- data/lib/pact_broker/pacts/latest_tagged_pact_publications.rb +5 -1
- data/lib/pact_broker/pacts/pact_publication.rb +2 -1
- data/lib/pact_broker/pacts/pact_version.rb +20 -0
- data/lib/pact_broker/pacts/repository.rb +33 -4
- data/lib/pact_broker/pacts/service.rb +15 -2
- data/lib/pact_broker/pacts/squash_pacts_for_verification.rb +37 -0
- data/lib/pact_broker/pacts/verifiable_pact.rb +30 -0
- data/lib/pact_broker/pacts/verifiable_pact_messages.rb +75 -0
- data/lib/pact_broker/test/test_data_builder.rb +30 -2
- data/lib/pact_broker/ui/view_models/index_item.rb +4 -4
- data/lib/pact_broker/ui/view_models/matrix_line.rb +1 -1
- data/lib/pact_broker/ui/views/index/show-with-tags.haml +1 -1
- data/lib/pact_broker/ui/views/index/show.haml +1 -1
- data/lib/pact_broker/ui/views/matrix/show.haml +2 -2
- data/lib/pact_broker/verifications/{verification_status.rb → pseudo_branch_status.rb} +10 -4
- data/lib/pact_broker/version.rb +1 -1
- data/script/docker/mysql-db-start.sh +10 -0
- data/spec/features/can_i_deploy_spec.rb +31 -0
- data/spec/features/get_latest_verification_for_pact_spec.rb +17 -0
- data/spec/features/get_provider_pacts_for_verification_spec.rb +39 -0
- data/spec/features/metrics_spec.rb +1 -1
- data/spec/features/pending_pacts_spec.rb +109 -0
- data/spec/integration/ui/matrix_spec.rb +30 -0
- data/spec/lib/pact_broker/api/contracts/verifiable_pacts_query_schema_spec.rb +62 -0
- data/spec/lib/pact_broker/api/decorators/dashboard_decorator_spec.rb +1 -1
- data/spec/lib/pact_broker/api/decorators/integration_decorator_spec.rb +5 -1
- data/spec/lib/pact_broker/api/decorators/verifiable_pact_decorator_spec.rb +30 -5
- data/spec/lib/pact_broker/api/decorators/verifiable_pacts_query_decorator_spec.rb +46 -0
- data/spec/lib/pact_broker/api/resources/badge_spec.rb +3 -3
- data/spec/lib/pact_broker/api/resources/provider_pacts_for_verification_spec.rb +35 -0
- data/spec/lib/pact_broker/api/resources/verification_spec.rb +18 -0
- data/spec/lib/pact_broker/badges/service_spec.rb +18 -18
- data/spec/lib/pact_broker/db/clean_spec.rb +69 -8
- data/spec/lib/pact_broker/doc/coverage_spec.rb +8 -2
- data/spec/lib/pact_broker/index/service_spec.rb +28 -14
- data/spec/lib/pact_broker/integrations/integration_spec.rb +60 -0
- data/spec/lib/pact_broker/integrations/service_spec.rb +27 -0
- data/spec/lib/pact_broker/matrix/quick_row_spec.rb +31 -0
- data/spec/lib/pact_broker/matrix/repository_spec.rb +8 -8
- data/spec/lib/pact_broker/matrix/service_spec.rb +4 -4
- data/spec/lib/pact_broker/metrics/service_spec.rb +56 -0
- data/spec/lib/pact_broker/pacts/pact_version_spec.rb +69 -0
- data/spec/lib/pact_broker/pacts/repository_find_for_verification_spec.rb +65 -0
- data/spec/lib/pact_broker/pacts/repository_find_wip_pact_versions_for_provider_spec.rb +54 -24
- data/spec/lib/pact_broker/pacts/service_find_for_verification_spec.rb +51 -0
- data/spec/lib/pact_broker/pacts/squash_pacts_for_verification_spec.rb +92 -0
- data/spec/lib/pact_broker/pacts/verifiable_pact_messages_spec.rb +93 -0
- data/spec/lib/pact_broker/pacts/verifiable_pact_spec.rb +0 -0
- data/spec/lib/pact_broker/ui/view_models/index_item_spec.rb +10 -10
- data/spec/lib/pact_broker/verifications/{verification_status_spec.rb → pseudo_branch_status_spec.rb} +4 -4
- data/spec/support/shared_examples_for_responses.rb +7 -1
- metadata +56 -13
- data/lib/pact_broker/api/resources/pending_provider_pacts.rb +0 -21
- data/spec/features/get_pacts_to_verify_spec.rb +0 -41
- data/spec/features/get_wip_provider_pacts_spec.rb +0 -26
- data/spec/lib/pact_broker/api/resources/pending_provider_pacts_spec.rb +0 -34
@@ -13,51 +13,41 @@ module PactBroker
|
|
13
13
|
extend PactBroker::Services
|
14
14
|
extend PactBroker::Logging
|
15
15
|
|
16
|
+
# This method provides data for both the OSS server side rendered index (with and without tags)
|
17
|
+
# and the Pactflow UI. It really needs to be broken into to separate methods, as it's getting too messy
|
18
|
+
# supporting both
|
19
|
+
|
16
20
|
def self.find_index_items options = {}
|
17
21
|
rows = PactBroker::Matrix::HeadRow
|
18
22
|
.select_all_qualified
|
19
23
|
.eager(:latest_triggered_webhooks)
|
20
24
|
.eager(:webhooks)
|
21
25
|
|
22
|
-
rows = rows.consumer(options[:consumer_name]) if options[:consumer_name]
|
23
|
-
rows = rows.provider(options[:provider_name]) if options[:provider_name]
|
24
|
-
|
25
26
|
if !options[:tags]
|
27
|
+
# server side rendered index page without tags
|
26
28
|
rows = rows.where(consumer_version_tag_name: nil)
|
27
29
|
else
|
30
|
+
# server side rendered index page with tags=true or tags[]=a&tags=[]b
|
28
31
|
if options[:tags].is_a?(Array)
|
29
32
|
rows = rows.where(consumer_version_tag_name: options[:tags]).or(consumer_version_tag_name: nil)
|
30
33
|
end
|
31
34
|
rows = rows.eager(:consumer_version_tags)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
.eager(:provider_version_tags)
|
36
|
+
.eager(:latest_verification_for_consumer_version_tag)
|
37
|
+
.eager(:latest_verification_for_consumer_and_provider)
|
35
38
|
end
|
36
39
|
rows = rows.all.group_by(&:pact_publication_id).values.collect{ | rows| Matrix::AggregatedRow.new(rows) }
|
37
40
|
|
38
41
|
|
39
42
|
|
40
43
|
rows.sort.collect do | row |
|
41
|
-
# The concept of "stale" (the pact used to be verified but then it changed and we haven't got
|
42
|
-
# a new verification result yet) only really make sense if we're trying to summarise
|
43
|
-
# the latest state of an integration. Once we start showing multiple pacts for each
|
44
|
-
# integration (ie. the latest for each tag) then each pact version is either verified,
|
45
|
-
# or it's not verified.
|
46
|
-
# For backwards compatiblity with the existing UI, don't change the 'stale' concept for the OSS
|
47
|
-
# UI - just ensure we don't use it for the new dashboard endpoint with the consumer/provider specified.
|
48
|
-
latest_verification = if options[:dashboard]
|
49
|
-
row.latest_verification_for_pact_version
|
50
|
-
else
|
51
|
-
row.latest_verification_for_pseudo_branch
|
52
|
-
end
|
53
|
-
|
54
44
|
# TODO simplify. Do we really need 3 layers of abstraction?
|
55
45
|
PactBroker::Domain::IndexItem.create(
|
56
46
|
row.consumer,
|
57
47
|
row.provider,
|
58
48
|
row.pact,
|
59
49
|
row.overall_latest?,
|
60
|
-
|
50
|
+
row.latest_verification_for_pseudo_branch,
|
61
51
|
row.webhooks,
|
62
52
|
row.latest_triggered_webhooks,
|
63
53
|
options[:tags] ? row.consumer_head_tag_names : [],
|
@@ -65,6 +55,34 @@ module PactBroker
|
|
65
55
|
)
|
66
56
|
end
|
67
57
|
end
|
58
|
+
|
59
|
+
def self.find_index_items_for_api(consumer_name: nil, provider_name: nil, **ignored)
|
60
|
+
rows = PactBroker::Matrix::HeadRow
|
61
|
+
.eager(:consumer_version_tags)
|
62
|
+
.eager(:provider_version_tags)
|
63
|
+
.select_all_qualified
|
64
|
+
|
65
|
+
rows = rows.consumer(consumer_name) if consumer_name
|
66
|
+
rows = rows.provider(provider_name) if provider_name
|
67
|
+
|
68
|
+
rows = rows.all.group_by(&:pact_publication_id).values.collect{ | rows| Matrix::AggregatedRow.new(rows) }
|
69
|
+
|
70
|
+
rows.sort.collect do | row |
|
71
|
+
# TODO separate this model from IndexItem
|
72
|
+
# webhook status not currently displayed in Pactflow UI, so don't query for it.
|
73
|
+
PactBroker::Domain::IndexItem.create(
|
74
|
+
row.consumer,
|
75
|
+
row.provider,
|
76
|
+
row.pact,
|
77
|
+
row.overall_latest?,
|
78
|
+
row.latest_verification_for_pact_version,
|
79
|
+
[],
|
80
|
+
[],
|
81
|
+
row.consumer_head_tag_names,
|
82
|
+
row.provider_version_tags.select(&:latest?)
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
68
86
|
end
|
69
87
|
end
|
70
88
|
end
|
@@ -1,10 +1,26 @@
|
|
1
1
|
require 'pact_broker/db'
|
2
|
+
require 'pact_broker/verifications/pseudo_branch_status'
|
3
|
+
require 'pact_broker/domain/verification'
|
2
4
|
|
3
5
|
module PactBroker
|
4
6
|
module Integrations
|
5
7
|
class Integration < Sequel::Model
|
6
8
|
associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
|
7
9
|
associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
|
10
|
+
associate(:one_to_one, :latest_pact, :class => "PactBroker::Pacts::LatestPactPublications", key: [:consumer_id, :provider_id], primary_key: [:consumer_id, :provider_id])
|
11
|
+
associate(:one_to_one, :latest_verification, :class => "PactBroker::Verifications::LatestVerificationForConsumerAndProvider", key: [:consumer_id, :provider_id], primary_key: [:consumer_id, :provider_id])
|
12
|
+
|
13
|
+
def verification_status_for_latest_pact
|
14
|
+
@verification_status_for_latest_pact ||= PactBroker::Verifications::PseudoBranchStatus.new(latest_pact, latest_pact&.latest_verification)
|
15
|
+
end
|
16
|
+
|
17
|
+
def latest_pact_or_verification_publication_date
|
18
|
+
[latest_pact.created_at, latest_verification_publication_date].compact.max
|
19
|
+
end
|
20
|
+
|
21
|
+
def latest_verification_publication_date
|
22
|
+
latest_verification&.execution_date
|
23
|
+
end
|
8
24
|
end
|
9
25
|
end
|
10
26
|
end
|
@@ -11,7 +11,21 @@ module PactBroker
|
|
11
11
|
include PactBroker::Logging
|
12
12
|
|
13
13
|
def self.find_all
|
14
|
-
|
14
|
+
# The only reason the pact_version needs to be loaded is that
|
15
|
+
# the Verification::PseudoBranchStatus uses it to determine if
|
16
|
+
# the pseudo branch is 'stale'.
|
17
|
+
# Because this is the status for a pact, and not a pseudo branch,
|
18
|
+
# the status can never be 'stale',
|
19
|
+
# so it would be better to create a Verification::PactStatus class
|
20
|
+
# that doesn't have the 'stale' logic in it.
|
21
|
+
# Then we can remove the eager loading of the pact_version
|
22
|
+
PactBroker::Integrations::Integration
|
23
|
+
.eager(:consumer)
|
24
|
+
.eager(:provider)
|
25
|
+
.eager(latest_pact: [:latest_verification, :pact_version])
|
26
|
+
.eager(:latest_verification)
|
27
|
+
.all
|
28
|
+
.sort { | a, b| b.latest_pact_or_verification_publication_date <=> a.latest_pact_or_verification_publication_date }
|
15
29
|
end
|
16
30
|
|
17
31
|
def self.delete(consumer_name, provider_name)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'dry-validation'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Api
|
5
|
+
module Contracts
|
6
|
+
class CanIDeployQuerySchema
|
7
|
+
SCHEMA = Dry::Validation.Schema do
|
8
|
+
required(:pacticipant).filled(:str?)
|
9
|
+
required(:version).filled(:str?)
|
10
|
+
optional(:to).filled(:str?)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.call(params)
|
14
|
+
select_first_message(SCHEMA.call(params).messages(full: true))
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.select_first_message(messages)
|
18
|
+
messages.each_with_object({}) do | (key, value), new_messages |
|
19
|
+
new_messages[key] = [value.first]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Matrix
|
5
|
+
class ParseCanIDeployQuery
|
6
|
+
def self.call params
|
7
|
+
selector = {}
|
8
|
+
options = {
|
9
|
+
latestby: 'cvp',
|
10
|
+
latest: true
|
11
|
+
}
|
12
|
+
|
13
|
+
if params[:pacticipant].is_a?(String)
|
14
|
+
selector[:pacticipant_name] = params[:pacticipant]
|
15
|
+
end
|
16
|
+
|
17
|
+
if params[:version].is_a?(String)
|
18
|
+
selector[:pacticipant_version_number] = params[:version]
|
19
|
+
end
|
20
|
+
|
21
|
+
if params[:to].is_a?(String)
|
22
|
+
options[:tag] = params[:to]
|
23
|
+
end
|
24
|
+
|
25
|
+
return [selector], options
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
=begin
|
2
|
+
The Matrix::Row is based on the matrix view which does a join of every pact/verification
|
3
|
+
and then selects the relevant ones.
|
4
|
+
|
5
|
+
The Matrix::QuickRow starts with the relevant rows, and builds the matrix query from that,
|
6
|
+
making it much quicker.
|
7
|
+
|
8
|
+
=end
|
9
|
+
require 'sequel'
|
10
|
+
require 'pact_broker/repositories/helpers'
|
11
|
+
require 'pact_broker/logging'
|
12
|
+
require 'pact_broker/pacts/pact_version'
|
13
|
+
require 'pact_broker/domain/pacticipant'
|
14
|
+
require 'pact_broker/domain/version'
|
15
|
+
require 'pact_broker/domain/verification'
|
16
|
+
require 'pact_broker/pacts/pact_publication'
|
17
|
+
require 'pact_broker/tags/tag_with_latest_flag'
|
18
|
+
|
19
|
+
module PactBroker
|
20
|
+
module Matrix
|
21
|
+
LV = :latest_verification_id_for_pact_version_and_provider_version
|
22
|
+
LP = :latest_pact_publication_ids_for_consumer_versions
|
23
|
+
|
24
|
+
CONSUMER_COLUMNS = [Sequel[:lp][:consumer_id], Sequel[:consumers][:name].as(:consumer_name), Sequel[:lp][:pact_publication_id], Sequel[:lp][:pact_version_id]]
|
25
|
+
PROVIDER_COLUMNS = [Sequel[:lp][:provider_id], Sequel[:providers][:name].as(:provider_name), Sequel[:lv][:verification_id]]
|
26
|
+
CONSUMER_VERSION_COLUMNS = [Sequel[:lp][:consumer_version_id], Sequel[:cv][:number].as(:consumer_version_number), Sequel[:cv][:order].as(:consumer_version_order)]
|
27
|
+
PROVIDER_VERSION_COLUMNS = [Sequel[:lv][:provider_version_id], Sequel[:pv][:number].as(:provider_version_number), Sequel[:pv][:order].as(:provider_version_order)]
|
28
|
+
ALL_COLUMNS = CONSUMER_COLUMNS + CONSUMER_VERSION_COLUMNS + PROVIDER_COLUMNS + PROVIDER_VERSION_COLUMNS
|
29
|
+
|
30
|
+
LP_LV_JOIN = { Sequel[:lp][:pact_version_id] => Sequel[:lv][:pact_version_id] }
|
31
|
+
CONSUMER_JOIN = { Sequel[:lp][:consumer_id] => Sequel[:consumers][:id] }
|
32
|
+
PROVIDER_JOIN = { Sequel[:lp][:provider_id] => Sequel[:providers][:id] }
|
33
|
+
CONSUMER_VERSION_JOIN = { Sequel[:lp][:consumer_version_id] => Sequel[:cv][:id] }
|
34
|
+
PROVIDER_VERSION_JOIN = { Sequel[:lv][:provider_version_id] => Sequel[:pv][:id] }
|
35
|
+
|
36
|
+
RAW_QUERY = Sequel::Model.db[Sequel.as(LP, :lp)]
|
37
|
+
.select(*ALL_COLUMNS)
|
38
|
+
.left_outer_join(LV, LP_LV_JOIN, { table_alias: :lv } )
|
39
|
+
.join(:pacticipants, CONSUMER_JOIN, { table_alias: :consumers })
|
40
|
+
.join(:pacticipants, PROVIDER_JOIN, { table_alias: :providers })
|
41
|
+
.join(:versions, CONSUMER_VERSION_JOIN, { table_alias: :cv })
|
42
|
+
.left_outer_join(:versions, PROVIDER_VERSION_JOIN, { table_alias: :pv } )
|
43
|
+
|
44
|
+
ALIASED_QUERY = Sequel.as(RAW_QUERY, :smart_rows)
|
45
|
+
|
46
|
+
class QuickRow < Sequel::Model(ALIASED_QUERY)
|
47
|
+
CONSUMER_ID = Sequel[:smart_rows][:consumer_id]
|
48
|
+
PROVIDER_ID = Sequel[:smart_rows][:provider_id]
|
49
|
+
CONSUMER_VERSION_ID = Sequel[:smart_rows][:consumer_version_id]
|
50
|
+
PROVIDER_VERSION_ID = Sequel[:smart_rows][:provider_version_id]
|
51
|
+
PACT_PUBLICATION_ID = Sequel[:smart_rows][:pact_publication_id]
|
52
|
+
VERIFICATION_ID = Sequel[:smart_rows][:verification_id]
|
53
|
+
|
54
|
+
associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
|
55
|
+
associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
|
56
|
+
associate(:many_to_one, :consumer, :class => "PactBroker::Domain::Pacticipant", :key => :consumer_id, :primary_key => :id)
|
57
|
+
associate(:many_to_one, :consumer_version, :class => "PactBroker::Domain::Version", :key => :consumer_version_id, :primary_key => :id)
|
58
|
+
associate(:many_to_one, :provider_version, :class => "PactBroker::Domain::Version", :key => :provider_version_id, :primary_key => :id)
|
59
|
+
associate(:many_to_one, :pact_version, class: "PactBroker::Pacts::PactVersion", :key => :pact_version_id, :primary_key => :id)
|
60
|
+
associate(:many_to_one, :verification, class: "PactBroker::Domain::Verification", :key => :verification_id, :primary_key => :id)
|
61
|
+
associate(:one_to_many, :consumer_version_tags, :class => "PactBroker::Tags::TagWithLatestFlag", primary_key: :consumer_version_id, key: :version_id)
|
62
|
+
associate(:one_to_many, :provider_version_tags, :class => "PactBroker::Tags::TagWithLatestFlag", primary_key: :provider_version_id, key: :version_id)
|
63
|
+
|
64
|
+
dataset_module do
|
65
|
+
include PactBroker::Repositories::Helpers
|
66
|
+
include PactBroker::Logging
|
67
|
+
|
68
|
+
def consumer_id consumer_id
|
69
|
+
where(CONSUMER_ID => consumer_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
def matching_selectors selectors
|
73
|
+
if selectors.size == 1
|
74
|
+
where_consumer_or_provider_is(selectors.first)
|
75
|
+
else
|
76
|
+
where_consumer_and_provider_in(selectors)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# find rows where (the consumer (and optional version) matches any of the selectors)
|
81
|
+
# AND
|
82
|
+
# the (provider (and optional version) matches any of the selectors OR the provider matches
|
83
|
+
# and the verification is missing (and hence the provider version is null))
|
84
|
+
def where_consumer_and_provider_in selectors
|
85
|
+
where{
|
86
|
+
Sequel.&(
|
87
|
+
Sequel.|(
|
88
|
+
*QueryHelper.consumer_and_maybe_consumer_version_match_any_selector(selectors)
|
89
|
+
),
|
90
|
+
Sequel.|(
|
91
|
+
*QueryHelper.provider_and_maybe_provider_version_match_any_selector_or_verification_is_missing(selectors)
|
92
|
+
),
|
93
|
+
QueryHelper.either_consumer_or_provider_was_specified_in_query(selectors)
|
94
|
+
)
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Can't access other dataset_module methods from inside the Sequel `where{ ... }` block, so make a private class
|
99
|
+
# with some helper methods
|
100
|
+
class QueryHelper
|
101
|
+
def self.consumer_and_maybe_consumer_version_match_any_selector(selectors)
|
102
|
+
selectors.collect { |s| consumer_and_maybe_consumer_version_match_selector(s) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.consumer_and_maybe_consumer_version_match_selector(s)
|
106
|
+
if s[:pact_publication_ids]
|
107
|
+
Sequel.&(PACT_PUBLICATION_ID => s[:pact_publication_ids])
|
108
|
+
elsif s[:pacticipant_version_id]
|
109
|
+
Sequel.&(CONSUMER_ID => s[:pacticipant_id], CONSUMER_VERSION_ID => s[:pacticipant_version_id])
|
110
|
+
else
|
111
|
+
Sequel.&(CONSUMER_ID => s[:pacticipant_id])
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.provider_and_maybe_provider_version_match_selector(s)
|
116
|
+
if s[:verification_ids]
|
117
|
+
Sequel.&(VERIFICATION_ID => s[:verification_ids])
|
118
|
+
elsif s[:pacticipant_version_id]
|
119
|
+
Sequel.&(PROVIDER_ID => s[:pacticipant_id], PROVIDER_VERSION_ID => s[:pacticipant_version_id])
|
120
|
+
else
|
121
|
+
Sequel.&(PROVIDER_ID => s[:pacticipant_id])
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# if the pact for a consumer version has never been verified, it exists in the matrix as a row
|
126
|
+
# with a blank provider version id
|
127
|
+
def self.provider_verification_is_missing_for_matching_selector(s)
|
128
|
+
Sequel.&(PROVIDER_ID => s[:pacticipant_id], PROVIDER_VERSION_ID => nil)
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.provider_and_maybe_provider_version_match_any_selector_or_verification_is_missing(selectors)
|
132
|
+
selectors.collect { |s|
|
133
|
+
provider_and_maybe_provider_version_match_selector(s)
|
134
|
+
} + selectors.collect { |s|
|
135
|
+
provider_verification_is_missing_for_matching_selector(s)
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
# Some selecters are specified in the query, others are implied (when only one pacticipant is specified,
|
140
|
+
# the integrations are automatically worked out, and the selectors for these are of type :implied )
|
141
|
+
# When there are 3 pacticipants that each have dependencies on each other (A->B, A->C, B->C), the query
|
142
|
+
# to deploy C (implied A, implied B, specified C) was returning the A->B row because it matched the
|
143
|
+
# implied selectors as well.
|
144
|
+
# This extra filter makes sure that every row that is returned actually matches one of the specified
|
145
|
+
# selectors.
|
146
|
+
def self.either_consumer_or_provider_was_specified_in_query(selectors)
|
147
|
+
specified_pacticipant_ids = selectors.select{ |s| s[:type] == :specified }.collect{ |s| s[:pacticipant_id] }
|
148
|
+
Sequel.|({ CONSUMER_ID => specified_pacticipant_ids } , { PROVIDER_ID => specified_pacticipant_ids })
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def where_consumer_or_provider_is s
|
153
|
+
where{
|
154
|
+
Sequel.|(
|
155
|
+
s[:pacticipant_version_id] ? Sequel.&(CONSUMER_ID => s[:pacticipant_id], CONSUMER_VERSION_ID => s[:pacticipant_version_id]) : Sequel.&(CONSUMER_ID => s[:pacticipant_id]),
|
156
|
+
s[:pacticipant_version_id] ? Sequel.&(PROVIDER_ID => s[:pacticipant_id], PROVIDER_VERSION_ID => s[:pacticipant_version_id]) : Sequel.&(PROVIDER_ID => s[:pacticipant_id])
|
157
|
+
)
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
def order_by_names_ascending_most_recent_first
|
162
|
+
order(
|
163
|
+
Sequel.asc(:consumer_name),
|
164
|
+
Sequel.desc(:consumer_version_order),
|
165
|
+
Sequel.asc(:provider_name),
|
166
|
+
Sequel.desc(:provider_version_order),
|
167
|
+
Sequel.desc(:verification_id))
|
168
|
+
end
|
169
|
+
|
170
|
+
def eager_all_the_things
|
171
|
+
eager(:consumer)
|
172
|
+
.eager(:provider)
|
173
|
+
.eager(:consumer_version)
|
174
|
+
.eager(:provider_version)
|
175
|
+
.eager(:verification)
|
176
|
+
.eager(:pact_publication)
|
177
|
+
.eager(:pact_version)
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
def success
|
183
|
+
verification&.success
|
184
|
+
end
|
185
|
+
|
186
|
+
def pact_version_sha
|
187
|
+
pact_version.sha
|
188
|
+
end
|
189
|
+
|
190
|
+
def pact_revision_number
|
191
|
+
pact_publication.revision_number
|
192
|
+
end
|
193
|
+
|
194
|
+
def verification_number
|
195
|
+
verification&.number
|
196
|
+
end
|
197
|
+
|
198
|
+
def success
|
199
|
+
verification&.success
|
200
|
+
end
|
201
|
+
|
202
|
+
def pact_created_at
|
203
|
+
pact_publication.created_at
|
204
|
+
end
|
205
|
+
|
206
|
+
def verification_executed_at
|
207
|
+
verification.execution_date
|
208
|
+
end
|
209
|
+
|
210
|
+
# Add logic for ignoring case
|
211
|
+
def <=> other
|
212
|
+
comparisons = [
|
213
|
+
compare_name_asc(consumer_name, other.consumer_name),
|
214
|
+
compare_number_desc(consumer_version_order, other.consumer_version_order),
|
215
|
+
compare_number_desc(pact_revision_number, other.pact_revision_number),
|
216
|
+
compare_name_asc(provider_name, other.provider_name),
|
217
|
+
compare_number_desc(provider_version_order, other.provider_version_order),
|
218
|
+
compare_number_desc(verification_id, other.verification_id)
|
219
|
+
]
|
220
|
+
|
221
|
+
comparisons.find{|c| c != 0 } || 0
|
222
|
+
end
|
223
|
+
|
224
|
+
def compare_name_asc name1, name2
|
225
|
+
name1 <=> name2
|
226
|
+
end
|
227
|
+
|
228
|
+
def to_s
|
229
|
+
"#{consumer_name} v#{consumer_version_number} #{provider_name} #{provider_version_number} #{success}"
|
230
|
+
end
|
231
|
+
|
232
|
+
def compare_number_desc number1, number2
|
233
|
+
if number1 && number2
|
234
|
+
number2 <=> number1
|
235
|
+
elsif number1
|
236
|
+
1
|
237
|
+
else
|
238
|
+
-1
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def eql?(obj)
|
243
|
+
(obj.class == model) && (obj.values == values)
|
244
|
+
end
|
245
|
+
|
246
|
+
def pacticipant_names
|
247
|
+
[consumer_name, provider_name]
|
248
|
+
end
|
249
|
+
|
250
|
+
def involves_pacticipant_with_name?(pacticipant_name)
|
251
|
+
pacticipant_name.include?(pacticipant_name)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|