pact_broker 2.43.0 → 2.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -1
- data/DEVELOPER_DOCUMENTATION.md +10 -6
- data/README.md +1 -1
- data/lib/pact_broker/api.rb +2 -2
- data/lib/pact_broker/api/decorators/version_decorator.rb +8 -0
- data/lib/pact_broker/db/models.rb +1 -1
- data/lib/pact_broker/doc/views/matrix.markdown +92 -2
- data/lib/pact_broker/matrix/deployment_status_summary.rb +11 -2
- data/lib/pact_broker/matrix/every_row.rb +43 -0
- data/lib/pact_broker/matrix/query_builder.rb +5 -5
- data/lib/pact_broker/matrix/quick_row.rb +96 -28
- data/lib/pact_broker/matrix/reason.rb +3 -0
- data/lib/pact_broker/matrix/repository.rb +33 -35
- data/lib/pact_broker/pacticipants/repository.rb +9 -1
- data/lib/pact_broker/pacts/{latest_pact_publication_id_by_consumer_version.rb → latest_pact_publication_id_for_consumer_version.rb} +0 -0
- data/lib/pact_broker/pacts/repository.rb +1 -1
- data/lib/pact_broker/repositories/helpers.rb +12 -5
- data/lib/pact_broker/version.rb +1 -1
- data/pact_broker.gemspec +1 -1
- data/spec/lib/pact_broker/integrations/service_spec.rb +1 -0
- data/spec/lib/pact_broker/matrix/deployment_status_summary_spec.rb +38 -33
- data/spec/lib/pact_broker/matrix/every_row_spec.rb +136 -0
- data/spec/lib/pact_broker/matrix/integration_spec.rb +149 -30
- data/spec/lib/pact_broker/matrix/repository_dependency_spec.rb +3 -3
- data/spec/lib/pact_broker/matrix/repository_spec.rb +5 -4
- data/spec/lib/pact_broker/pacticipants/repository_spec.rb +37 -3
- data/spec/service_consumers/provider_states_for_pact_ruby.rb +12 -0
- data/spec/support/shared_examples_for_responses.rb +7 -0
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90700346c7cb45045249cf0006851d517a154879
|
4
|
+
data.tar.gz: 492ebdd3a03cf7d6f617cc820a1bbf0316031d66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8236c0d6c9ba4a6f81e776599047e24cea2ea6433454ba3072565e02eb1aca73bb72184fd9b01913a869bdb3ffbed12f06d791af3f853038f16dc981005512c
|
7
|
+
data.tar.gz: 29bdec1d5c5ed4be6d8751faa517012337f7e04f587d83f2d83455656104764f001bb8425706a590ae42ce32ac66c87fcc5112bad2083748e08e27af82d7f81b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
<a name="v2.44.0"></a>
|
2
|
+
### v2.44.0 (2020-01-22)
|
3
|
+
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* **matrix**
|
8
|
+
* optimise query to determine integrations, again ([44e78ad2](/../../commit/44e78ad2))
|
9
|
+
* add indexes to optimise queries ([cdc9aad7](/../../commit/cdc9aad7))
|
10
|
+
* optimise query to determine integrations ([9e874f3b](/../../commit/9e874f3b))
|
11
|
+
|
12
|
+
* add hal relation for creating a tag on the pacticipant version resource ([dca0ad4f](/../../commit/dca0ad4f))
|
13
|
+
|
14
|
+
|
15
|
+
#### Bug Fixes
|
16
|
+
|
17
|
+
* update pact-support to fix bug caused by missing require ([416ecdf5](/../../commit/416ecdf5))
|
18
|
+
* correct logic for finding pacticipants by name when the name contains an underscore ([6d975ebe](/../../commit/6d975ebe))
|
19
|
+
* correct logic for finding pacticipants by name when the name contains an underscore ([2db59797](/../../commit/2db59797))
|
20
|
+
|
21
|
+
* **matrix**
|
22
|
+
* correctly infer selectors when multiple selectors have been specified ([4288c282](/../../commit/4288c282))
|
23
|
+
|
24
|
+
|
1
25
|
<a name="v2.43.0"></a>
|
2
26
|
### v2.43.0 (2020-01-06)
|
3
27
|
|
@@ -10,7 +34,6 @@
|
|
10
34
|
|
11
35
|
* **matrix**
|
12
36
|
* optimise the query that determines the integrations ([704944b6](/../../commit/704944b6))
|
13
|
-
* attempt to optimise the query that determines the integrations ([afde01e1](/../../commit/afde01e1))
|
14
37
|
|
15
38
|
|
16
39
|
#### Bug Fixes
|
data/DEVELOPER_DOCUMENTATION.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
* API - [lib/pact_broker/api](lib/pact_broker/api)
|
8
8
|
* Routes - [lib/pact_broker/api.rb](lib/pact_broker/api.rb)
|
9
9
|
* HTTP Resources - [lib/pact_broker/api/resources](lib/pact_broker/api/resources) These handle the HTTP requests.
|
10
|
-
* Decorators - [lib/pact_broker/api/decorators](lib/pact_broker/api/decorators) These render the response bodies.
|
10
|
+
* Decorators - [lib/pact_broker/api/decorators](lib/pact_broker/api/decorators) These parse the request bodies and render the response bodies.
|
11
11
|
* Contracts - [lib/pact_broker/api/contracts](lib/pact_broker/api/contracts) These validate incoming API requests.
|
12
12
|
* UI - [lib/pact_broker/ui](lib/pact_broker/ui)
|
13
13
|
* Routes - [lib/pact_broker/ui/app.rb](lib/pact_broker/ui/app.rb)
|
@@ -35,10 +35,13 @@ Domain classes are found in `lib/pact_broker/domain`. Many of these classes are
|
|
35
35
|
|
36
36
|
* `pacticipant` - an application that participates in a pact. A very bad pun which I deeply regret.
|
37
37
|
* `pact` - this term is confusing and overloaded. It generally means a `pact publication` in the code.
|
38
|
-
* `pact publication` - the resource that gets created when a PUT request is sent to the Pact Broker to
|
38
|
+
* `pact publication` - the resource that gets created when a PUT request is sent to the Pact Broker to `/pacts/provider/PROVIDER/consumer/CONSUMER/version/VERSION`.
|
39
39
|
* `pact version` - the JSON contents of the pact publication. One pact version may belong to many pact publications. That is, if a pact publication with exactly the same contents is published twice, then a new
|
40
|
-
pact publication resource will be created, but it will reuse the existing pact version.
|
40
|
+
pact publication resource will be created with an incremented revision number, but it will reuse the existing pact version.
|
41
|
+
* `pacticipant version` - a resource that represents a version of the application
|
42
|
+
* `integration` - the relationship between a consumer and a provider
|
41
43
|
* `pseudo branch` - A time ordered list of pacts that are related to a particular tag. The most recent pact for each pseudo branch is a "head" pact.
|
44
|
+
* `matrix` - the table that shows the cartesian join of pact versions/verifications, and hence shows which consumer versions and provider versions have been tested together.
|
42
45
|
|
43
46
|
### Tables
|
44
47
|
* `pact_versions` - the JSON content of each UNIQUE pact document is stored in this table. The same content is likely to be published over and over again by the CI builds, so deduplicating the content saves us a lot of disk space. Once created, a row is never modified. Uniqueness is just done on string equality - no special pact logic. This means that pacts with randomly generated values or orders (most of pact-jvm pacts!) will get a new version record every time they publish.
|
@@ -80,11 +83,11 @@ pact publication resource will be created, but it will reuse the existing pact v
|
|
80
83
|
* `consumer version number` and `consumer version order`
|
81
84
|
* `revision_number`
|
82
85
|
|
83
|
-
* `latest_pact_publications_by_consumer_versions` - This view has the same columns as `all_pact_publications`, but it only contains the latest revision of the pact for each provider/consumer/version. It maps to what a user would consider the "pact" resource ie. `/pacts/provider/
|
86
|
+
* `latest_pact_publications_by_consumer_versions` - This view has the same columns as `all_pact_publications`, but it only contains the latest revision of the pact for each provider/consumer/version. It maps to what a user would consider the "pact" resource ie. `/pacts/provider/PROVIDER/consumer/CONSUMER/version/VERSION`. Previous revisions are not currently exposed via the API.
|
84
87
|
|
85
88
|
The `AllPactPublications` Sequel model in the code is what is used when querying data for displaying in a response, rather than the normalised separate PactPublication and PactVersion models.
|
86
89
|
|
87
|
-
* `latest_pact_publications` - This view has the same columns as `all_pact_publications`, but it only contains the latest revision of the pact for the latest consumer version for each consumer/provider pair. It is what a user would consider the "latest pact", and maps to the resource at `/pacts/provider/
|
90
|
+
* `latest_pact_publications` - This view has the same columns as `all_pact_publications`, but it only contains the latest revision of the pact for the latest consumer version for each consumer/provider pair. It is what a user would consider the "latest pact", and maps to the resource at `/pacts/provider/PROVIDER/consumer/CONSUMER/latest`
|
88
91
|
|
89
92
|
* `latest_tagged_pact_publications` - This view has the same columns as `all_pact_publications`, plus a `tag_name` column. It is used to return the pact for the latest tagged version of a consumer.
|
90
93
|
|
@@ -116,8 +119,9 @@ pact publication resource will be created, but it will reuse the existing pact v
|
|
116
119
|
|
117
120
|
```
|
118
121
|
|
122
|
+
### Database modeling approach
|
119
123
|
|
120
|
-
|
124
|
+
In the beginning, I made a lot of Sequel models based on views that pulled in the different tables of data together (eg denormalising consumer, provider, pact publication and pact version in to `all_pact_publications`). This made the Ruby code quite simple, but it was not very performant. As time has progressed, I have moved more and more of the "data joining" code into the Ruby to optimise the queries. That's why there are a lot of "aggregated data" views that are not being used by the code any more.
|
121
125
|
|
122
126
|
### Useful to know stuff
|
123
127
|
|
data/README.md
CHANGED
@@ -166,7 +166,7 @@ Please read the [UPGRADING.md](UPGRADING.md) documentation before upgrading your
|
|
166
166
|
[pact]: https://github.com/pact-foundation/pact-ruby
|
167
167
|
[nerf]: https://github.com/pact-foundation/pact_broker/wiki/pact-broker-ci-nerf-gun
|
168
168
|
[different-teams]: https://github.com/pact-foundation/pact-ruby/wiki/Using-pact-where-the-consumer-team-is-different-from-the-provider-team
|
169
|
-
[docker]: https://
|
169
|
+
[docker]: https://github.com/pact-foundation/pact-broker-docker
|
170
170
|
[terraform]: https://github.com/nadnerb/terraform-pact-broker
|
171
171
|
[pactflow]: https:/pactflow.io/?utm_source=github&utm_campaign=pact_broker_usage
|
172
172
|
[wiki]: https://github.com/pact-foundation/pact_broker/wiki
|
data/lib/pact_broker/api.rb
CHANGED
@@ -53,7 +53,7 @@ module PactBroker
|
|
53
53
|
add ['pacts', 'provider', :provider_name, 'for-verification'], Api::Resources::ProviderPactsForVerification, {resource_name: "pacts_for_verification"}
|
54
54
|
|
55
55
|
# Deprecated pact
|
56
|
-
add ['pact', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number], Api::Resources::Pact, {resource_name: "
|
56
|
+
add ['pact', 'provider', :provider_name, 'consumer', :consumer_name, 'version', :consumer_version_number], Api::Resources::Pact, {resource_name: "pact_publication", deprecated: "true"} # Deprecate, singular /pact
|
57
57
|
add ['pact', 'provider', :provider_name, 'consumer', :consumer_name, 'latest'], Api::Resources::LatestPact, {resource_name: "latest_pact_publications", deprecated: "true"}
|
58
58
|
|
59
59
|
# Pacticipants
|
@@ -88,7 +88,7 @@ module PactBroker
|
|
88
88
|
add ['matrix', 'provider', :provider_name, 'consumer', :consumer_name], Api::Resources::MatrixForConsumerAndProvider, {resource_name: "matrix_consumer_provider"}
|
89
89
|
add ['matrix', 'provider', :provider_name, 'latest', :provider_tag, 'consumer', :consumer_name, 'latest', :tag, 'badge'], Api::Resources::MatrixBadge, {resource_name: "matrix_tag_badge"}
|
90
90
|
add ['matrix'], Api::Resources::Matrix, {resource_name: "matrix"}
|
91
|
-
add ['can-i-deploy'], Api::Resources::CanIDeploy, {resource_name: "
|
91
|
+
add ['can-i-deploy'], Api::Resources::CanIDeploy, {resource_name: "can_i_deploy"}
|
92
92
|
|
93
93
|
add ['dashboard'], Api::Resources::Dashboard, {resource_name: "dashboard"}
|
94
94
|
add ['dashboard', 'provider', :provider_name, 'consumer', :consumer_name ], Api::Resources::Dashboard, {resource_name: "integration_dashboard"}
|
@@ -26,6 +26,14 @@ module PactBroker
|
|
26
26
|
}
|
27
27
|
end
|
28
28
|
|
29
|
+
link :'pb:tag' do | options |
|
30
|
+
{
|
31
|
+
href: pacticipant_url(options.fetch(:base_url), represented.pacticipant) + '/tags/{tag}',
|
32
|
+
title: "Get, create or delete a tag for this pacticipant version",
|
33
|
+
templated: true
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
29
37
|
link :'pb:latest-verification-results-where-pacticipant-is-consumer' do | options |
|
30
38
|
{
|
31
39
|
title: "Latest verification results for consumer version",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'pact_broker/webhooks/execution'
|
2
2
|
require 'pact_broker/webhooks/triggered_webhook'
|
3
3
|
require 'pact_broker/webhooks/webhook'
|
4
|
-
require 'pact_broker/pacts/
|
4
|
+
require 'pact_broker/pacts/latest_pact_publication_id_for_consumer_version'
|
5
5
|
require 'pact_broker/verifications/latest_verification_id_for_pact_version_and_provider_version'
|
6
6
|
require 'pact_broker/pacts/pact_publication'
|
7
7
|
require 'pact_broker/pacts/pact_version'
|
@@ -2,6 +2,96 @@
|
|
2
2
|
|
3
3
|
Allowed methods: `GET`
|
4
4
|
|
5
|
-
This resource returns the "cartesian join" of every pact publication and every verification results publication, and is used to determine whether or not
|
5
|
+
This resource returns the "cartesian join" of every pact publication and every verification results publication, and is used to determine whether or not a set of integrated application versions are safe to deploy together.
|
6
6
|
|
7
|
-
If you need to use this API, consider calling the `/can-i-deploy` resource instead.
|
7
|
+
If you need to use this API, consider calling the `/can-i-deploy` resource instead, as it provides an interface that is easier to understand.
|
8
|
+
|
9
|
+
|
10
|
+
## Matrix selectors and options
|
11
|
+
|
12
|
+
Selectors are the way we specify which pacticipants and versions we want to view the matrix for. The best way to understand them is to imagine that we start with a Matrix table that contains the pacts/verification results for every consumer and provider in the Pact Broker.
|
13
|
+
|
14
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
15
|
+
|----------|------------------|----------|------------------|---------|
|
16
|
+
| Foo | 1 | Oink | 6 | true |
|
17
|
+
| Foo | 1 | Bar | 2 | true |
|
18
|
+
| Foo | 1 | Bar | 3 | false |
|
19
|
+
|
20
|
+
To specify that we wanted to see all the rows between Foo and Bar, our selectors would be:
|
21
|
+
|
22
|
+
`{"pacticipant": "Foo"}` and `{"pacticipant": "Bar"}`.
|
23
|
+
|
24
|
+
This would return:
|
25
|
+
|
26
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
27
|
+
|----------|------------------|----------|------------------|---------|
|
28
|
+
| Foo | 1 | Bar | 2 | true |
|
29
|
+
| Foo | 1 | Bar | 3 | false |
|
30
|
+
|
31
|
+
To specify that we wanted to see the results for Foo v1 and Bar v3, our selectors would be:
|
32
|
+
|
33
|
+
`{"pacticipant": "Foo", "version": "1"}` and `{"pacticipant": "Bar", "version": "3"}`.
|
34
|
+
|
35
|
+
This would return:
|
36
|
+
|
37
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
38
|
+
|----------|------------------|----------|------------------|---------|
|
39
|
+
| Foo | 1 | Bar | 3 | false |
|
40
|
+
|
41
|
+
|
42
|
+
Best "Pact Broker" practice specifies that once a pact is published for a particular consumer version, it should not be overwritten, however, there is nothing built in to the broker to stop multiple pacts being published with the same consumer version. If the provider verifies each revision, we would end up with a table that looks like this:
|
43
|
+
|
44
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
45
|
+
|----------|------------------|----------|------------------|---------|
|
46
|
+
| Foo | 1 (revision 1) | Bar | 3 | false |
|
47
|
+
| Foo | 1 (revision 2) | Bar | 3 | true |
|
48
|
+
| Foo | 1 (revision 3) | Bar | 3 | false |
|
49
|
+
|
50
|
+
The overwritten revisions are not useful for determining whether or not we are safe to deploy, so to remove these lines from the dataset, we can specify the option `{latestby: "cvpv"}` to return the latest row when grouped and ordered by "consumer version and provider version".
|
51
|
+
|
52
|
+
Putting the selectors and the options together, to specify that we wanted to see the *latest* results for Foo v1 and Bar v3, our selectors would be:
|
53
|
+
|
54
|
+
`{"pacticipant": "Foo", "version": "1"}` and `{"pacticipant": "Bar", "version": "3"}` and our options would be `{"latestby": "cvpv"}`.
|
55
|
+
|
56
|
+
This would return:
|
57
|
+
|
58
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
59
|
+
|----------|------------------|----------|------------------|---------|
|
60
|
+
| Foo | 1 (revision 3) | Bar | 3 | false |
|
61
|
+
|
62
|
+
|
63
|
+
Instead of specifying the version using the version number, you can also specify it by indicating the tag name.
|
64
|
+
|
65
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
66
|
+
|----------|------------------|----------|------------------|---------|
|
67
|
+
| Foo | 1 (prod) | Bar | 2 | true |
|
68
|
+
| Foo | 1 (prod) | Bar | 3 (prod) | true |
|
69
|
+
| Foo | 2 | Bar | 4 (prod) | true |
|
70
|
+
| Foo | 2 | Bar | 5 | true |
|
71
|
+
|
72
|
+
Version 1 of Foo has been tagged prod, while versions 3 and 4 of Bar have been tagged prod.
|
73
|
+
|
74
|
+
To determine if Foo v2 can be deployed with the latest prod version of Bar, our selectors would be:
|
75
|
+
|
76
|
+
`{"pacticipant": "Foo", "version": "2"}` and `{"pacticipant": "Bar", tag: "prod", latest: true}` and our options would be `{"latestby": "cvpv"}`.
|
77
|
+
|
78
|
+
Using the dataset above, this query would return:
|
79
|
+
|
80
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
81
|
+
|----------|------------------|----------|------------------|---------|
|
82
|
+
| Foo | 2 | Bar | 4 (prod) | true |
|
83
|
+
|
84
|
+
|
85
|
+
Imagine that Foo added another provider (and may add more in the future). It would be brittle to specify each of its integration partners by name. The Pact Broker already knows which applications Foo integrates with, so let's allow it to work out the dependencies by itself.
|
86
|
+
|
87
|
+
To determine if Foo v2 can be deployed with the latest prod versions of all its integration partners, our selectors would be:
|
88
|
+
|
89
|
+
`{"pacticipant": "Foo", "version": "2"}` and our options would be `{ "tag": "prod", latest: true, latestby: "cvp"}`. (Note the change in `latestby` from "cvpv" to "cvp". The reasons why this is the case are beyond the scope of this document.)
|
90
|
+
|
91
|
+
|
92
|
+
If Foo was a mobile client, and Bar was its provider, we might want to know if a particular version of Bar was compatible with _all_ the production versions of Foo. To do this, we drop the `"latest": true` from Foo's selector, like so: `{"pacticipant": "Foo", "tag": "prod"}` and `{"pacticipant": "Bar", version: "3"}`. Using the dataset from above, this query would return the following rows:
|
93
|
+
|
94
|
+
| Consumer | Consumer version | Provider | Provider version | Success |
|
95
|
+
|----------|------------------|----------|------------------|---------|
|
96
|
+
| Foo | 1 (prod) | Bar | 2 | true |
|
97
|
+
| Foo | 1 (prod) | Bar | 3 (prod) | true |
|
@@ -99,12 +99,21 @@ module PactBroker
|
|
99
99
|
# the Foo -> Bar integration, and therefore cannot deploy Foo.
|
100
100
|
# However, if we were to try and deploy the provider, Bar, that would be ok
|
101
101
|
# as Bar does not rely on Foo, so this method would not return that integration.
|
102
|
+
# UPDATE:
|
103
|
+
# The matrix query now returns a row with blank provider version/verification fields
|
104
|
+
# so the above comment is now redundant.
|
105
|
+
# I'm not sure if this piece of code can ever return a list with anything in it any more.
|
106
|
+
# Will log it for a while and see.
|
102
107
|
def required_integrations_without_a_row
|
103
108
|
@required_integrations_without_a_row ||= begin
|
104
109
|
integrations.select(&:required?).select do | integration |
|
105
110
|
!row_exists_for_integration(integration)
|
106
111
|
end
|
107
|
-
end
|
112
|
+
end.tap { |it| log_required_integrations_without_a_row_occurred(it) if it.any? }
|
113
|
+
end
|
114
|
+
|
115
|
+
def log_required_integrations_without_a_row_occurred integrations
|
116
|
+
logger.info("required_integrations_without_a_row returned non empty", payload: { integrations: integrations, rows: rows })
|
108
117
|
end
|
109
118
|
|
110
119
|
def row_exists_for_integration(integration)
|
@@ -148,7 +157,7 @@ module PactBroker
|
|
148
157
|
[selector_for(row.consumer_name), selector_for(row.provider_name)]
|
149
158
|
end
|
150
159
|
|
151
|
-
# When the user has not specified a version of the provider (eg no 'latest' and/or 'tag')
|
160
|
+
# When the user has not specified a version of the provider (eg no 'latest' and/or 'tag', which means 'all versions')
|
152
161
|
# so the "add inferred selectors" code in the Matrix::Repository has not run,
|
153
162
|
# we may end up with rows for which we do not have a selector.
|
154
163
|
# To solve this, create dummy selectors from the row and integration data.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'pact_broker/matrix/quick_row'
|
2
|
+
|
3
|
+
module PactBroker
|
4
|
+
module Matrix
|
5
|
+
class EveryRow < PactBroker::Matrix::QuickRow
|
6
|
+
set_dataset(Sequel.as(:pact_publications, :p))
|
7
|
+
|
8
|
+
P_V_JOIN = { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }
|
9
|
+
|
10
|
+
PACT_COLUMNS = [
|
11
|
+
Sequel[:p][:id].as(:pact_publication_id),
|
12
|
+
Sequel[:p][:pact_version_id],
|
13
|
+
Sequel[:p][:revision_number].as(:pact_revision_number)
|
14
|
+
]
|
15
|
+
VERIFICATION_COLUMNS = [
|
16
|
+
Sequel[:v][:id].as(:verification_id)
|
17
|
+
]
|
18
|
+
|
19
|
+
ALL_COLUMNS = CONSUMER_COLUMNS + CONSUMER_VERSION_COLUMNS + PACT_COLUMNS +
|
20
|
+
PROVIDER_COLUMNS + PROVIDER_VERSION_COLUMNS + VERIFICATION_COLUMNS
|
21
|
+
|
22
|
+
SELECT_ALL_COLUMN_ARGS = [:select_all_columns] + ALL_COLUMNS
|
23
|
+
dataset_module do
|
24
|
+
select *SELECT_ALL_COLUMN_ARGS
|
25
|
+
|
26
|
+
def join_verifications
|
27
|
+
left_outer_join(:verifications, P_V_JOIN, { table_alias: :v } )
|
28
|
+
end
|
29
|
+
|
30
|
+
def verifications_for(query_ids)
|
31
|
+
db[:verifications]
|
32
|
+
.select(:id, :pact_version_id, :provider_id, :provider_version_id)
|
33
|
+
.where {
|
34
|
+
Sequel.&(
|
35
|
+
QueryBuilder.consumer_in_pacticipant_ids(query_ids),
|
36
|
+
QueryBuilder.provider_or_provider_version_matches(query_ids)
|
37
|
+
)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -9,7 +9,7 @@ module PactBroker
|
|
9
9
|
ors = provider_or_provider_version_criteria(query_ids, qualifier)
|
10
10
|
|
11
11
|
ors << {
|
12
|
-
qualify(:
|
12
|
+
qualify(:p, :provider_id) => query_ids.all_pacticipant_ids,
|
13
13
|
qualify(qualifier, :provider_version_id) => nil
|
14
14
|
}
|
15
15
|
Sequel.|(*ors)
|
@@ -53,13 +53,13 @@ module PactBroker
|
|
53
53
|
def self.consumer_or_consumer_version_or_provider_or_provider_or_provider_version_match(query_ids)
|
54
54
|
ors = if query_ids.pacticipant_version_id
|
55
55
|
[
|
56
|
-
{ Sequel[:
|
57
|
-
{ Sequel[:
|
56
|
+
{ Sequel[:p][:consumer_version_id] => query_ids.pacticipant_version_id },
|
57
|
+
{ Sequel[:v][:provider_version_id] => query_ids.pacticipant_version_id }
|
58
58
|
]
|
59
59
|
else
|
60
60
|
[
|
61
|
-
{ Sequel[:
|
62
|
-
{ Sequel[:
|
61
|
+
{ Sequel[:p][:consumer_id] => query_ids.pacticipant_id },
|
62
|
+
{ Sequel[:p][:provider_id] => query_ids.pacticipant_id }
|
63
63
|
]
|
64
64
|
end
|
65
65
|
|
@@ -20,54 +20,52 @@ require 'pact_broker/matrix/query_ids'
|
|
20
20
|
|
21
21
|
module PactBroker
|
22
22
|
module Matrix
|
23
|
-
class QuickRow < Sequel::Model(Sequel.as(:latest_pact_publication_ids_for_consumer_versions, :
|
23
|
+
class QuickRow < Sequel::Model(Sequel.as(:latest_pact_publication_ids_for_consumer_versions, :p))
|
24
24
|
|
25
25
|
# Tables
|
26
26
|
LV = :latest_verification_id_for_pact_version_and_provider_version
|
27
27
|
LP = :latest_pact_publication_ids_for_consumer_versions
|
28
28
|
|
29
29
|
# Joins
|
30
|
-
LP_LV_JOIN = { Sequel[:
|
31
|
-
|
32
|
-
|
33
|
-
CONSUMER_VERSION_JOIN = { Sequel[:lp][:consumer_version_id] => Sequel[:cv][:id] }
|
34
|
-
PROVIDER_VERSION_JOIN = { Sequel[:lv][:provider_version_id] => Sequel[:pv][:id] }
|
30
|
+
LP_LV_JOIN = { Sequel[:p][:pact_version_id] => Sequel[:v][:pact_version_id] }
|
31
|
+
CONSUMER_VERSION_JOIN = { Sequel[:p][:consumer_version_id] => Sequel[:cv][:id] }
|
32
|
+
PROVIDER_VERSION_JOIN = { Sequel[:v][:provider_version_id] => Sequel[:pv][:id] }
|
35
33
|
|
36
34
|
# Not sure why we're eager loading some things and including others in the base query :shrug:
|
37
35
|
|
38
36
|
# Columns
|
39
37
|
CONSUMER_COLUMNS = [
|
40
|
-
Sequel[:
|
38
|
+
Sequel[:p][:consumer_id],
|
41
39
|
Sequel[:consumers][:name].as(:consumer_name)
|
42
40
|
]
|
43
41
|
PROVIDER_COLUMNS = [
|
44
|
-
Sequel[:
|
42
|
+
Sequel[:p][:provider_id],
|
45
43
|
Sequel[:providers][:name].as(:provider_name)
|
46
44
|
]
|
47
45
|
CONSUMER_VERSION_COLUMNS = [
|
48
|
-
Sequel[:
|
46
|
+
Sequel[:p][:consumer_version_id],
|
49
47
|
Sequel[:cv][:number].as(:consumer_version_number),
|
50
48
|
Sequel[:cv][:order].as(:consumer_version_order)
|
51
49
|
]
|
52
50
|
PROVIDER_VERSION_COLUMNS = [
|
53
|
-
Sequel[:
|
51
|
+
Sequel[:v][:provider_version_id],
|
54
52
|
Sequel[:pv][:number].as(:provider_version_number),
|
55
53
|
Sequel[:pv][:order].as(:provider_version_order)
|
56
54
|
]
|
57
55
|
PACT_COLUMNS = [
|
58
|
-
Sequel[:
|
59
|
-
Sequel[:
|
56
|
+
Sequel[:p][:pact_publication_id],
|
57
|
+
Sequel[:p][:pact_version_id]
|
60
58
|
]
|
61
59
|
VERIFICATION_COLUMNS = [
|
62
|
-
Sequel[:
|
60
|
+
Sequel[:v][:verification_id]
|
63
61
|
]
|
64
62
|
ALL_COLUMNS = CONSUMER_COLUMNS + CONSUMER_VERSION_COLUMNS + PACT_COLUMNS +
|
65
63
|
PROVIDER_COLUMNS + PROVIDER_VERSION_COLUMNS + VERIFICATION_COLUMNS
|
66
|
-
|
64
|
+
|
67
65
|
|
68
66
|
# cachable select arguments
|
69
67
|
SELECT_ALL_COLUMN_ARGS = [:select_all_columns] + ALL_COLUMNS
|
70
|
-
|
68
|
+
SELECT_PACTICIPANT_IDS_ARGS = [:select_pacticipant_ids, Sequel[:p][:consumer_id], Sequel[:p][:provider_id]]
|
71
69
|
|
72
70
|
associate(:many_to_one, :pact_publication, :class => "PactBroker::Pacts::PactPublication", :key => :pact_publication_id, :primary_key => :id)
|
73
71
|
associate(:many_to_one, :provider, :class => "PactBroker::Domain::Pacticipant", :key => :provider_id, :primary_key => :id)
|
@@ -83,12 +81,26 @@ module PactBroker
|
|
83
81
|
include PactBroker::Repositories::Helpers
|
84
82
|
|
85
83
|
select *SELECT_ALL_COLUMN_ARGS
|
86
|
-
select *
|
84
|
+
select *SELECT_PACTICIPANT_IDS_ARGS
|
87
85
|
|
88
86
|
def distinct_integrations selectors
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
query = if selectors.size == 1
|
88
|
+
pacticipant_ids_matching_one_selector_optimised(selectors)
|
89
|
+
else
|
90
|
+
select_pacticipant_ids
|
91
|
+
.distinct
|
92
|
+
.matching_any_of_multiple_selectors(selectors)
|
93
|
+
end
|
94
|
+
|
95
|
+
query.from_self(alias: :pacticipant_ids)
|
96
|
+
.select(
|
97
|
+
:consumer_id,
|
98
|
+
Sequel[:c][:name].as(:consumer_name),
|
99
|
+
:provider_id,
|
100
|
+
Sequel[:p][:name].as(:provider_name)
|
101
|
+
)
|
102
|
+
.join_consumers(:pacticipant_ids, :c)
|
103
|
+
.join_providers(:pacticipant_ids, :p)
|
92
104
|
end
|
93
105
|
|
94
106
|
def matching_selectors selectors
|
@@ -117,6 +129,8 @@ module PactBroker
|
|
117
129
|
.eager(:verification)
|
118
130
|
.eager(:pact_publication)
|
119
131
|
.eager(:pact_version)
|
132
|
+
.eager(:consumer_version_tags)
|
133
|
+
.eager(:provider_version_tags)
|
120
134
|
end
|
121
135
|
|
122
136
|
def default_scope
|
@@ -135,6 +149,29 @@ module PactBroker
|
|
135
149
|
}
|
136
150
|
end
|
137
151
|
|
152
|
+
def pacticipant_ids_matching_one_selector_optimised(selectors)
|
153
|
+
query_ids = QueryIds.from_selectors(selectors)
|
154
|
+
distinct_pacticipant_ids_where_consumer_or_consumer_version_matches(query_ids)
|
155
|
+
.union(distinct_pacticipant_ids_where_provider_or_provider_version_matches(query_ids), all: true)
|
156
|
+
end
|
157
|
+
|
158
|
+
def distinct_pacticipant_ids_where_consumer_or_consumer_version_matches(query_ids)
|
159
|
+
select_pacticipant_ids
|
160
|
+
.distinct
|
161
|
+
.where {
|
162
|
+
QueryBuilder.consumer_or_consumer_version_matches(query_ids, :p)
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
def distinct_pacticipant_ids_where_provider_or_provider_version_matches(query_ids)
|
167
|
+
select_pacticipant_ids
|
168
|
+
.distinct
|
169
|
+
.inner_join_verifications
|
170
|
+
.where {
|
171
|
+
QueryBuilder.provider_or_provider_version_matches(query_ids, :v)
|
172
|
+
}
|
173
|
+
end
|
174
|
+
|
138
175
|
# When the user has specified multiple selectors, we only want to join the verifications for
|
139
176
|
# the specified selectors. This is because of the behaviour of the left outer join.
|
140
177
|
# Imagine a pact has been verified by a provider version that was NOT specified in the selectors.
|
@@ -150,15 +187,30 @@ module PactBroker
|
|
150
187
|
.join_pacticipants_and_pacticipant_versions
|
151
188
|
.where {
|
152
189
|
Sequel.&(
|
153
|
-
QueryBuilder.consumer_or_consumer_version_matches(query_ids, :
|
154
|
-
QueryBuilder.provider_or_provider_version_matches_or_pact_unverified(query_ids, :
|
155
|
-
QueryBuilder.either_consumer_or_provider_was_specified_in_query(query_ids, :
|
190
|
+
QueryBuilder.consumer_or_consumer_version_matches(query_ids, :p),
|
191
|
+
QueryBuilder.provider_or_provider_version_matches_or_pact_unverified(query_ids, :v),
|
192
|
+
QueryBuilder.either_consumer_or_provider_was_specified_in_query(query_ids, :p)
|
193
|
+
)
|
194
|
+
}
|
195
|
+
end
|
196
|
+
|
197
|
+
def matching_any_of_multiple_selectors(selectors)
|
198
|
+
query_ids = QueryIds.from_selectors(selectors)
|
199
|
+
join_verifications_for(query_ids)
|
200
|
+
.join_pacticipants_and_pacticipant_versions
|
201
|
+
.where {
|
202
|
+
Sequel.&(
|
203
|
+
Sequel.|(
|
204
|
+
QueryBuilder.consumer_or_consumer_version_matches(query_ids, :p),
|
205
|
+
QueryBuilder.provider_or_provider_version_matches_or_pact_unverified(query_ids, :v),
|
206
|
+
),
|
207
|
+
QueryBuilder.either_consumer_or_provider_was_specified_in_query(query_ids, :p)
|
156
208
|
)
|
157
209
|
}
|
158
210
|
end
|
159
211
|
|
160
212
|
def join_verifications_for(query_ids)
|
161
|
-
left_outer_join(verifications_for(query_ids), LP_LV_JOIN, { table_alias: :
|
213
|
+
left_outer_join(verifications_for(query_ids), LP_LV_JOIN, { table_alias: :v } )
|
162
214
|
end
|
163
215
|
|
164
216
|
def verifications_for(query_ids)
|
@@ -179,12 +231,20 @@ module PactBroker
|
|
179
231
|
.join_provider_versions
|
180
232
|
end
|
181
233
|
|
182
|
-
def join_consumers
|
183
|
-
join(
|
234
|
+
def join_consumers qualifier = :p, table_alias = :consumers
|
235
|
+
join(
|
236
|
+
:pacticipants,
|
237
|
+
{ Sequel[qualifier][:consumer_id] => Sequel[table_alias][:id] },
|
238
|
+
{ table_alias: table_alias }
|
239
|
+
)
|
184
240
|
end
|
185
241
|
|
186
|
-
def join_providers
|
187
|
-
join(
|
242
|
+
def join_providers qualifier = :p, table_alias = :providers
|
243
|
+
join(
|
244
|
+
:pacticipants,
|
245
|
+
{ Sequel[qualifier][:provider_id] => Sequel[table_alias][:id] },
|
246
|
+
{ table_alias: table_alias }
|
247
|
+
)
|
188
248
|
end
|
189
249
|
|
190
250
|
def join_consumer_versions
|
@@ -196,7 +256,11 @@ module PactBroker
|
|
196
256
|
end
|
197
257
|
|
198
258
|
def join_verifications
|
199
|
-
left_outer_join(LV, LP_LV_JOIN, { table_alias: :
|
259
|
+
left_outer_join(LV, LP_LV_JOIN, { table_alias: :v } )
|
260
|
+
end
|
261
|
+
|
262
|
+
def inner_join_verifications
|
263
|
+
join(LV, LP_LV_JOIN, { table_alias: :v } )
|
200
264
|
end
|
201
265
|
end # end dataset_module
|
202
266
|
|
@@ -306,6 +370,10 @@ module PactBroker
|
|
306
370
|
return_or_raise_if_not_set(:provider_version_order)
|
307
371
|
end
|
308
372
|
|
373
|
+
def has_verification?
|
374
|
+
!!verification_id
|
375
|
+
end
|
376
|
+
|
309
377
|
# This model needs the verifications and pacticipants joined to it
|
310
378
|
# before it can be used, as it's not a "real" model.
|
311
379
|
def return_or_raise_if_not_set(key)
|