pact_broker 2.120.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 +552 -482
- data/Gemfile +0 -6
- data/README.md +0 -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/version_decorator.rb +7 -2
- data/lib/pact_broker/api/pact_broker_urls.rb +4 -0
- 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/tag_versions.rb +1 -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_incremental.rb +4 -8
- data/lib/pact_broker/db.rb +0 -7
- 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/selector_resolver.rb +30 -2
- data/lib/pact_broker/pacticipants/repository.rb +4 -1
- data/lib/pact_broker/pacts/service.rb +2 -2
- data/lib/pact_broker/tags/service.rb +4 -5
- data/lib/pact_broker/verifications/repository.rb +1 -1
- data/lib/pact_broker/version.rb +1 -1
- data/lib/pact_broker/versions/branch_version_repository.rb +3 -3
- 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 +2 -2
- metadata +15 -6
|
@@ -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
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require "semantic_logger"
|
|
2
|
+
require "pact_broker/error"
|
|
3
|
+
|
|
4
|
+
module PactBroker
|
|
5
|
+
module Logging
|
|
6
|
+
# Adds semantic_logger's :open_telemetry appender when configured, without
|
|
7
|
+
# taking a hard dependency on the OpenTelemetry gems.
|
|
8
|
+
class OpenTelemetryAppenderSetup
|
|
9
|
+
def self.call(runtime_configuration)
|
|
10
|
+
new(runtime_configuration).call
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(runtime_configuration)
|
|
14
|
+
@runtime_configuration = runtime_configuration
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns the added (or already-present) appender, or nil if none was added.
|
|
18
|
+
def call
|
|
19
|
+
case @runtime_configuration.log_otel_enabled
|
|
20
|
+
when false
|
|
21
|
+
nil
|
|
22
|
+
when true
|
|
23
|
+
unless otel_available?
|
|
24
|
+
raise PactBroker::ConfigurationError,
|
|
25
|
+
"log_otel_enabled is set to true but the opentelemetry-logs-sdk gem could not be loaded. " \
|
|
26
|
+
"Add it to your Gemfile, or set log_otel_enabled to auto/false."
|
|
27
|
+
end
|
|
28
|
+
add_appender(warn_if_no_provider: true)
|
|
29
|
+
else # :auto
|
|
30
|
+
add_appender(warn_if_no_provider: false) if otel_available? && otel_provider_configured?
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def add_appender(warn_if_no_provider:)
|
|
37
|
+
existing = existing_otel_appender
|
|
38
|
+
return existing if existing
|
|
39
|
+
|
|
40
|
+
if warn_if_no_provider && !otel_provider_configured?
|
|
41
|
+
SemanticLogger["pact-broker"].warn(
|
|
42
|
+
"log_otel_enabled is true but no OpenTelemetry LoggerProvider is configured; " \
|
|
43
|
+
"OTel log records may be dropped."
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
SemanticLogger.add_appender(appender: :open_telemetry)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def existing_otel_appender
|
|
51
|
+
return nil unless defined?(SemanticLogger::Appender::OpenTelemetry)
|
|
52
|
+
|
|
53
|
+
SemanticLogger.appenders.find { |appender| appender.is_a?(SemanticLogger::Appender::OpenTelemetry) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def otel_available?
|
|
57
|
+
require "opentelemetry-logs-sdk"
|
|
58
|
+
defined?(OpenTelemetry::Logs) ? true : false
|
|
59
|
+
rescue LoadError
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def otel_provider_configured?
|
|
64
|
+
return false unless defined?(OpenTelemetry)
|
|
65
|
+
|
|
66
|
+
# A no-op / proxy provider means no real logs pipeline is configured.
|
|
67
|
+
OpenTelemetry.logger_provider.class.name.to_s.start_with?("OpenTelemetry::SDK::Logs")
|
|
68
|
+
rescue StandardError
|
|
69
|
+
false
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require "semantic_logger"
|
|
2
|
+
require "semantic_logger/formatters/json"
|
|
3
|
+
|
|
4
|
+
module PactBroker
|
|
5
|
+
module Logging
|
|
6
|
+
# A JSON log formatter that adds the standard OpenTelemetry log-correlation
|
|
7
|
+
# fields (trace_id, span_id, trace_flags) when a valid span is active.
|
|
8
|
+
# Degrades to plain JSON when OTel is not loaded or there is no active span,
|
|
9
|
+
# so it is safe for the open-source Pact Broker.
|
|
10
|
+
class TraceAwareJsonFormatter < SemanticLogger::Formatters::Json
|
|
11
|
+
def call(log, logger)
|
|
12
|
+
json = super
|
|
13
|
+
context = otel_trace_context
|
|
14
|
+
return json if context.empty?
|
|
15
|
+
|
|
16
|
+
# `hash` was populated by Raw#call during `super`; reuse it.
|
|
17
|
+
SemanticLogger::Utils.to_json(hash.merge(context))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def otel_trace_context
|
|
23
|
+
return {} unless defined?(OpenTelemetry::Trace)
|
|
24
|
+
|
|
25
|
+
span_context = OpenTelemetry::Trace.current_span.context
|
|
26
|
+
return {} unless span_context.valid?
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
trace_id: span_context.hex_trace_id,
|
|
30
|
+
span_id: span_context.hex_span_id,
|
|
31
|
+
trace_flags: span_context.trace_flags.sampled? ? "01" : "00"
|
|
32
|
+
}
|
|
33
|
+
rescue StandardError
|
|
34
|
+
{}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -61,8 +61,13 @@ module PactBroker
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
# consumer
|
|
64
|
-
pact_publication_matching_consumer = select_pact_columns_with_aliases
|
|
65
|
-
|
|
64
|
+
pact_publication_matching_consumer = select_pact_columns_with_aliases
|
|
65
|
+
.most_recent(limit)
|
|
66
|
+
.from_self(alias: :p)
|
|
67
|
+
.where_consumer_version_matches_selectors(resolved_selectors)
|
|
68
|
+
rows_where_selector_matches_consumer = pact_publication_matching_consumer
|
|
69
|
+
.left_outer_join_verifications
|
|
70
|
+
.select_all_columns_after_join
|
|
66
71
|
|
|
67
72
|
# provider
|
|
68
73
|
verifications_matching_provider = verification_dataset.matching_selectors_as_provider_for_any_consumer(resolved_selectors)
|
|
@@ -143,24 +148,37 @@ module PactBroker
|
|
|
143
148
|
|
|
144
149
|
if resolved_selectors_with_versions_specified.any?
|
|
145
150
|
select_pact_columns_with_aliases
|
|
146
|
-
.
|
|
151
|
+
.where_consumer_version_matches_selectors(resolved_selectors_with_versions_specified)
|
|
147
152
|
.where(provider_id: all_pacticipant_ids)
|
|
148
153
|
.most_recent(limit)
|
|
149
154
|
end
|
|
150
155
|
end
|
|
151
156
|
|
|
157
|
+
# Name-only selectors carry no version ID — matching_one_selector_for_either_consumer_or_provider
|
|
158
|
+
# passes its selectors unfiltered — so they filter on the pacticipant instead. That
|
|
159
|
+
# identifies the same rows, because a pact publication's consumer_id is the
|
|
160
|
+
# pacticipant_id of its consumer_version.
|
|
152
161
|
# @private
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
# @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
|
|
163
|
+
def where_consumer_version_matches_selectors(resolved_selectors)
|
|
164
|
+
if resolved_selectors.empty?
|
|
165
|
+
raise ArgumentError.new("resolved_selectors must not be empty")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
criteria = consumer_criteria_for_selectors(resolved_selectors)
|
|
169
|
+
where(criteria.size > 1 ? Sequel.|(*criteria) : criteria.first)
|
|
158
170
|
end
|
|
159
171
|
|
|
160
172
|
# @private
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
173
|
+
# @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
|
|
174
|
+
# @return [Array<Hash>]
|
|
175
|
+
def consumer_criteria_for_selectors(resolved_selectors)
|
|
176
|
+
name_only, with_versions = resolved_selectors.partition(&:only_pacticipant_name_specified?)
|
|
177
|
+
|
|
178
|
+
criteria = []
|
|
179
|
+
criteria << { Sequel[:p][:consumer_id] => name_only.collect(&:pacticipant_id).uniq } if name_only.any?
|
|
180
|
+
criteria << { Sequel[:p][:consumer_version_id] => with_versions.collect(&:pacticipant_version_id).uniq } if with_versions.any?
|
|
181
|
+
criteria
|
|
164
182
|
end
|
|
165
183
|
|
|
166
184
|
# @private
|
|
@@ -21,7 +21,7 @@ module PactBroker
|
|
|
21
21
|
# @return [Sequel::Dataset<Verification>, nil]
|
|
22
22
|
def matching_selectors_as_provider_for_any_consumer(resolved_selectors)
|
|
23
23
|
select_verification_columns_with_aliases
|
|
24
|
-
.
|
|
24
|
+
.where_provider_version_matches_selectors(resolved_selectors)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Return verifications where the provider is described by any of the resolved_selectors *that only specify the pacticipant NAME*,
|
|
@@ -51,32 +51,43 @@ module PactBroker
|
|
|
51
51
|
# @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
|
|
52
52
|
# @return [Sequel::Dataset<Verification>, nil]
|
|
53
53
|
def matching_only_selectors_as_provider_where_not_only_pacticipant_name_in_selector(resolved_selectors)
|
|
54
|
-
# get the UnresolvedSelector objects back out of the resolved_selectors because the Version.for_selector() method uses the UnresolvedSelector
|
|
55
54
|
all_pacticipant_ids = resolved_selectors.collect(&:pacticipant_id).uniq
|
|
56
55
|
resolved_selectors_with_versions_specified = resolved_selectors.reject(&:only_pacticipant_name_specified?)
|
|
57
56
|
|
|
58
57
|
if resolved_selectors_with_versions_specified.any?
|
|
59
58
|
select_verification_columns_with_aliases
|
|
60
|
-
.
|
|
59
|
+
.where_provider_version_matches_selectors(resolved_selectors_with_versions_specified)
|
|
61
60
|
.where(consumer_id: all_pacticipant_ids)
|
|
62
61
|
end
|
|
63
62
|
end
|
|
64
63
|
|
|
65
|
-
#
|
|
66
|
-
#
|
|
64
|
+
# Name-only selectors carry no version id — matching_selectors_as_provider_for_any_consumer
|
|
65
|
+
# passes its selectors unfiltered — so they filter on the provider pacticipant instead. That
|
|
66
|
+
# identifies the same rows, because a verification's provider_id is the
|
|
67
|
+
# pacticipant_id of its provider_version.
|
|
67
68
|
# @private
|
|
68
69
|
# @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
|
|
69
70
|
# @return [Sequel::Dataset<Verification>]
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
def where_provider_version_matches_selectors(resolved_selectors)
|
|
72
|
+
if resolved_selectors.empty?
|
|
73
|
+
raise ArgumentError.new("resolved_selectors must not be empty")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
criteria = provider_criteria_for_selectors(resolved_selectors)
|
|
77
|
+
where(criteria.size > 1 ? Sequel.|(*criteria) : criteria.first)
|
|
75
78
|
end
|
|
76
79
|
|
|
77
80
|
# @private
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
# @param [Array<PactBroker::Matrix::ResolvedSelector>] resolved_selectors
|
|
82
|
+
# @return [Array<Hash>]
|
|
83
|
+
def provider_criteria_for_selectors(resolved_selectors)
|
|
84
|
+
name_only, with_versions = resolved_selectors.partition(&:only_pacticipant_name_specified?)
|
|
85
|
+
table = self.model.table_name
|
|
86
|
+
|
|
87
|
+
criteria = []
|
|
88
|
+
criteria << { Sequel[table][:provider_id] => name_only.collect(&:pacticipant_id).uniq } if name_only.any?
|
|
89
|
+
criteria << { Sequel[table][:provider_version_id] => with_versions.collect(&:pacticipant_version_id).uniq } if with_versions.any?
|
|
90
|
+
criteria
|
|
80
91
|
end
|
|
81
92
|
end
|
|
82
93
|
end
|
|
@@ -73,15 +73,43 @@ module PactBroker
|
|
|
73
73
|
|
|
74
74
|
private :resolve_versions_and_add_ids
|
|
75
75
|
|
|
76
|
-
# Return a Hash of the pacticipant names used in the selectors, where the key is the name
|
|
76
|
+
# Return a Hash of the pacticipant names used in the selectors, where the key is the name
|
|
77
|
+
# as specified in the selector (not necessarily the pacticipant's stored name, when
|
|
78
|
+
# use_case_sensitive_resource_names is false), and the value is the pacticipant.
|
|
77
79
|
# @return [Hash<String, PactBroker::Domain::Pacticipant>]
|
|
78
80
|
def find_pacticipants_for_selectors(unresolved_selectors)
|
|
79
81
|
names = unresolved_selectors.collect(&:pacticipant_name)
|
|
80
|
-
|
|
82
|
+
pacticipants = pacticipants_matching_names(names)
|
|
83
|
+
|
|
84
|
+
names.uniq.each_with_object({}) do | name, hash |
|
|
85
|
+
matching = pacticipants.select { | candidate | pacticipant_name_matches?(candidate.name, name) }
|
|
86
|
+
pacticipant_repository.handle_multiple_pacticipants_found(name, matching) if matching.size > 1
|
|
87
|
+
hash[name] = matching.first if matching.any?
|
|
88
|
+
end
|
|
81
89
|
end
|
|
82
90
|
|
|
83
91
|
private :find_pacticipants_for_selectors
|
|
84
92
|
|
|
93
|
+
# @param [Array<String>] names
|
|
94
|
+
# @return [Array<PactBroker::Domain::Pacticipant>]
|
|
95
|
+
def pacticipants_matching_names(names)
|
|
96
|
+
return [] if names.empty?
|
|
97
|
+
|
|
98
|
+
PactBroker::Domain::Pacticipant.where(Sequel.|(*names.collect { | name | Sequel.name_like(:name, name) })).all
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private :pacticipants_matching_names
|
|
102
|
+
|
|
103
|
+
def pacticipant_name_matches?(stored_name, requested_name)
|
|
104
|
+
if PactBroker.configuration.use_case_sensitive_resource_names
|
|
105
|
+
stored_name == requested_name
|
|
106
|
+
else
|
|
107
|
+
stored_name.casecmp?(requested_name)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private :pacticipant_name_matches?
|
|
112
|
+
|
|
85
113
|
def build_selectors(pacticipants_hash, unresolved_selector, selector_type, selector_ignorer)
|
|
86
114
|
selector_builder = ResolvedSelectorBuilder.new(unresolved_selector, selector_type, selector_ignorer)
|
|
87
115
|
selector_builder.pacticipant = pacticipants_hash[unresolved_selector.pacticipant_name]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "pact_broker/dataset"
|
|
1
2
|
require "pact_broker/domain/pacticipant"
|
|
2
3
|
require "pact_broker/error"
|
|
3
4
|
require "pact_broker/repositories/scopes"
|
|
@@ -47,6 +48,8 @@ module PactBroker
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def find_by_name_or_create name
|
|
51
|
+
raise PactBroker::Error, "Cannot create a pacticipant with a blank name" if name.to_s.strip.empty?
|
|
52
|
+
|
|
50
53
|
pacticipant = find_by_name(name)
|
|
51
54
|
pacticipant ? pacticipant : create(name: name)
|
|
52
55
|
end
|
|
@@ -104,7 +107,7 @@ module PactBroker
|
|
|
104
107
|
end
|
|
105
108
|
|
|
106
109
|
def search_by_name(pacticipant_name)
|
|
107
|
-
terms = pacticipant_name.split.map { |v|
|
|
110
|
+
terms = pacticipant_name.split.map { |v| PactBroker::Dataset::Helpers.escape_wildcards(v) }
|
|
108
111
|
columns = [:name, :display_name]
|
|
109
112
|
string_match_query = Sequel.|(
|
|
110
113
|
*terms.map do |term|
|
|
@@ -182,7 +182,7 @@ module PactBroker
|
|
|
182
182
|
# Modifing pacts is strongly discouraged now, and support for it will be dropped in the next major version of the Pact Broker
|
|
183
183
|
def create_pact_revision params, existing_pact
|
|
184
184
|
logger.info("Updating existing pact publication", params.without(:json_content))
|
|
185
|
-
logger.debug
|
|
185
|
+
logger.debug { "Content #{params[:json_content]}" }
|
|
186
186
|
pact_version_sha = params.fetch(:pact_version_sha)
|
|
187
187
|
json_content = add_interaction_ids(params[:json_content])
|
|
188
188
|
update_params = { pact_version_sha: pact_version_sha, json_content: json_content }
|
|
@@ -211,7 +211,7 @@ module PactBroker
|
|
|
211
211
|
# When no publication for the given consumer/provider/consumer version number exists
|
|
212
212
|
def create_pact(params, version, provider)
|
|
213
213
|
logger.debug("Creating new pact publication", params.without(:json_content))
|
|
214
|
-
logger.debug
|
|
214
|
+
logger.debug { "Content #{params[:json_content]}" }
|
|
215
215
|
json_content = add_interaction_ids(params[:json_content])
|
|
216
216
|
pact = pact_repository.create(
|
|
217
217
|
version_id: version.id,
|
|
@@ -24,17 +24,16 @@ module PactBroker
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def delete args
|
|
27
|
-
version = version_repository.find_by_pacticipant_name_and_number
|
|
28
|
-
|
|
29
|
-
connection.run("delete from tags where name = '#{args.fetch(:tag_name)}' and version_id = '#{version.id}'")
|
|
27
|
+
version = version_repository.find_by_pacticipant_name_and_number(args.fetch(:pacticipant_name), args.fetch(:pacticipant_version_number))
|
|
28
|
+
PactBroker::Domain::Tag.where(name: args.fetch(:tag_name), version_id: version.id).delete
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
def find_all_tag_names_for_pacticipant pacticipant_name
|
|
33
|
-
tag_repository.find_all_tag_names_for_pacticipant
|
|
32
|
+
tag_repository.find_all_tag_names_for_pacticipant(pacticipant_name)
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def find_all_by_pacticipant_name_and_tag pacticipant_name:, tag_name:
|
|
37
|
-
tag_repository.find_all_by_pacticipant_name_and_tag
|
|
36
|
+
tag_repository.find_all_by_pacticipant_name_and_tag(pacticipant_name, tag_name)
|
|
38
37
|
end
|
|
39
38
|
end
|
|
40
39
|
end
|
|
@@ -10,7 +10,7 @@ module PactBroker
|
|
|
10
10
|
include PactBroker::Repositories
|
|
11
11
|
include PactBroker::Repositories::Scopes
|
|
12
12
|
|
|
13
|
-
# Ideally this would just be a sequence, but Sqlite
|
|
13
|
+
# Ideally this would just be a sequence, but Sqlite doesn't support sequences
|
|
14
14
|
# in the way we need to use them ie. determining what the next number will be before we
|
|
15
15
|
# create the record, because Webmachine wants to set the URL of the resource that is about
|
|
16
16
|
# to be created *before* we actually create it.
|
data/lib/pact_broker/version.rb
CHANGED
|
@@ -27,14 +27,14 @@ module PactBroker
|
|
|
27
27
|
branch = find_or_create_branch(version.pacticipant, branch_name)
|
|
28
28
|
branch_version = version.branch_version_for_branch(branch)
|
|
29
29
|
if branch_version
|
|
30
|
-
PactBroker.logger.
|
|
31
|
-
branch_version.update(updated_at: Sequel.datetime_class.now)
|
|
30
|
+
PactBroker.logger.debug("Branch version already exists #{branch_version.inspect}")
|
|
32
31
|
else
|
|
33
32
|
PactBroker.logger.info("Creating branch version time: #{Time.now}")
|
|
34
33
|
branch_version = PactBroker::Versions::BranchVersion.new(version: version, branch: branch, auto_created: auto_created).insert_ignore
|
|
35
34
|
PactBroker::Versions::BranchHead.new(branch: branch, branch_version: branch_version).upsert
|
|
36
35
|
end
|
|
37
|
-
|
|
36
|
+
now = Sequel.datetime_class.now
|
|
37
|
+
Branch.where(id: branch.id).where(Sequel[:updated_at] < now - Rational(60, 86400)).update(updated_at: now)
|
|
38
38
|
pacticipant_service.maybe_set_main_branch(version.pacticipant, branch_name)
|
|
39
39
|
branch_version
|
|
40
40
|
end
|
|
@@ -89,22 +89,13 @@ module PactBroker
|
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def create_or_update(pacticipant, version_number, open_struct_version)
|
|
92
|
-
saved_version = PactBroker::Domain::Version.where(pacticipant_id: pacticipant.id, number: version_number).single_record
|
|
93
92
|
params = open_struct_version.to_h
|
|
94
93
|
tags = params.delete(:tags)
|
|
95
94
|
branch_name = params.delete(:branch)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
# Upsert blanks out any fields that are not provided
|
|
101
|
-
saved_version = PactBroker::Domain::Version.new(
|
|
102
|
-
params.merge(
|
|
103
|
-
pacticipant_id: pacticipant.id,
|
|
104
|
-
number: version_number
|
|
105
|
-
).compact
|
|
106
|
-
).upsert
|
|
107
|
-
end
|
|
95
|
+
insert_params = params.merge(pacticipant_id: pacticipant.id, number: version_number).compact
|
|
96
|
+
saved_version = PactBroker::Domain::Version.new(insert_params).insert_ignore
|
|
97
|
+
update_params = params.reject { |k, _| [:created_at, :order].include?(k) }
|
|
98
|
+
saved_version.update(update_params) if update_params.any?
|
|
108
99
|
|
|
109
100
|
branch_version_repository.add_branch(saved_version, branch_name) if branch_name
|
|
110
101
|
replace_tags(saved_version, tags) if tags
|
|
@@ -3,7 +3,7 @@ require "pact_broker/webhooks/pact_and_verification_parameters"
|
|
|
3
3
|
module PactBroker
|
|
4
4
|
module Webhooks
|
|
5
5
|
class Render
|
|
6
|
-
TEMPLATE_PARAMETER_REGEXP = /\$\{pactbroker\.[^\}]
|
|
6
|
+
TEMPLATE_PARAMETER_REGEXP = /\$\{pactbroker\.[^\}]++\}/
|
|
7
7
|
DEFAULT_ESCAPER = lambda { |it| it }
|
|
8
8
|
|
|
9
9
|
def self.includes_parameter?(value)
|
|
@@ -19,7 +19,7 @@ module Sequel
|
|
|
19
19
|
|
|
20
20
|
def upsert(opts = {})
|
|
21
21
|
@upsert_plugin_upserting = true
|
|
22
|
-
if postgres?
|
|
22
|
+
if postgres?
|
|
23
23
|
save(opts)
|
|
24
24
|
else
|
|
25
25
|
manual_upsert(opts)
|
|
@@ -92,9 +92,6 @@ module Sequel
|
|
|
92
92
|
if upsert_plugin_upserting
|
|
93
93
|
if postgres?
|
|
94
94
|
super.insert_conflict(update: values_to_update, target: self.class.upsert_plugin_identifying_columns)
|
|
95
|
-
elsif mysql?
|
|
96
|
-
columns_to_update = values_to_update.keys - self.class.upsert_plugin_identifying_columns
|
|
97
|
-
super.on_duplicate_key_update(*columns_to_update)
|
|
98
95
|
else
|
|
99
96
|
super
|
|
100
97
|
end
|
|
@@ -103,10 +100,6 @@ module Sequel
|
|
|
103
100
|
end
|
|
104
101
|
end
|
|
105
102
|
|
|
106
|
-
def mysql?
|
|
107
|
-
model.db.adapter_scheme.to_s =~ /mysql/
|
|
108
|
-
end
|
|
109
|
-
|
|
110
103
|
def postgres?
|
|
111
104
|
model.db.adapter_scheme.to_s =~ /postgres/
|
|
112
105
|
end
|
data/pact_broker.gemspec
CHANGED
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |gem|
|
|
|
14
14
|
gem.summary = %q{See description}
|
|
15
15
|
gem.homepage = "https://github.com/pact-foundation/pact_broker"
|
|
16
16
|
|
|
17
|
-
gem.required_ruby_version = ">= 2.
|
|
17
|
+
gem.required_ruby_version = ">= 3.2.0"
|
|
18
18
|
|
|
19
19
|
gem.files = begin
|
|
20
20
|
if Dir.exist?(".git")
|
|
@@ -64,7 +64,7 @@ Gem::Specification.new do |gem|
|
|
|
64
64
|
gem.add_runtime_dependency "sucker_punch", "~>3.0"
|
|
65
65
|
gem.add_runtime_dependency "rack-protection", "~> 4.1"
|
|
66
66
|
gem.add_runtime_dependency "table_print", "~> 1.5"
|
|
67
|
-
gem.add_runtime_dependency "semantic_logger", "~>
|
|
67
|
+
gem.add_runtime_dependency "semantic_logger", "~> 5.0"
|
|
68
68
|
gem.add_runtime_dependency "sanitize", "~> 6.0"
|
|
69
69
|
gem.add_runtime_dependency "wisper", "~> 2.0"
|
|
70
70
|
gem.add_runtime_dependency "anyway_config", "~> 2.1"
|
metadata
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pact_broker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.121.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bethany Skurrie
|
|
8
8
|
- Sergei Matheson
|
|
9
9
|
- Warner Godfrey
|
|
10
|
+
autorequire:
|
|
10
11
|
bindir: bin
|
|
11
12
|
cert_chain: []
|
|
12
|
-
date:
|
|
13
|
+
date: 2026-09-04 00:00:00.000000000 Z
|
|
13
14
|
dependencies:
|
|
14
15
|
- !ruby/object:Gem::Dependency
|
|
15
16
|
name: json
|
|
@@ -227,14 +228,14 @@ dependencies:
|
|
|
227
228
|
requirements:
|
|
228
229
|
- - "~>"
|
|
229
230
|
- !ruby/object:Gem::Version
|
|
230
|
-
version: '
|
|
231
|
+
version: '5.0'
|
|
231
232
|
type: :runtime
|
|
232
233
|
prerelease: false
|
|
233
234
|
version_requirements: !ruby/object:Gem::Requirement
|
|
234
235
|
requirements:
|
|
235
236
|
- - "~>"
|
|
236
237
|
- !ruby/object:Gem::Version
|
|
237
|
-
version: '
|
|
238
|
+
version: '5.0'
|
|
238
239
|
- !ruby/object:Gem::Dependency
|
|
239
240
|
name: sanitize
|
|
240
241
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -591,6 +592,8 @@ files:
|
|
|
591
592
|
- docs/developer/design_pattern_for_eager_loading_collections.md
|
|
592
593
|
- docs/developer/matrix.md
|
|
593
594
|
- docs/developer/rack.md
|
|
595
|
+
- docs/matrix-optimisation/README.md
|
|
596
|
+
- lib/pact/doc.rb
|
|
594
597
|
- lib/pact/doc/doc_file.rb
|
|
595
598
|
- lib/pact/doc/generate.rb
|
|
596
599
|
- lib/pact/doc/generator.rb
|
|
@@ -735,9 +738,11 @@ files:
|
|
|
735
738
|
- lib/pact_broker/api/resources/currently_deployed_versions_for_environment.rb
|
|
736
739
|
- lib/pact_broker/api/resources/currently_supported_versions_for_environment.rb
|
|
737
740
|
- lib/pact_broker/api/resources/dashboard.rb
|
|
741
|
+
- lib/pact_broker/api/resources/deployed_or_released_versions.rb
|
|
738
742
|
- lib/pact_broker/api/resources/deployed_version.rb
|
|
739
743
|
- lib/pact_broker/api/resources/deployed_versions_for_version_and_environment.rb
|
|
740
744
|
- lib/pact_broker/api/resources/environment.rb
|
|
745
|
+
- lib/pact_broker/api/resources/environment_versions.rb
|
|
741
746
|
- lib/pact_broker/api/resources/environments.rb
|
|
742
747
|
- lib/pact_broker/api/resources/error_handler.rb
|
|
743
748
|
- lib/pact_broker/api/resources/error_handling_methods.rb
|
|
@@ -967,6 +972,8 @@ files:
|
|
|
967
972
|
- lib/pact_broker/locale/en.yml
|
|
968
973
|
- lib/pact_broker/logging.rb
|
|
969
974
|
- lib/pact_broker/logging/default_formatter.rb
|
|
975
|
+
- lib/pact_broker/logging/open_telemetry_appender_setup.rb
|
|
976
|
+
- lib/pact_broker/logging/trace_aware_json_formatter.rb
|
|
970
977
|
- lib/pact_broker/matrix/deployment_status_summary.rb
|
|
971
978
|
- lib/pact_broker/matrix/every_row.rb
|
|
972
979
|
- lib/pact_broker/matrix/integration.rb
|
|
@@ -1278,6 +1285,7 @@ homepage: https://github.com/pact-foundation/pact_broker
|
|
|
1278
1285
|
licenses:
|
|
1279
1286
|
- MIT
|
|
1280
1287
|
metadata: {}
|
|
1288
|
+
post_install_message:
|
|
1281
1289
|
rdoc_options: []
|
|
1282
1290
|
require_paths:
|
|
1283
1291
|
- lib
|
|
@@ -1285,14 +1293,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
1285
1293
|
requirements:
|
|
1286
1294
|
- - ">="
|
|
1287
1295
|
- !ruby/object:Gem::Version
|
|
1288
|
-
version: 2.
|
|
1296
|
+
version: 3.2.0
|
|
1289
1297
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1290
1298
|
requirements:
|
|
1291
1299
|
- - ">="
|
|
1292
1300
|
- !ruby/object:Gem::Version
|
|
1293
1301
|
version: '0'
|
|
1294
1302
|
requirements: []
|
|
1295
|
-
rubygems_version: 4.
|
|
1303
|
+
rubygems_version: 3.4.19
|
|
1304
|
+
signing_key:
|
|
1296
1305
|
specification_version: 4
|
|
1297
1306
|
summary: See description
|
|
1298
1307
|
test_files: []
|