pact_broker 2.119.0 → 2.121.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +579 -479
- data/Gemfile +2 -6
- data/README.md +1 -2
- data/db/migrations/000015_create_pact_version_content.rb +1 -1
- data/db/migrations/000023_create_pact_versions_table.rb +1 -1
- data/db/migrations/000033_create_config_table.rb +1 -1
- data/db/migrations/000036_create_webhook_execution.rb +1 -1
- data/db/migrations/20180108_create_certificates_table.rb +1 -1
- data/db/migrations/migration_helper.rb +5 -1
- data/docs/CONFIGURATION.md +29 -2
- data/docs/matrix-optimisation/README.md +85 -0
- data/lib/pact/doc/interaction_view_model.rb +2 -1
- data/lib/pact/doc/markdown/consumer_contract_renderer.rb +3 -1
- data/lib/pact/doc.rb +5 -0
- data/lib/pact_broker/api/contracts/put_pact_params_contract.rb +2 -0
- data/lib/pact_broker/api/decorators/provider_states_decorator.rb +1 -1
- data/lib/pact_broker/api/decorators/triggered_webhook_logs_decorator.rb +4 -0
- data/lib/pact_broker/api/decorators/version_decorator.rb +29 -4
- data/lib/pact_broker/api/pact_broker_urls.rb +4 -0
- data/lib/pact_broker/api/resources/branch_versions.rb +5 -1
- data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment.rb +4 -1
- data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment_badge.rb +1 -0
- data/lib/pact_broker/api/resources/clean.rb +9 -1
- data/lib/pact_broker/api/resources/deployed_or_released_versions.rb +78 -0
- data/lib/pact_broker/api/resources/environment_versions.rb +89 -0
- data/lib/pact_broker/api/resources/pacticipants_for_label.rb +29 -1
- data/lib/pact_broker/api/resources/tag_versions.rb +5 -1
- data/lib/pact_broker/api/resources/version.rb +5 -1
- data/lib/pact_broker/api/resources/versions.rb +5 -1
- data/lib/pact_broker/api.rb +2 -0
- data/lib/pact_broker/app.rb +0 -1
- data/lib/pact_broker/config/runtime_configuration.rb +19 -0
- data/lib/pact_broker/configuration.rb +15 -2
- data/lib/pact_broker/dataset.rb +4 -23
- data/lib/pact_broker/db/clean/branch_selector.rb +40 -0
- data/lib/pact_broker/db/clean.rb +45 -0
- data/lib/pact_broker/db/clean_incremental.rb +78 -14
- data/lib/pact_broker/db.rb +0 -7
- data/lib/pact_broker/deployments/released_version_service.rb +14 -0
- data/lib/pact_broker/domain/version.rb +6 -2
- data/lib/pact_broker/initializers/database_connection.rb +5 -0
- data/lib/pact_broker/integrations/repository.rb +1 -1
- data/lib/pact_broker/integrations/service.rb +1 -3
- data/lib/pact_broker/logging/open_telemetry_appender_setup.rb +73 -0
- data/lib/pact_broker/logging/trace_aware_json_formatter.rb +38 -0
- data/lib/pact_broker/matrix/matrix_row_dataset_module.rb +29 -11
- data/lib/pact_broker/matrix/matrix_row_verification_dataset_module.rb +23 -12
- data/lib/pact_broker/matrix/parse_can_i_deploy_query.rb +5 -0
- data/lib/pact_broker/matrix/selector_resolver.rb +30 -2
- data/lib/pact_broker/pacticipants/repository.rb +5 -2
- data/lib/pact_broker/pacts/service.rb +2 -2
- data/lib/pact_broker/tags/service.rb +4 -5
- data/lib/pact_broker/tasks/clean_task.rb +23 -1
- data/lib/pact_broker/verifications/repository.rb +1 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/versions/branch_repository.rb +1 -1
- data/lib/pact_broker/versions/branch_service.rb +1 -1
- data/lib/pact_broker/versions/branch_version_repository.rb +3 -2
- data/lib/pact_broker/versions/repository.rb +4 -13
- data/lib/pact_broker/webhooks/render.rb +1 -1
- data/lib/sequel/plugins/upsert.rb +1 -8
- data/pact_broker.gemspec +8 -7
- metadata +38 -32
data/Gemfile
CHANGED
|
@@ -5,8 +5,6 @@ gemspec
|
|
|
5
5
|
|
|
6
6
|
gem "rake", "~> 13.3"
|
|
7
7
|
gem "sqlite3", ">=2.0.0"
|
|
8
|
-
gem "conventional-changelog", "~>1.3"
|
|
9
|
-
gem "bump", "~> 0.5"
|
|
10
8
|
gem "padrino-core", ">= 0.16.0.pre3", require: false
|
|
11
9
|
gem "rackup", "~> 2.2"
|
|
12
10
|
gem "thor", "~> 1.4" # thor is secondary dependency but bumping here to avoid CVEs
|
|
@@ -21,6 +19,8 @@ end
|
|
|
21
19
|
|
|
22
20
|
group :test do
|
|
23
21
|
gem "simplecov", :require => false
|
|
22
|
+
gem "simplecov-cobertura", :require => false
|
|
23
|
+
gem "rspec_junit_formatter", :require => false
|
|
24
24
|
if ENV["X_PACT_DEVELOPMENT"] == "true"
|
|
25
25
|
gem "pact", path: "../pact-ruby"
|
|
26
26
|
gem "pact-ffi", path: "../pact-ruby-ffi"
|
|
@@ -47,10 +47,6 @@ group :pg, optional: true do
|
|
|
47
47
|
gem "pg", "~>1.6"
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
group :mysql, optional: true do
|
|
51
|
-
gem "mysql2", "~>0.5"
|
|
52
|
-
end
|
|
53
|
-
|
|
54
50
|
if ENV["X_PACT_DEVELOPMENT"] == "true"
|
|
55
51
|
gem "pact-support", path: "../pact-support"
|
|
56
52
|
end
|
data/README.md
CHANGED
|
@@ -151,7 +151,6 @@ You can use the [Pact Broker Docker image][docker] or [Terraform on AWS][terrafo
|
|
|
151
151
|
* Are you sure you don't just want to use the [Pact Broker Docker image][docker]? No Docker at your company yet? Ah well, keep reading.
|
|
152
152
|
* Create a PostgreSQL database.
|
|
153
153
|
* To ensure you're on a supported version of the database that you choose, check the [.github/workflows/test.yml](.github/workflows/test.yml) file to see which versions we're currently running our tests against.
|
|
154
|
-
* MySQL was supported for the native Ruby application until around 2021, but the official `pactfoundation/pact-broker` Docker image does not support it. New features will not be optimised for MySQL, and some new features may not even be supported on it (eg. the database clean feature).
|
|
155
154
|
* You'll find a sample database creation script in the [example/config.ru](https://github.com/pact-foundation/pact_broker/blob/master/example/config.ru).
|
|
156
155
|
* Install ruby 2.7 and the latest version of bundler (if you've come this far, I'm assuming you know how to do both of these. Did I mention there was a [Docker][docker] image?)
|
|
157
156
|
* Copy the [pact\_broker](https://github.com/DiUS/pact_broker-docker/tree/master/pact_broker) directory from the Pact Broker Docker project. This will have the recommended settings for database connections, logging, basic auth etc. Note that the Docker image uses Phusion Passenger as the web application server in front of the Pact Broker Ruby application, which is the recommended set up if you are not using a containerized solution.
|
|
@@ -170,7 +169,7 @@ Please read the [UPGRADING.md](UPGRADING.md) documentation before upgrading your
|
|
|
170
169
|
|
|
171
170
|
The Pact Broker follows the [semantic versioning](https://semver.org/) scheme.
|
|
172
171
|
|
|
173
|
-
[decouple]: https://
|
|
172
|
+
[decouple]: https://docs.pact.io/pact_broker/can_i_deploy
|
|
174
173
|
[pact]: https://github.com/pact-foundation/pact-ruby
|
|
175
174
|
[nerf]: https://github.com/pact-foundation/pact_broker/wiki/pact-broker-ci-nerf-gun
|
|
176
175
|
[different-teams]: https://github.com/pact-foundation/pact-ruby/wiki/Using-pact-where-the-consumer-team-is-different-from-the-provider-team
|
|
@@ -5,7 +5,7 @@ Sequel.migration do
|
|
|
5
5
|
change do
|
|
6
6
|
create_table(:pact_version_contents, charset: "utf8") do
|
|
7
7
|
String :sha, primary_key: true, null: false, primary_key_constraint_name: "pk_pact_version_contents"
|
|
8
|
-
|
|
8
|
+
column :content, PactBroker::MigrationHelper.large_text_type
|
|
9
9
|
DateTime :created_at, null: false
|
|
10
10
|
DateTime :updated_at, null: false
|
|
11
11
|
end
|
|
@@ -7,7 +7,7 @@ Sequel.migration do
|
|
|
7
7
|
foreign_key :consumer_id, :pacticipants
|
|
8
8
|
foreign_key :provider_id, :pacticipants
|
|
9
9
|
String :sha, null: false
|
|
10
|
-
|
|
10
|
+
column :content, PactBroker::MigrationHelper.large_text_type
|
|
11
11
|
index [:consumer_id, :provider_id, :sha], unique: true, name: "unq_pvc_con_prov_sha"
|
|
12
12
|
DateTime :created_at, null: false
|
|
13
13
|
end
|
|
@@ -6,7 +6,7 @@ Sequel.migration do
|
|
|
6
6
|
primary_key :id
|
|
7
7
|
String :name, null: false
|
|
8
8
|
String :type, null: false
|
|
9
|
-
|
|
9
|
+
column :value, PactBroker::MigrationHelper.large_text_type
|
|
10
10
|
DateTime :created_at, null: false
|
|
11
11
|
DateTime :updated_at, null: false
|
|
12
12
|
index [:name], unique: true, name: "unq_config_name"
|
|
@@ -9,7 +9,7 @@ Sequel.migration do
|
|
|
9
9
|
foreign_key :consumer_id, :pacticipants, null: false
|
|
10
10
|
foreign_key :provider_id, :pacticipants, null: false
|
|
11
11
|
Boolean :success, null: false
|
|
12
|
-
|
|
12
|
+
column :logs, PactBroker::MigrationHelper.large_text_type
|
|
13
13
|
DateTime :created_at, null: false
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -6,7 +6,7 @@ Sequel.migration do
|
|
|
6
6
|
primary_key :id
|
|
7
7
|
String :uuid, null: false, unique: true, unique_constraint_name: "uq_certificate_uuid"
|
|
8
8
|
String :description, null: true
|
|
9
|
-
|
|
9
|
+
column :content, PactBroker::MigrationHelper.large_text_type, null: false
|
|
10
10
|
DateTime :created_at, null: false
|
|
11
11
|
DateTime :updated_at, null: false
|
|
12
12
|
end
|
|
@@ -10,7 +10,7 @@ module PactBroker
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def large_text_type
|
|
13
|
-
if postgres?
|
|
13
|
+
if postgres? || sqlite?
|
|
14
14
|
:text
|
|
15
15
|
else
|
|
16
16
|
# Assume mysql
|
|
@@ -32,6 +32,10 @@ module PactBroker
|
|
|
32
32
|
adapter =~ /postgres/
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
def sqlite?
|
|
36
|
+
adapter =~ /sqlite/
|
|
37
|
+
end
|
|
38
|
+
|
|
35
39
|
def adapter
|
|
36
40
|
Sequel::Model.db.adapter_scheme.to_s
|
|
37
41
|
end
|
data/docs/CONFIGURATION.md
CHANGED
|
@@ -34,6 +34,25 @@ The application log format. Can be any value supported by Semantic Logger.
|
|
|
34
34
|
**Allowed values:** `default`, `json`, `color`<br/>
|
|
35
35
|
**More information:** https://github.com/rocketjob/semantic_logger/tree/master/lib/semantic_logger/formatters<br/>
|
|
36
36
|
|
|
37
|
+
### log_otel_enabled
|
|
38
|
+
|
|
39
|
+
Controls whether logs are also emitted to the OpenTelemetry logs pipeline.
|
|
40
|
+
|
|
41
|
+
`auto` (the default) adds the OpenTelemetry appender only when the
|
|
42
|
+
`opentelemetry-logs-sdk` gem is installed and an OpenTelemetry logger provider
|
|
43
|
+
is configured. `true` forces the appender on and raises an error if the gem is
|
|
44
|
+
not available. `false` disables it entirely.
|
|
45
|
+
|
|
46
|
+
The `opentelemetry-logs-sdk` gem is an optional, runtime-detected dependency and
|
|
47
|
+
is not bundled with the Pact Broker. When `log_format` is set to `json`, active
|
|
48
|
+
trace and span IDs are also embedded in the JSON log output.
|
|
49
|
+
|
|
50
|
+
**Supported versions:** From v2.120.0<br/>
|
|
51
|
+
**Environment variable name:** `PACT_BROKER_LOG_OTEL_ENABLED`<br/>
|
|
52
|
+
**YAML configuration key name:** `log_otel_enabled`<br/>
|
|
53
|
+
**Default:** `auto`<br/>
|
|
54
|
+
**Allowed values:** `auto`, `true`, `false`<br/>
|
|
55
|
+
|
|
37
56
|
### log_dir
|
|
38
57
|
|
|
39
58
|
The log file directory
|
|
@@ -248,8 +267,8 @@ The number of seconds after which an SQL query will be aborted. Only supported f
|
|
|
248
267
|
|
|
249
268
|
**Environment variable name:** `PACT_BROKER_DATABASE_STATEMENT_TIMEOUT`<br/>
|
|
250
269
|
**YAML configuration key name:** `database_statement_timeout`<br/>
|
|
251
|
-
**Default:** `
|
|
252
|
-
**Allowed values:** A positive integer
|
|
270
|
+
**Default:** `15`<br/>
|
|
271
|
+
**Allowed values:** A positive integer or float.<br/>
|
|
253
272
|
**More information:** https://www.postgresql.org/docs/9.3/runtime-config-client.html<br/>
|
|
254
273
|
|
|
255
274
|
### metrics_sql_statement_timeout
|
|
@@ -533,6 +552,14 @@ The URL of the shields.io server used to generate the README badges.
|
|
|
533
552
|
**Default:** `https://img.shields.io`<br/>
|
|
534
553
|
**More information:** https://shields.io<br/>
|
|
535
554
|
|
|
555
|
+
### badge_default_cache_setting
|
|
556
|
+
|
|
557
|
+
Cache Control header value for the badge, this sets the cache-control header for the badge image, for more information on header formats see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cache-control
|
|
558
|
+
|
|
559
|
+
**Environment variable name:** `PACT_BROKER_BADGE_DEFAULT_CACHE_SETTING`<br/>
|
|
560
|
+
**YAML configuration key name:** `badge_default_cache_setting`<br/>
|
|
561
|
+
**Default:** `max-age=30`<br/>
|
|
562
|
+
|
|
536
563
|
### badge_provider_mode
|
|
537
564
|
|
|
538
565
|
The method by which the badges are generated. When set to `redirect`, a request to the Pact Broker for a badge will be sent a redirect response
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Matrix query baselines
|
|
2
|
+
|
|
3
|
+
Tooling to capture a query-profile baseline (per-request query count, exact SQL,
|
|
4
|
+
and `EXPLAIN` plans) for the `/matrix` and `/can-i-deploy` endpoints, so query
|
|
5
|
+
cost can be compared before and after changes to the query engine.
|
|
6
|
+
|
|
7
|
+
The generated baseline files (`baseline-*.md`) are **git-ignored** — generate them
|
|
8
|
+
locally and diff two runs; they are not committed.
|
|
9
|
+
|
|
10
|
+
## Generate a baseline (Postgres)
|
|
11
|
+
|
|
12
|
+
Baselines are generated against **Postgres** (the production backend). Start a
|
|
13
|
+
throwaway Postgres with the dev compose file:
|
|
14
|
+
|
|
15
|
+
docker compose -f docker-compose-dev-postgres.yml up -d postgres
|
|
16
|
+
|
|
17
|
+
The Postgres version is controlled by `POSTGRES_VERSION` (default `15`),
|
|
18
|
+
so a baseline can be captured against a specific major version:
|
|
19
|
+
|
|
20
|
+
POSTGRES_VERSION=14 docker compose -f docker-compose-dev-postgres.yml up -d postgres
|
|
21
|
+
|
|
22
|
+
The `pg` driver lives in an optional bundle group, so it must be installed and
|
|
23
|
+
enabled explicitly — without `BUNDLE_WITH=pg` the run fails with
|
|
24
|
+
`LoadError: cannot load such file -- pg`:
|
|
25
|
+
|
|
26
|
+
BUNDLE_WITH=pg bundle install
|
|
27
|
+
|
|
28
|
+
Point the suite at the database and run the generator:
|
|
29
|
+
|
|
30
|
+
BUNDLE_WITH=pg \
|
|
31
|
+
PACT_BROKER_TEST_DATABASE_URL="postgres://postgres:postgres@localhost:5432/postgres" \
|
|
32
|
+
bundle exec rspec spec/benchmarks/matrix_baseline_spec.rb --tag matrix_baseline
|
|
33
|
+
|
|
34
|
+
This writes `docs/matrix-optimisation/baseline-postgres.md`. Tear the container down
|
|
35
|
+
with `docker compose -f docker-compose-dev-postgres.yml down -v` when done.
|
|
36
|
+
|
|
37
|
+
> Postgres 18 and later relocated the data directory, which is incompatible with
|
|
38
|
+
> the `/var/lib/postgresql/data` volume mount in `docker-compose-dev-postgres.yml`;
|
|
39
|
+
> the container exits on startup. Use a tag of `17` or lower until that mount is
|
|
40
|
+
> updated.
|
|
41
|
+
|
|
42
|
+
The generator is tagged `matrix_baseline` and excluded from the default test run;
|
|
43
|
+
it only executes when invoked with `--tag matrix_baseline`. Against a non-Postgres
|
|
44
|
+
database it skips with a message.
|
|
45
|
+
|
|
46
|
+
## What's captured
|
|
47
|
+
|
|
48
|
+
For each request shape (see `spec/support/matrix_baseline/shapes.rb`), the file
|
|
49
|
+
records, inside collapsible sections:
|
|
50
|
+
|
|
51
|
+
- the number of SQL statements the request issued (main query + eager loads);
|
|
52
|
+
- the exact SQL of each statement;
|
|
53
|
+
- its `EXPLAIN` plan.
|
|
54
|
+
|
|
55
|
+
Plans are captured with `EXPLAIN (ANALYZE, BUFFERS, TIMING OFF)`. That keeps the
|
|
56
|
+
measures of work done — estimated cost, actual row counts, buffer hit/read
|
|
57
|
+
counts, sort and hash memory usage — and drops the measures of how fast this
|
|
58
|
+
particular machine did it. Wall-clock figures are excluded deliberately: they
|
|
59
|
+
vary with unrelated load and would swamp the diff.
|
|
60
|
+
|
|
61
|
+
## Comparing runs
|
|
62
|
+
|
|
63
|
+
**Two runs against unchanged code produce a byte-identical file.** Any diff at
|
|
64
|
+
all is a real difference in what the query engine did. Regenerate and diff two
|
|
65
|
+
`baseline-postgres.md` files to compare:
|
|
66
|
+
|
|
67
|
+
- **query count** per shape (the `N queries` in each section heading);
|
|
68
|
+
- **plan shape** — sequential vs index scans, sorts, join types, UNION branch count;
|
|
69
|
+
- **estimated cost, actual rows, buffers and memory usage** per plan node.
|
|
70
|
+
|
|
71
|
+
Determinism depends on the generator resetting the database itself — it
|
|
72
|
+
truncates with `RESTART IDENTITY` so surrogate keys in the captured SQL are
|
|
73
|
+
stable, and runs `VACUUM ANALYZE` so plans are chosen against real statistics
|
|
74
|
+
on an unbloated heap. That is why it is tagged `no_db_clean` and will wipe the
|
|
75
|
+
database it is pointed at. **Point it at a throwaway Postgres, never at a
|
|
76
|
+
database whose contents you want to keep.**
|
|
77
|
+
|
|
78
|
+
## Limitations
|
|
79
|
+
|
|
80
|
+
- The seed is a few hundred rows per table. Postgres will often choose a
|
|
81
|
+
sequential scan at this size regardless of index quality, so a plan-shape
|
|
82
|
+
change here does not automatically imply the same change in production. Query
|
|
83
|
+
counts and join structure transfer; scan choice on small tables may not.
|
|
84
|
+
- The success filter and can-i-deploy's `--ignore` are applied in Ruby after
|
|
85
|
+
the query, so their shapes exercise no extra SQL beyond selector resolution.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require "pact/shared/active_support_support"
|
|
2
2
|
require "pact/reification"
|
|
3
3
|
require "cgi"
|
|
4
|
+
require "pact/doc"
|
|
4
5
|
|
|
5
6
|
module Pact
|
|
6
7
|
module Doc
|
|
@@ -149,7 +150,7 @@ module Pact
|
|
|
149
150
|
|
|
150
151
|
def markdown_escape string
|
|
151
152
|
return nil unless string
|
|
152
|
-
string.gsub(
|
|
153
|
+
string.gsub(Pact::Doc::MARKDOWN_SPECIAL_CHARS_REGEXP) { |char| "\\#{char}" }
|
|
153
154
|
end
|
|
154
155
|
end
|
|
155
156
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require "pact/doc/markdown/interaction_renderer"
|
|
2
2
|
require "pact/doc/sort_interactions"
|
|
3
3
|
require "rack/utils"
|
|
4
|
+
require "pact/doc"
|
|
4
5
|
|
|
5
6
|
module Pact
|
|
6
7
|
module Doc
|
|
@@ -60,7 +61,8 @@ module Pact
|
|
|
60
61
|
end
|
|
61
62
|
|
|
62
63
|
def markdown_escape string
|
|
63
|
-
string
|
|
64
|
+
return nil unless string
|
|
65
|
+
string.gsub(Pact::Doc::MARKDOWN_SPECIAL_CHARS_REGEXP) { |char| "\\#{char}" }
|
|
64
66
|
end
|
|
65
67
|
|
|
66
68
|
def h(text)
|
data/lib/pact/doc.rb
ADDED
|
@@ -10,6 +10,8 @@ module PactBroker
|
|
|
10
10
|
required(:name_in_pact).maybe(:string)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
rule(:name).validate(:not_blank_if_present)
|
|
14
|
+
|
|
13
15
|
rule(:name, :name_in_pact) do
|
|
14
16
|
if name_in_pact_does_not_match_name_in_url_path?(values)
|
|
15
17
|
key.failure(validation_message("pact_name_in_path_mismatch_name_in_pact", name_in_pact: values[:name_in_pact], name_in_path: values[:name]))
|
|
@@ -26,7 +26,7 @@ module PactBroker
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
consumers_map.map do |(name, params), consumers|
|
|
29
|
-
{ name: name, params: params, consumers: consumers.uniq }
|
|
29
|
+
{ name: name, params: params, consumers: consumers.uniq.sort }
|
|
30
30
|
end
|
|
31
31
|
.sort_by { |provider_state| provider_state[:name] }
|
|
32
32
|
}, :extend => PactBroker::Api::Decorators::ProviderStateDecorator
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require_relative "base_decorator"
|
|
2
2
|
require_relative "embedded_tag_decorator"
|
|
3
3
|
require_relative "embedded_branch_version_decorator"
|
|
4
|
+
require_relative "format_date_time"
|
|
4
5
|
|
|
5
6
|
module PactBroker
|
|
6
7
|
module Api
|
|
@@ -74,21 +75,45 @@ module PactBroker
|
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
links :'pb:deployed-environments' do | context |
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
|
|
78
|
+
# NB: use fully-qualified ::Hash. The tins gem shadows the bare `Hash`
|
|
79
|
+
# constant in this scope, so `is_a?(Hash)` returns false even for a real
|
|
80
|
+
# Hash (this is the collection-vs-single-item branch: the collection
|
|
81
|
+
# resource passes a version_id-keyed Hash, the single resource an Array).
|
|
82
|
+
deployed_versions = context.dig(:deployed_versions)
|
|
83
|
+
deployed_versions = deployed_versions[represented.id] if deployed_versions.is_a?(::Hash)
|
|
80
84
|
deployed_versions&.collect do | deployed_version |
|
|
81
85
|
{
|
|
82
86
|
title: "Version deployed to #{deployed_version.environment.display_name}",
|
|
83
87
|
name: deployed_version.environment.display_name,
|
|
84
88
|
href: deployed_version_url(deployed_version, context.fetch(:base_url)),
|
|
85
|
-
currently_deployed: deployed_version.currently_deployed
|
|
89
|
+
currently_deployed: deployed_version.currently_deployed,
|
|
90
|
+
deployed_at: FormatDateTime.call(deployed_version.created_at),
|
|
91
|
+
undeployed_at: FormatDateTime.call(deployed_version.undeployed_at)
|
|
86
92
|
}.tap do |hash|
|
|
87
93
|
hash[:application_instance] = deployed_version.application_instance unless deployed_version.application_instance.nil?
|
|
88
94
|
end
|
|
89
95
|
end
|
|
90
96
|
end
|
|
91
97
|
|
|
98
|
+
links :'pb:released-environments' do | context |
|
|
99
|
+
# NB: use fully-qualified ::Hash. The tins gem shadows the bare `Hash`
|
|
100
|
+
# constant in this scope, so `is_a?(Hash)` returns false even for a real
|
|
101
|
+
# Hash (this is the collection-vs-single-item branch: the collection
|
|
102
|
+
# resource passes a version_id-keyed Hash, the single resource an Array).
|
|
103
|
+
released_versions = context.dig(:released_versions)
|
|
104
|
+
released_versions = released_versions[represented.id] if released_versions.is_a?(::Hash)
|
|
105
|
+
released_versions&.collect do | released_version |
|
|
106
|
+
{
|
|
107
|
+
title: "Version released to #{released_version.environment.display_name}",
|
|
108
|
+
name: released_version.environment.display_name,
|
|
109
|
+
href: released_version_url(released_version, context.fetch(:base_url)),
|
|
110
|
+
currently_supported: released_version.currently_supported,
|
|
111
|
+
released_at: FormatDateTime.call(released_version.created_at),
|
|
112
|
+
support_ended_at: FormatDateTime.call(released_version.support_ended_at)
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
92
117
|
links :'pb:record-deployment' do | context |
|
|
93
118
|
context[:environments]&.collect do | environment |
|
|
94
119
|
{
|
|
@@ -370,6 +370,10 @@ module PactBroker
|
|
|
370
370
|
"#{environments_url(base_url)}/#{environment.uuid}"
|
|
371
371
|
end
|
|
372
372
|
|
|
373
|
+
def environment_versions_url(pacticipant, environment, base_url = "")
|
|
374
|
+
"#{pacticipant_url(base_url, pacticipant)}/environments/#{environment.uuid}/versions"
|
|
375
|
+
end
|
|
376
|
+
|
|
373
377
|
def deployed_versions_for_version_and_environment_url(version, environment, base_url = "")
|
|
374
378
|
"#{version_url(base_url, version)}/deployed-versions/environment/#{environment.uuid}"
|
|
375
379
|
end
|
|
@@ -27,7 +27,7 @@ module PactBroker
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def to_json
|
|
30
|
-
decorator_class(:versions_decorator).new(versions).to_json(**decorator_options(identifier_from_path.merge(resource_title: resource_title, deployed_versions: deployed_versions)))
|
|
30
|
+
decorator_class(:versions_decorator).new(versions).to_json(**decorator_options(identifier_from_path.merge(resource_title: resource_title, deployed_versions: deployed_versions, released_versions: released_versions)))
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def versions
|
|
@@ -38,6 +38,10 @@ module PactBroker
|
|
|
38
38
|
@deployed_versions ||= deployed_version_service.find_deployed_versions_for_versions(versions)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def released_versions
|
|
42
|
+
@released_versions ||= released_version_service.find_released_versions_for_versions(versions)
|
|
43
|
+
end
|
|
44
|
+
|
|
41
45
|
def policy_name
|
|
42
46
|
:'versions::versions'
|
|
43
47
|
end
|
data/lib/pact_broker/api/resources/can_i_deploy_pacticipant_version_by_branch_to_environment.rb
CHANGED
|
@@ -37,8 +37,11 @@ module PactBroker
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def options
|
|
40
|
+
# "cvpv" (not "cvp") so that every version of an integrated application that is currently
|
|
41
|
+
# released/deployed to the environment is evaluated independently, rather than collapsing
|
|
42
|
+
# to just the latest provider version (which hides still-live incompatible versions). See issue #903.
|
|
40
43
|
@options ||= {
|
|
41
|
-
latestby: "
|
|
44
|
+
latestby: "cvpv",
|
|
42
45
|
environment_name: identifier_from_path[:environment_name]
|
|
43
46
|
}
|
|
44
47
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "pact_broker/api/resources/base_resource"
|
|
2
2
|
require "pact_broker/db/clean"
|
|
3
|
+
require "pact_broker/db/clean/branch_selector"
|
|
3
4
|
require "pact_broker/matrix/unresolved_selector"
|
|
4
5
|
|
|
5
6
|
# Not exposed yet as we'd need to support administrator auth first
|
|
@@ -22,7 +23,14 @@ module PactBroker
|
|
|
22
23
|
PactBroker::DB::Clean::Selector.new(hash)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
keep_branch_selectors = (params[:keep_branches] || []).collect do | hash |
|
|
27
|
+
PactBroker::DB::Clean::BranchSelector.from_hash(hash)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
result = PactBroker::DB::Clean.call(Sequel::Model.db, {
|
|
31
|
+
keep: keep_selectors,
|
|
32
|
+
keep_branches: keep_branch_selectors.empty? ? nil : keep_branch_selectors
|
|
33
|
+
})
|
|
26
34
|
response.body = result.to_json
|
|
27
35
|
else
|
|
28
36
|
415
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require "pact_broker/api/resources/base_resource"
|
|
2
|
+
require "pact_broker/api/decorators/versions_decorator"
|
|
3
|
+
require "pact_broker/api/resources/pagination_methods"
|
|
4
|
+
|
|
5
|
+
module PactBroker
|
|
6
|
+
module Api
|
|
7
|
+
module Resources
|
|
8
|
+
class DeployedOrReleasedVersions < BaseResource
|
|
9
|
+
include PaginationMethods
|
|
10
|
+
|
|
11
|
+
def content_types_provided
|
|
12
|
+
[["application/hal+json", :to_json]]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def allowed_methods
|
|
16
|
+
["GET", "OPTIONS"]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def malformed_request?
|
|
20
|
+
super || request.get? && validation_errors_for_schema?(schema, request.query)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def resource_exists?
|
|
24
|
+
!!pacticipant
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_json
|
|
28
|
+
decorator_class(:versions_decorator).new(versions).to_json(
|
|
29
|
+
**decorator_options(
|
|
30
|
+
identifier_from_path.merge(
|
|
31
|
+
resource_title: "Versions of #{pacticipant_name} that have been deployed or released",
|
|
32
|
+
deployed_versions: deployed_versions,
|
|
33
|
+
released_versions: released_versions
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def policy_name
|
|
40
|
+
:'versions::versions'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def versions
|
|
46
|
+
@versions ||= version_service.find_by_ids_in_reverse_order(
|
|
47
|
+
version_ids,
|
|
48
|
+
pagination_options,
|
|
49
|
+
decorator_class(:versions_decorator).eager_load_associations
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def version_ids
|
|
54
|
+
PactBroker::Deployments::DeployedVersion
|
|
55
|
+
.for_pacticipant_name(pacticipant_name)
|
|
56
|
+
.select(:version_id)
|
|
57
|
+
.union(
|
|
58
|
+
PactBroker::Deployments::ReleasedVersion
|
|
59
|
+
.for_pacticipant_name(pacticipant_name)
|
|
60
|
+
.select(:version_id)
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def deployed_versions
|
|
65
|
+
@deployed_versions ||= deployed_version_service.find_deployed_versions_for_versions(versions)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def released_versions
|
|
69
|
+
@released_versions ||= released_version_service.find_released_versions_for_versions(versions)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def schema
|
|
73
|
+
PactBroker::Api::Contracts::PaginationQueryParamsSchema if request.get?
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require "pact_broker/api/resources/base_resource"
|
|
2
|
+
require "pact_broker/api/decorators/versions_decorator"
|
|
3
|
+
require "pact_broker/api/resources/pagination_methods"
|
|
4
|
+
|
|
5
|
+
module PactBroker
|
|
6
|
+
module Api
|
|
7
|
+
module Resources
|
|
8
|
+
class EnvironmentVersions < BaseResource
|
|
9
|
+
include PaginationMethods
|
|
10
|
+
|
|
11
|
+
def content_types_provided
|
|
12
|
+
[["application/hal+json", :to_json]]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def allowed_methods
|
|
16
|
+
["GET", "OPTIONS"]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def malformed_request?
|
|
20
|
+
super || request.get? && validation_errors_for_schema?(schema, request.query)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def resource_exists?
|
|
24
|
+
!!environment && !!pacticipant
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_json
|
|
28
|
+
decorator_class(:versions_decorator).new(versions).to_json(
|
|
29
|
+
**decorator_options(
|
|
30
|
+
identifier_from_path.merge(
|
|
31
|
+
resource_title: resource_title,
|
|
32
|
+
deployed_versions: deployed_versions,
|
|
33
|
+
released_versions: released_versions
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def policy_name
|
|
40
|
+
:'versions::versions'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def versions
|
|
46
|
+
@versions ||= version_service.find_by_ids_in_reverse_order(
|
|
47
|
+
version_ids,
|
|
48
|
+
pagination_options,
|
|
49
|
+
decorator_class(:versions_decorator).eager_load_associations
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def version_ids
|
|
54
|
+
deployed_ids = PactBroker::Deployments::DeployedVersion
|
|
55
|
+
.for_environment(environment)
|
|
56
|
+
.for_pacticipant_name(pacticipant_name)
|
|
57
|
+
.select_map(:version_id)
|
|
58
|
+
|
|
59
|
+
released_ids = PactBroker::Deployments::ReleasedVersion
|
|
60
|
+
.for_environment(environment)
|
|
61
|
+
.for_pacticipant_name(pacticipant_name)
|
|
62
|
+
.select_map(:version_id)
|
|
63
|
+
|
|
64
|
+
(deployed_ids + released_ids).uniq
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def deployed_versions
|
|
68
|
+
@deployed_versions ||= deployed_version_service.find_deployed_versions_for_versions(versions)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def released_versions
|
|
72
|
+
@released_versions ||= released_version_service.find_released_versions_for_versions(versions)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def environment
|
|
76
|
+
@environment ||= environment_service.find(identifier_from_path[:environment_uuid])
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def resource_title
|
|
80
|
+
"Versions for #{pacticipant.name} in environment #{environment.display_name}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def schema
|
|
84
|
+
PactBroker::Api::Contracts::PaginationQueryParamsSchema if request.get?
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|