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
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
require "pact_broker/api/resources/base_resource"
|
|
2
2
|
require "pact_broker/api/decorators/pacticipants_decorator"
|
|
3
|
+
require "pact_broker/api/resources/pagination_methods"
|
|
3
4
|
|
|
4
5
|
module PactBroker
|
|
5
6
|
module Api
|
|
6
7
|
module Resources
|
|
7
8
|
class PacticipantsForLabel < BaseResource
|
|
9
|
+
include PaginationMethods
|
|
8
10
|
|
|
9
11
|
def content_types_provided
|
|
10
12
|
[["application/hal+json", :to_json]]
|
|
@@ -14,8 +16,18 @@ module PactBroker
|
|
|
14
16
|
["GET", "OPTIONS"]
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
def malformed_request?
|
|
20
|
+
if super
|
|
21
|
+
true
|
|
22
|
+
elsif request.get? && validation_errors_for_schema?(schema, request.query)
|
|
23
|
+
true
|
|
24
|
+
else
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
17
29
|
def to_json
|
|
18
|
-
generate_json(pacticipant_service.
|
|
30
|
+
generate_json(pacticipant_service.find_all_pacticipants(filter_options, pagination_options, eager_load_associations))
|
|
19
31
|
end
|
|
20
32
|
|
|
21
33
|
def generate_json pacticipants
|
|
@@ -25,6 +37,22 @@ module PactBroker
|
|
|
25
37
|
def policy_name
|
|
26
38
|
:'pacticipants::pacticipants'
|
|
27
39
|
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def schema
|
|
44
|
+
PactBroker::Api::Contracts::PaginationQueryParamsSchema
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def eager_load_associations
|
|
48
|
+
decorator_class(:pacticipants_decorator).eager_load_associations
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def filter_options
|
|
52
|
+
options = { label_name: identifier_from_path[:label_name] }
|
|
53
|
+
options[:query_string] = request.query["q"] if request.query.has_key?("q")
|
|
54
|
+
options
|
|
55
|
+
end
|
|
28
56
|
end
|
|
29
57
|
end
|
|
30
58
|
end
|
|
@@ -30,7 +30,7 @@ module PactBroker
|
|
|
30
30
|
|
|
31
31
|
def to_json
|
|
32
32
|
decorator_class(:versions_decorator).new(tag_versions)
|
|
33
|
-
.to_json(**decorator_options(deployed_versions: deployed_versions))
|
|
33
|
+
.to_json(**decorator_options(identifier_from_path.merge(deployed_versions: deployed_versions, released_versions: released_versions)))
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
private
|
|
@@ -39,6 +39,10 @@ module PactBroker
|
|
|
39
39
|
@deployed_versions ||= deployed_version_service.find_deployed_versions_for_versions(tag_versions)
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
def released_versions
|
|
43
|
+
@released_versions ||= released_version_service.find_released_versions_for_versions(tag_versions)
|
|
44
|
+
end
|
|
45
|
+
|
|
42
46
|
def tag_versions
|
|
43
47
|
@versions ||= version_service.find_by_ids_in_reverse_order(@tags.select_map(:version_id), pagination_options, decorator_class(:versions_decorator).eager_load_associations)
|
|
44
48
|
end
|
|
@@ -54,7 +54,7 @@ module PactBroker
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def to_json
|
|
57
|
-
decorator_class(:version_decorator).new(version).to_json(**decorator_options(environments: environments, deployed_versions: deployed_versions))
|
|
57
|
+
decorator_class(:version_decorator).new(version).to_json(**decorator_options(environments: environments, deployed_versions: deployed_versions, released_versions: released_versions))
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def delete_resource
|
|
@@ -87,6 +87,10 @@ module PactBroker
|
|
|
87
87
|
@deployed_versions ||= deployed_version_service.find_deployed_versions_for_version(version)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
+
def released_versions
|
|
91
|
+
@released_versions ||= released_version_service.find_released_versions_for_version(version)
|
|
92
|
+
end
|
|
93
|
+
|
|
90
94
|
def version
|
|
91
95
|
@version ||= version_service.find_by_pacticipant_name_and_number(identifier_from_path)
|
|
92
96
|
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(deployed_versions: deployed_versions)))
|
|
30
|
+
decorator_class(:versions_decorator).new(versions).to_json(**decorator_options(identifier_from_path.merge(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.rb
CHANGED
|
@@ -104,7 +104,9 @@ module PactBroker
|
|
|
104
104
|
|
|
105
105
|
# Versions
|
|
106
106
|
add ["pacticipants", :pacticipant_name, "versions"], Api::Resources::Versions, {resource_name: "pacticipant_versions"}
|
|
107
|
+
add ["pacticipants", :pacticipant_name, "deployed-or-released", "versions"], Api::Resources::DeployedOrReleasedVersions, {resource_name: "pacticipant_deployed_or_released_versions"}
|
|
107
108
|
add ["pacticipants", :pacticipant_name, "branches", :branch_name, "versions"], Api::Resources::BranchVersions, {resource_name: "pacticipant_branch_versions"}
|
|
109
|
+
add ["pacticipants", :pacticipant_name, "environments", :environment_uuid, "versions"], Api::Resources::EnvironmentVersions, {resource_name: "pacticipant_environment_versions"}
|
|
108
110
|
add ["pacticipants", :pacticipant_name, "versions", :pacticipant_version_number], Api::Resources::Version, {resource_name: "pacticipant_version"}
|
|
109
111
|
add ["pacticipants", :pacticipant_name, "latest-version", :tag], Api::Resources::LatestVersion, {resource_name: "latest_tagged_pacticipant_version"}
|
|
110
112
|
add ["pacticipants", :pacticipant_name, "latest-version", :tag, "can-i-deploy", "to", :to], Api::Resources::CanIDeployPacticipantVersionByTagToTag, { resource_name: "can_i_deploy_latest_tagged_version_to_tag" }
|
data/lib/pact_broker/app.rb
CHANGED
|
@@ -148,7 +148,6 @@ module PactBroker
|
|
|
148
148
|
configuration.database_connection ||= PactBroker.create_database_connection(configuration.database_configuration, configuration.logger)
|
|
149
149
|
PactBroker::DB.connection = configuration.database_connection
|
|
150
150
|
PactBroker::DB.validate_connection_config if configuration.validate_database_connection_config
|
|
151
|
-
PactBroker::DB.set_mysql_strict_mode_if_mysql
|
|
152
151
|
PactBroker::DB.connection.extension(:pagination)
|
|
153
152
|
PactBroker::DB.connection.extension(:statement_timeout)
|
|
154
153
|
PactBroker::DB.connection.extension(:any_not_empty)
|
|
@@ -40,6 +40,7 @@ module PactBroker
|
|
|
40
40
|
log_stream: :file,
|
|
41
41
|
log_level: :info,
|
|
42
42
|
log_format: nil,
|
|
43
|
+
log_otel_enabled: :auto,
|
|
43
44
|
warning_error_class_names: ["Sequel::ForeignKeyConstraintViolation"],
|
|
44
45
|
hide_pactflow_messages: false,
|
|
45
46
|
log_configuration_on_startup: true,
|
|
@@ -129,6 +130,10 @@ module PactBroker
|
|
|
129
130
|
super(log_format&.to_sym)
|
|
130
131
|
end
|
|
131
132
|
|
|
133
|
+
def log_otel_enabled= value
|
|
134
|
+
super(coerce_log_otel_enabled(value))
|
|
135
|
+
end
|
|
136
|
+
|
|
132
137
|
def custom_log_formatters= custom_log_formatters
|
|
133
138
|
super(custom_log_formatters&.symbolize_keys)
|
|
134
139
|
end
|
|
@@ -215,12 +220,26 @@ module PactBroker
|
|
|
215
220
|
if log_stream == :file && log_dir.blank?
|
|
216
221
|
raise_validation_error("Must specify log_dir if log_stream is set to file")
|
|
217
222
|
end
|
|
223
|
+
|
|
224
|
+
unless [:auto, true, false].include?(log_otel_enabled)
|
|
225
|
+
raise_validation_error("log_otel_enabled must be one of: auto, true, false")
|
|
226
|
+
end
|
|
218
227
|
end
|
|
219
228
|
|
|
220
229
|
def raise_validation_error(msg)
|
|
221
230
|
raise PactBroker::ConfigurationError, msg
|
|
222
231
|
end
|
|
223
232
|
|
|
233
|
+
def coerce_log_otel_enabled(value)
|
|
234
|
+
case value
|
|
235
|
+
when nil, "", "auto", :auto then :auto
|
|
236
|
+
when true, "true", "1", 1 then true
|
|
237
|
+
when false, "false", "0", 0 then false
|
|
238
|
+
else value
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
private :coerce_log_otel_enabled
|
|
242
|
+
|
|
224
243
|
def set_webhook_attribute_defaults
|
|
225
244
|
# can't set a default on this, or anyway config blows up when trying to merge the
|
|
226
245
|
# hash from the env vars into an array/nil.
|
|
@@ -3,6 +3,8 @@ require "pact_broker/error"
|
|
|
3
3
|
require "semantic_logger"
|
|
4
4
|
require "forwardable"
|
|
5
5
|
require "pact_broker/config/runtime_configuration"
|
|
6
|
+
require "pact_broker/logging/open_telemetry_appender_setup"
|
|
7
|
+
require "pact_broker/logging/trace_aware_json_formatter"
|
|
6
8
|
require "anyway/auto_cast"
|
|
7
9
|
require "request_store"
|
|
8
10
|
|
|
@@ -98,17 +100,28 @@ module PactBroker
|
|
|
98
100
|
def logger_from_runtime_configuration
|
|
99
101
|
@logger_from_runtime_configuration ||= begin
|
|
100
102
|
SemanticLogger.default_level = runtime_configuration.log_level
|
|
103
|
+
formatter = resolve_log_formatter(runtime_configuration.log_format)
|
|
101
104
|
if runtime_configuration.log_stream == :file
|
|
102
105
|
path = runtime_configuration.log_dir + "/pact_broker.log"
|
|
103
106
|
FileUtils.mkdir_p(runtime_configuration.log_dir)
|
|
104
|
-
@default_appender = SemanticLogger.add_appender(file_name: path, formatter:
|
|
107
|
+
@default_appender = SemanticLogger.add_appender(file_name: path, formatter: formatter)
|
|
105
108
|
else
|
|
106
|
-
@default_appender = SemanticLogger.add_appender(io: $stdout, formatter:
|
|
109
|
+
@default_appender = SemanticLogger.add_appender(io: $stdout, formatter: formatter)
|
|
107
110
|
end
|
|
111
|
+
PactBroker::Logging::OpenTelemetryAppenderSetup.call(runtime_configuration)
|
|
108
112
|
@logger_from_runtime_configuration = SemanticLogger["pact-broker"]
|
|
109
113
|
end
|
|
110
114
|
end
|
|
111
115
|
|
|
116
|
+
def resolve_log_formatter(log_format)
|
|
117
|
+
if log_format == :json
|
|
118
|
+
PactBroker::Logging::TraceAwareJsonFormatter.new
|
|
119
|
+
else
|
|
120
|
+
log_format
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
private :resolve_log_formatter
|
|
124
|
+
|
|
112
125
|
def logger
|
|
113
126
|
custom_logger || logger_from_runtime_configuration
|
|
114
127
|
end
|
data/lib/pact_broker/dataset.rb
CHANGED
|
@@ -8,10 +8,6 @@ module PactBroker
|
|
|
8
8
|
module Helpers
|
|
9
9
|
extend self
|
|
10
10
|
|
|
11
|
-
def mysql?
|
|
12
|
-
Sequel::Model.db.adapter_scheme.to_s =~ /mysql/
|
|
13
|
-
end
|
|
14
|
-
|
|
15
11
|
def postgres?
|
|
16
12
|
Sequel::Model.db.adapter_scheme.to_s =~ /postgres/
|
|
17
13
|
end
|
|
@@ -32,14 +28,9 @@ module PactBroker
|
|
|
32
28
|
|
|
33
29
|
def name_like column_name, value
|
|
34
30
|
if PactBroker.configuration.use_case_sensitive_resource_names
|
|
35
|
-
|
|
36
|
-
# sigh, mysql, this is the only way to perform a case sensitive search
|
|
37
|
-
Sequel.like(column_name, value.gsub("_", "\\_"), { case_insensitive: false })
|
|
38
|
-
else
|
|
39
|
-
{ column_name => value }
|
|
40
|
-
end
|
|
31
|
+
{ column_name => value }
|
|
41
32
|
else
|
|
42
|
-
Sequel.like(column_name, value
|
|
33
|
+
Sequel.like(column_name, escape_wildcards(value), { case_insensitive: true })
|
|
43
34
|
end
|
|
44
35
|
end
|
|
45
36
|
|
|
@@ -82,12 +73,7 @@ module PactBroker
|
|
|
82
73
|
end
|
|
83
74
|
|
|
84
75
|
def select_for_subquery column
|
|
85
|
-
|
|
86
|
-
column_name = column.respond_to?(:alias) ? column.alias : column
|
|
87
|
-
select(column).collect{ | it | it[column_name] }
|
|
88
|
-
else
|
|
89
|
-
select(column)
|
|
90
|
-
end
|
|
76
|
+
select(column)
|
|
91
77
|
end
|
|
92
78
|
|
|
93
79
|
def no_columns_selected?
|
|
@@ -109,12 +95,7 @@ module Sequel
|
|
|
109
95
|
# This has been used inconsistently, and in the next major version, support for case insensitive names will be dropped.
|
|
110
96
|
def self.name_like(column_name, value)
|
|
111
97
|
if PactBroker.configuration.use_case_sensitive_resource_names
|
|
112
|
-
|
|
113
|
-
# sigh, mysql, this is the only way to perform a case sensitive search
|
|
114
|
-
Sequel.like(column_name, PactBroker::Dataset::Helpers.escape_wildcards(value), { case_insensitive: false })
|
|
115
|
-
else
|
|
116
|
-
{ column_name => value }
|
|
117
|
-
end
|
|
98
|
+
{ column_name => value }
|
|
118
99
|
else
|
|
119
100
|
Sequel.like(column_name, PactBroker::Dataset::Helpers.escape_wildcards(value), { case_insensitive: true })
|
|
120
101
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require "pact_broker/hash_refinements"
|
|
2
|
+
|
|
3
|
+
module PactBroker
|
|
4
|
+
module DB
|
|
5
|
+
class Clean
|
|
6
|
+
class BranchSelector
|
|
7
|
+
using PactBroker::HashRefinements
|
|
8
|
+
|
|
9
|
+
ATTRIBUTES = [:max_age, :branch]
|
|
10
|
+
|
|
11
|
+
attr_accessor(*ATTRIBUTES)
|
|
12
|
+
|
|
13
|
+
def initialize(attributes = {})
|
|
14
|
+
attributes.each do | (name, value) |
|
|
15
|
+
instance_variable_set("@#{name}", value) if respond_to?(name)
|
|
16
|
+
end
|
|
17
|
+
@source_hash = attributes[:source_hash]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.from_hash(hash)
|
|
21
|
+
standard_hash = hash.symbolize_keys.snakecase_keys
|
|
22
|
+
new_hash = standard_hash.slice(*ATTRIBUTES)
|
|
23
|
+
new_hash[:source_hash] = hash
|
|
24
|
+
new(new_hash.compact)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_hash
|
|
28
|
+
ATTRIBUTES.each_with_object({}) do | key, hash |
|
|
29
|
+
hash[key] = send(key)
|
|
30
|
+
end.compact
|
|
31
|
+
end
|
|
32
|
+
alias_method :to_h, :to_hash
|
|
33
|
+
|
|
34
|
+
def to_json(_opts = nil)
|
|
35
|
+
(@source_hash || to_hash).to_json
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/pact_broker/db/clean.rb
CHANGED
|
@@ -2,6 +2,7 @@ require "sequel"
|
|
|
2
2
|
require "pact_broker/project_root"
|
|
3
3
|
require "pact_broker/logging"
|
|
4
4
|
require "pact_broker/db/clean/selector"
|
|
5
|
+
require "pact_broker/db/clean/branch_selector"
|
|
5
6
|
|
|
6
7
|
module PactBroker
|
|
7
8
|
module DB
|
|
@@ -130,6 +131,9 @@ module PactBroker
|
|
|
130
131
|
delete_orphan_tags
|
|
131
132
|
delete_orphan_versions
|
|
132
133
|
|
|
134
|
+
deleted_counts[:stale_branches] = delete_stale_branches
|
|
135
|
+
kept_counts[:stale_branches] = db[:branches].count
|
|
136
|
+
|
|
133
137
|
{ kept: kept_counts, deleted: deleted_counts }
|
|
134
138
|
end
|
|
135
139
|
|
|
@@ -180,6 +184,47 @@ module PactBroker
|
|
|
180
184
|
db[:versions].where(id: referenced_version_ids).invert.delete
|
|
181
185
|
end
|
|
182
186
|
|
|
187
|
+
def delete_stale_branches
|
|
188
|
+
return 0 unless keep_branches && !keep_branches.empty?
|
|
189
|
+
|
|
190
|
+
db[:branches].where(id: stale_branch_ids_to_delete.from_self.select(:id)).delete
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def stale_branch_ids_to_delete
|
|
194
|
+
db[:branches]
|
|
195
|
+
.select(Sequel[:branches][:id])
|
|
196
|
+
.left_outer_join(stale_branch_ids_to_keep, { Sequel[:branches][:id] => Sequel[:keep_branches][:id] }, table_alias: :keep_branches)
|
|
197
|
+
.where(Sequel[:keep_branches][:id] => nil)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def stale_branch_ids_to_keep
|
|
201
|
+
queries = [main_branch_ids_to_keep]
|
|
202
|
+
|
|
203
|
+
keep_branches.each do | selector |
|
|
204
|
+
if selector.max_age
|
|
205
|
+
cutoff = Date.today - selector.max_age
|
|
206
|
+
queries << db[:branches].where { updated_at >= cutoff }.select(:id)
|
|
207
|
+
end
|
|
208
|
+
if selector.branch
|
|
209
|
+
queries << db[:branches].where(name: Array(selector.branch)).select(:id)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
queries.reduce(:union)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def main_branch_ids_to_keep
|
|
217
|
+
db[:branches]
|
|
218
|
+
.join(:pacticipants, id: Sequel[:branches][:pacticipant_id])
|
|
219
|
+
.exclude(Sequel[:pacticipants][:main_branch] => nil)
|
|
220
|
+
.where(Sequel[:branches][:name] => Sequel[:pacticipants][:main_branch])
|
|
221
|
+
.select(Sequel[:branches][:id])
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def keep_branches
|
|
225
|
+
@keep_branches ||= options[:keep_branches]&.collect { | selector_hash | BranchSelector.from_hash(selector_hash.to_hash) }
|
|
226
|
+
end
|
|
227
|
+
|
|
183
228
|
def delete_overwritten_verifications
|
|
184
229
|
verification_ids = db[:verifications].select(:id).where(id: db[:latest_verification_id_for_pact_version_and_provider_version].select(:verification_id)).invert
|
|
185
230
|
deleted_counts = { verification_results: verification_ids.count }
|
|
@@ -2,6 +2,7 @@ require "pact_broker/logging"
|
|
|
2
2
|
require "pact_broker/matrix/unresolved_selector"
|
|
3
3
|
require "pact_broker/date_helper"
|
|
4
4
|
require "pact_broker/db/clean/selector"
|
|
5
|
+
require "pact_broker/db/clean/branch_selector"
|
|
5
6
|
|
|
6
7
|
module PactBroker
|
|
7
8
|
module DB
|
|
@@ -14,7 +15,10 @@ module PactBroker
|
|
|
14
15
|
PactBroker::DB::Clean::Selector.new(released: true),
|
|
15
16
|
PactBroker::DB::Clean::Selector.new(max_age: 90)
|
|
16
17
|
]
|
|
17
|
-
|
|
18
|
+
DEFAULT_KEEP_BRANCH_SELECTORS = [
|
|
19
|
+
PactBroker::DB::Clean::BranchSelector.new(max_age: 90)
|
|
20
|
+
]
|
|
21
|
+
TABLES = [:versions, :pact_publications, :pact_versions, :verifications, :triggered_webhooks, :webhook_executions, :branches]
|
|
18
22
|
|
|
19
23
|
def self.call database_connection, options = {}
|
|
20
24
|
new(database_connection, options).call
|
|
@@ -42,6 +46,7 @@ module PactBroker
|
|
|
42
46
|
def execute_clean
|
|
43
47
|
db.transaction do
|
|
44
48
|
before_counts = current_counts
|
|
49
|
+
delete_stale_branches
|
|
45
50
|
PactBroker::Domain::Version.where(id: versions_to_delete.from_self.select_map(:id)).delete
|
|
46
51
|
delete_orphan_pact_versions
|
|
47
52
|
after_counts = current_counts
|
|
@@ -68,10 +73,22 @@ module PactBroker
|
|
|
68
73
|
end
|
|
69
74
|
end
|
|
70
75
|
|
|
76
|
+
def keep_branches
|
|
77
|
+
@keep_branches ||= if options.key?(:keep_branches)
|
|
78
|
+
options[:keep_branches]&.collect { | selector_hash | PactBroker::DB::Clean::BranchSelector.from_hash(selector_hash.to_hash) }
|
|
79
|
+
else
|
|
80
|
+
DEFAULT_KEEP_BRANCH_SELECTORS
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
71
84
|
def limit
|
|
72
85
|
options[:limit] || 1000
|
|
73
86
|
end
|
|
74
87
|
|
|
88
|
+
def branch_limit
|
|
89
|
+
options[:branch_limit] || limit
|
|
90
|
+
end
|
|
91
|
+
|
|
75
92
|
def versions_to_delete(columns = [:id])
|
|
76
93
|
fully_qualified_columns = columns.collect { |col| Sequel[:versions][col] }
|
|
77
94
|
PactBroker::Domain::Version
|
|
@@ -96,13 +113,50 @@ module PactBroker
|
|
|
96
113
|
options[:dry_run]
|
|
97
114
|
end
|
|
98
115
|
|
|
116
|
+
def delete_stale_branches
|
|
117
|
+
return unless keep_branches && !keep_branches.empty?
|
|
118
|
+
|
|
119
|
+
# Wrap the dataset in a derived table with `from_self` before selecting
|
|
120
|
+
# the ids for deletion, to avoid referencing the target table directly
|
|
121
|
+
# in the subquery.
|
|
122
|
+
PactBroker::Versions::Branch.where(id: stale_branch_ids_to_delete.from_self.select(:id)).delete
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def stale_branch_ids_to_delete
|
|
126
|
+
PactBroker::Versions::Branch
|
|
127
|
+
.select(Sequel[:branches][:id])
|
|
128
|
+
.left_outer_join(stale_branch_ids_to_keep, { Sequel[:branches][:id] => Sequel[:keep_branches][:id] }, table_alias: :keep_branches)
|
|
129
|
+
.where(Sequel[:keep_branches][:id] => nil)
|
|
130
|
+
.limit(branch_limit)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def stale_branch_ids_to_keep
|
|
134
|
+
# Always keep main branches for each pacticipant
|
|
135
|
+
queries = [main_branch_ids_to_keep]
|
|
136
|
+
|
|
137
|
+
keep_branches.each do | selector |
|
|
138
|
+
if selector.max_age
|
|
139
|
+
cutoff = Date.today - selector.max_age
|
|
140
|
+
queries << PactBroker::Versions::Branch.where { updated_at >= cutoff }.select(Sequel[:branches][:id])
|
|
141
|
+
end
|
|
142
|
+
if selector.branch
|
|
143
|
+
queries << PactBroker::Versions::Branch.where(name: Array(selector.branch)).select(Sequel[:branches][:id])
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
queries.reduce(&:union)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def main_branch_ids_to_keep
|
|
151
|
+
PactBroker::Versions::Branch
|
|
152
|
+
.join(:pacticipants, id: Sequel[:branches][:pacticipant_id])
|
|
153
|
+
.exclude(Sequel[:pacticipants][:main_branch] => nil)
|
|
154
|
+
.where(Sequel[:branches][:name] => Sequel[:pacticipants][:main_branch])
|
|
155
|
+
.select(Sequel[:branches][:id])
|
|
156
|
+
end
|
|
157
|
+
|
|
99
158
|
def delete_orphan_pact_versions
|
|
100
159
|
db[:pact_versions].where(id: orphan_pact_versions).delete
|
|
101
|
-
rescue Sequel::DatabaseError => e
|
|
102
|
-
raise unless e.cause.class.name == "Mysql2::Error"
|
|
103
|
-
|
|
104
|
-
ids = orphan_pact_versions.map { |row| row[:id] }
|
|
105
|
-
db[:pact_versions].where(id: ids).delete
|
|
106
160
|
end
|
|
107
161
|
|
|
108
162
|
def orphan_pact_versions
|
|
@@ -142,19 +196,29 @@ module PactBroker
|
|
|
142
196
|
}
|
|
143
197
|
end
|
|
144
198
|
|
|
199
|
+
{
|
|
200
|
+
"counts" => dry_run_counts(kept_per_selector),
|
|
201
|
+
"versionSummary" => pacticipant_results
|
|
202
|
+
}
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def dry_run_counts(kept_per_selector)
|
|
145
206
|
total_versions_count = PactBroker::Domain::Version.count
|
|
146
207
|
versions_to_keep_count = version_ids_to_keep.count
|
|
147
208
|
versions_to_delete_count = versions_to_delete.count
|
|
148
209
|
|
|
210
|
+
total_branches_count = PactBroker::Versions::Branch.count
|
|
211
|
+
branches_to_delete_count = keep_branches && !keep_branches.empty? ? stale_branch_ids_to_delete.count : 0
|
|
212
|
+
|
|
149
213
|
{
|
|
150
|
-
"
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
"
|
|
214
|
+
"totalVersions" => total_versions_count,
|
|
215
|
+
"versionsToDelete" => versions_to_delete_count,
|
|
216
|
+
"versionsNotToKeep" => total_versions_count - versions_to_keep_count,
|
|
217
|
+
"versionsToKeep" => versions_to_keep_count,
|
|
218
|
+
"versionsToKeepBySelector" => kept_per_selector,
|
|
219
|
+
"totalBranches" => total_branches_count,
|
|
220
|
+
"branchesToDelete" => branches_to_delete_count,
|
|
221
|
+
"branchesToKeep" => total_branches_count - branches_to_delete_count
|
|
158
222
|
}
|
|
159
223
|
end
|
|
160
224
|
|
data/lib/pact_broker/db.rb
CHANGED
|
@@ -57,12 +57,5 @@ module PactBroker
|
|
|
57
57
|
PactBroker::DB::ValidateEncoding.(connection)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
def self.set_mysql_strict_mode_if_mysql
|
|
61
|
-
connection.run("SET sql_mode='STRICT_TRANS_TABLES';") if mysql?
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def self.mysql?
|
|
65
|
-
connection.adapter_scheme =~ /mysql/
|
|
66
|
-
end
|
|
67
60
|
end
|
|
68
61
|
end
|
|
@@ -46,6 +46,20 @@ module PactBroker
|
|
|
46
46
|
.single_record
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
def self.find_released_versions_for_version(version)
|
|
50
|
+
scope_for(ReleasedVersion)
|
|
51
|
+
.where(version_id: version.id)
|
|
52
|
+
.eager(:environment)
|
|
53
|
+
.all
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.find_released_versions_for_versions(versions_array)
|
|
57
|
+
scope_for(ReleasedVersion)
|
|
58
|
+
.where(version_id: versions_array.map(&:id))
|
|
59
|
+
.eager(:environment)
|
|
60
|
+
.to_hash_groups(:version_id)
|
|
61
|
+
end
|
|
62
|
+
|
|
49
63
|
def self.record_version_support_ended(released_version)
|
|
50
64
|
released_version.record_support_ended
|
|
51
65
|
end
|
|
@@ -12,6 +12,7 @@ module PactBroker
|
|
|
12
12
|
|
|
13
13
|
plugin :timestamps, update_on_create: true
|
|
14
14
|
plugin :age
|
|
15
|
+
plugin :insert_ignore, identifying_columns: [:pacticipant_id, :number]
|
|
15
16
|
plugin :upsert, { identifying_columns: [:pacticipant_id, :number], ignore_columns_on_update: [:id, :created_at, :order] }
|
|
16
17
|
|
|
17
18
|
one_to_many :pact_publications, order: :revision_number, class: "PactBroker::Pacts::PactPublication", key: :consumer_version_id
|
|
@@ -241,9 +242,11 @@ module PactBroker
|
|
|
241
242
|
# @return Sequel::Dataset<PactBroker::Domain::Version>
|
|
242
243
|
def ids_for_selectors(unresolved_selectors)
|
|
243
244
|
# Need the select at the start and at the end to stop extra columns being returned (eg. branch name, environment name)
|
|
245
|
+
# from_self: false keeps this a single flat UNION. Sequel's default would wrap the
|
|
246
|
+
# accumulated dataset in a new subquery for every selector, nesting it N-1 deep.
|
|
244
247
|
unresolved_selectors
|
|
245
248
|
.collect{ |selector| self.select(Sequel[:versions][:id]).for_selector(selector).select(:id) }
|
|
246
|
-
.reduce(
|
|
249
|
+
.reduce { |all_ids, ids| all_ids.union(ids, from_self: false) }
|
|
247
250
|
end
|
|
248
251
|
|
|
249
252
|
def pacticipants_set
|
|
@@ -272,10 +275,11 @@ module PactBroker
|
|
|
272
275
|
end
|
|
273
276
|
|
|
274
277
|
# Isn't called on upsert when the record is updated with Sqlite
|
|
275
|
-
# Is called with Postgres
|
|
278
|
+
# Is called with Postgres
|
|
276
279
|
# Haven't had time to dig into why
|
|
277
280
|
def after_create
|
|
278
281
|
super
|
|
282
|
+
return unless id
|
|
279
283
|
OrderVersions.(self) unless self.order
|
|
280
284
|
refresh
|
|
281
285
|
end
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
require "sequel"
|
|
2
2
|
require "pact_broker/db/log_quietener"
|
|
3
3
|
require "fileutils"
|
|
4
|
+
require "pact_broker/error"
|
|
4
5
|
|
|
5
6
|
module PactBroker
|
|
6
7
|
def self.create_database_connection(config, logger = nil)
|
|
8
|
+
if config[:adapter].to_s =~ /mysql/
|
|
9
|
+
raise PactBroker::Error.new("MySQL is no longer supported. Please use PostgreSQL.")
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
logger&.info("Connecting to database:", config.merge(password: "*****"))
|
|
8
13
|
|
|
9
14
|
sequel_config = config.dup
|
|
@@ -74,7 +74,7 @@ module PactBroker
|
|
|
74
74
|
def set_contract_data_updated_at_for_multiple_integrations(objects_with_consumer_and_provider)
|
|
75
75
|
consumer_and_provider_ids = objects_with_consumer_and_provider.collect{ | object | { consumer_id: object.consumer&.id, provider_id: object.provider.id }.compact }.uniq
|
|
76
76
|
|
|
77
|
-
#
|
|
77
|
+
# Not all supported databases handle an UPDATE with a subquery, so branch on SKIP LOCKED support.
|
|
78
78
|
criteria = if Integration.dataset.supports_skip_locked?
|
|
79
79
|
integration_ids_to_update = Integration
|
|
80
80
|
.select(:id)
|
|
@@ -55,9 +55,7 @@ module PactBroker
|
|
|
55
55
|
model.truncate(cascade: true)
|
|
56
56
|
else
|
|
57
57
|
logger.info("Deleting all from ", model.table_name)
|
|
58
|
-
#
|
|
59
|
-
# https://travis-ci.org/pact-foundation/pact_broker/jobs/633050220#L841
|
|
60
|
-
# https://travis-ci.org/pact-foundation/pact_broker/jobs/633053228#L849
|
|
58
|
+
# SQLite does not support cascade truncate, so delete instead
|
|
61
59
|
model.dataset.delete
|
|
62
60
|
end
|
|
63
61
|
end
|