pact_broker 2.118.0 → 2.119.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d5c79b9a890f8984e3e2975740672d1b6c4810a88f750202692144d54b006b2
4
- data.tar.gz: 4fb8df1387017108768afd83f9117cab1a4cf274ce9f4a66a0701ca848474b5d
3
+ metadata.gz: e28c13c74efb9e4cd894da6d14e18a28ea6d15c3240f4defc2b2fe246d1fafb0
4
+ data.tar.gz: 6194f39dd67344eed51782de55bea6d95ee937716bd59afbe8b6ee2cfe473b08
5
5
  SHA512:
6
- metadata.gz: f1916525083f39001b263ddcd4d41867dec84b640f76b1ce8cd5b8e50c8341ef7e340a6c3f85d129ca56db79984fba48b1e348751ebb19adf5400cbdeaea3808
7
- data.tar.gz: e7d66f051526f19300d62bf772082324ba8774c03341380b9de219d7ce0b6113776124a4d88a66adaf1eade5b61667a38877036e76f3f29eb83bbfdbecc98410
6
+ metadata.gz: 40138782cf26259e00e0f2417d9243f5066f4b6dd77ad076869f12f47adcfb7f4a85481e4b9f3cff4ba9ba9bf03881bbb69e71fa7b269bd868a472ed74c2b91e
7
+ data.tar.gz: 056be7ffcb8273b41d7e1292307b495a6277b71248b685515185f0239b477aa8fb6ff6646ef9ac22e86cfb87aa10bfe969ff93a1868ef10e1e81a3ae793f381a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ <a name="v2.119.0"></a>
2
+ ### v2.119.0 (2026-04-02)
3
+
4
+ #### Features
5
+
6
+ * support customising webhook requests ([d20a8274](/../../commit/d20a8274))
7
+ * Optimize WIP Query Performance to Prevent Timeouts on Large Datasets (#902) ([711ac3c6](/../../commit/711ac3c6))
8
+
9
+ #### Bug Fixes
10
+
11
+ * add missing import and small improvement to batch delete (#899) ([2e83d012](/../../commit/2e83d012))
12
+ * new unit test failure ([6c39e927](/../../commit/6c39e927))
13
+ * avoid N+1 cascade ([681d98d9](/../../commit/681d98d9))
14
+ * dont create index for mysql ([1ec72cc8](/../../commit/1ec72cc8))
15
+ * Pacticipant API returning undeployed versions in pacticipant deployed-environments endpoint (#889) ([e217d3ba](/../../commit/e217d3ba))
16
+
17
+ * **PACT-5504**
18
+ * use batch delete to speed up deletion ([e908035a](/../../commit/e908035a))
19
+
1
20
  <a name="v2.118.0"></a>
2
21
  ### v2.118.0 (2026-01-02)
3
22
 
@@ -0,0 +1,21 @@
1
+ require_relative "migration_helper"
2
+
3
+ include PactBroker::MigrationHelper
4
+
5
+ Sequel.migration do
6
+ up do
7
+ if !mysql?
8
+ alter_table(:branch_versions) do
9
+ add_index([:version_id, :branch_name], name: "branch_versions_version_id_branch_name_idx")
10
+ end
11
+ end
12
+ end
13
+
14
+ down do
15
+ if !mysql?
16
+ alter_table(:branch_versions) do
17
+ drop_index([:version_id, :branch_name], name: "branch_versions_version_id_branch_name_idx")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ Sequel.migration do
2
+ up do
3
+ if !mysql?
4
+ alter_table(:pact_versions) do
5
+ add_index :consumer_id, name: :pact_versions_consumer_id_index
6
+ add_index :provider_id, name: :pact_versions_provider_id_index
7
+ end
8
+ end
9
+ end
10
+
11
+ down do
12
+ if !mysql?
13
+ alter_table(:pact_versions) do
14
+ drop_index :consumer_id, name: :pact_versions_consumer_id_index
15
+ drop_index :provider_id, name: :pact_versions_provider_id_index
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,17 @@
1
+ Sequel.migration do
2
+ up do
3
+ if !mysql?
4
+ alter_table(:branch_versions) do
5
+ drop_index([:branch_name], name: "branch_versions_branch_name_index")
6
+ end
7
+ end
8
+ end
9
+
10
+ down do
11
+ if !mysql?
12
+ alter_table(:branch_versions) do
13
+ add_index([:branch_name], name: "branch_versions_branch_name_index")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "migration_helper"
2
+
3
+ include PactBroker::MigrationHelper
4
+
5
+ Sequel.migration do
6
+ up do
7
+ if !mysql?
8
+ alter_table(:latest_pact_publication_ids_for_consumer_versions) do
9
+ add_index :pact_version_id, name: :latest_pp_ids_for_cons_ver_pact_version_id_index
10
+ end
11
+ end
12
+ end
13
+
14
+ down do
15
+ if !mysql?
16
+ alter_table(:latest_pact_publication_ids_for_consumer_versions) do
17
+ drop_index :pact_version_id, name: :latest_pp_ids_for_cons_ver_pact_version_id_index
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,31 @@
1
+ require_relative "migration_helper"
2
+
3
+ include PactBroker::MigrationHelper
4
+
5
+ Sequel.migration do
6
+ no_transaction if PactBroker::MigrationHelper.postgres?
7
+
8
+ up do
9
+ if !mysql?
10
+ alter_table(:pact_publications) do
11
+ add_index([:provider_id, :created_at], name: "idx_pp_provider_created", concurrently: postgres?)
12
+ end
13
+
14
+ alter_table(:verifications) do
15
+ add_index([:provider_id, :provider_version_id, :success, :wip, :pact_version_id], name: "idx_verifications_provider_lookup", concurrently: postgres?)
16
+ end
17
+ end
18
+ end
19
+
20
+ down do
21
+ if !mysql?
22
+ alter_table(:pact_publications) do
23
+ drop_index([:provider_id, :created_at], name: "idx_pp_provider_created")
24
+ end
25
+
26
+ alter_table(:verifications) do
27
+ drop_index([:provider_id, :provider_version_id, :success, :wip, :pact_version_id], name: "idx_verifications_provider_lookup")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -25,7 +25,7 @@ module PactBroker
25
25
  def self.eager_load_associations
26
26
  [
27
27
  :pacticipant,
28
- :pact_publications,
28
+ { pact_publications: [:consumer, :provider, { pact_version: :latest_verification }, :tags, :head_pact_publications_for_tags] },
29
29
  { branch_versions: [:version, :branch_head, { branch: :pacticipant }] },
30
30
  { tags: :head_tag }
31
31
  ]
@@ -94,7 +94,7 @@ module PactBroker
94
94
  end
95
95
 
96
96
  def log_request
97
- logger.info "Fetching pacts for verification by #{provider_name}", provider_name: provider_name, params: query
97
+ logger.debug "Fetching pacts for verification by #{provider_name}", provider_name: provider_name, params: query
98
98
  end
99
99
 
100
100
  def nested_query
@@ -201,6 +201,32 @@ module PactBroker
201
201
  webhook_host_whitelist&.any?
202
202
  end
203
203
 
204
+ def dynamic_wip_window_enabled?
205
+ ENV["PACT_BROKER_DYNAMIC_WIP_WINDOW"]&.downcase == "true"
206
+ end
207
+
208
+ # Maximum lookback window (days) to query for unverified pacts. Prevents timeout on large datasets.
209
+ def max_wip_lookback_days
210
+ ENV["PACT_BROKER_MAX_WIP_LOOKBACK_DAYS"]&.to_i || 14
211
+ end
212
+
213
+ # Minimum WIP window (days) to ensure recent pacts are always included, even if P80 is very low.
214
+ def min_wip_window_days
215
+ ENV["PACT_BROKER_MIN_WIP_WINDOW_DAYS"]&.to_i || 7
216
+ end
217
+
218
+ # Lookback window (days) for checking if a pact was verified by another branch before this branch was created.
219
+ # Uses verification execution_date to find recent branch activity, avoiding false negatives when old
220
+ # version numbers are reused across branches.
221
+ def verified_by_other_branch_before_this_branch_look_back
222
+ ENV["PACT_BROKER_VERIFIED_BY_OTHER_BRANCH_LOOKBACK_DAYS"]&.to_i || 30
223
+ end
224
+
225
+ # Default WIP window (days) used when dynamic calculation fails or no unverified pacts exist.
226
+ def default_wip_window_days
227
+ ENV["PACT_BROKER_DEFAULT_WIP_WINDOW_DAYS"]&.to_i || 7
228
+ end
229
+
204
230
  def enable_badge_resources= enable_badge_resources
205
231
  puts "Pact Broker configuration property `enable_badge_resources` is deprecated. Please use `enable_public_badge_access`"
206
232
  self.enable_public_badge_access = enable_badge_resources
@@ -68,6 +68,7 @@ module PactBroker
68
68
 
69
69
  def self.find_all_deployed_versions_for_pacticipant(pacticipant)
70
70
  scope_for(DeployedVersion)
71
+ .currently_deployed
71
72
  .where(pacticipant_id: pacticipant.id)
72
73
  .eager(:environment)
73
74
  .all
@@ -55,11 +55,22 @@ module PactBroker
55
55
  PactBroker::Pacts::PactPublication.where(provider: self).delete
56
56
  PactBroker::Domain::Verification.where(consumer: self).or(provider: self).delete
57
57
  PactBroker::Domain::Version.where(pacticipant: self).delete
58
- PactBroker::Pacts::PactVersion.where(consumer: self).or(provider: self).delete
58
+ delete_pact_versions_in_batches
59
59
  PactBroker::Domain::Label.where(pacticipant: self).destroy
60
60
  super
61
61
  end
62
62
 
63
+ BATCH_DELETE_SIZE = 500
64
+ def delete_pact_versions_in_batches
65
+ dataset = PactBroker::Pacts::PactVersion.where(consumer: self).or(provider: self).order(:id)
66
+ loop do
67
+ deleted = PactBroker::Pacts::PactVersion
68
+ .where(id: dataset.limit(BATCH_DELETE_SIZE).select(:id))
69
+ .delete
70
+ break if deleted.zero?
71
+ end
72
+ end
73
+
63
74
  def before_save
64
75
  super
65
76
  self.display_name = generate_display_name(name) if display_name.blank?
@@ -52,6 +52,16 @@ module PactBroker
52
52
  end
53
53
  end
54
54
 
55
+ def measure_debug(message, payload: {})
56
+ if logger.respond_to?(:measure_debug)
57
+ logger.measure_debug(message, payload: payload) do
58
+ yield
59
+ end
60
+ else
61
+ yield
62
+ end
63
+ end
64
+
55
65
  def log_error e, description = nil
56
66
  if logger.instance_of?(SemanticLogger::Logger)
57
67
  if description
@@ -287,9 +287,13 @@ module PactBroker
287
287
  # NEW LOGIC
288
288
  # @return [Sequel::Dataset<PactBroker::Pacts::PactPublication>]
289
289
  def for_all_tag_heads
290
+ # Optimization: Only aggregate tags for consumers that have pacts for this provider.
291
+ relevant_consumer_ids = self.select(:consumer_id).distinct
292
+
290
293
  head_tags = PactBroker::Domain::Tag
291
294
  .select_group(:pacticipant_id, :name)
292
- .select_append{ max(version_order).as(:latest_version_order) }
295
+ .select_append{ max(:version_order).as(:latest_version_order) }
296
+ .where(pacticipant_id: relevant_consumer_ids)
293
297
 
294
298
  head_tags_join = {
295
299
  Sequel[:pact_publications][:consumer_id] => Sequel[:head_tags][:pacticipant_id],
@@ -19,13 +19,19 @@ module PactBroker
19
19
  end
20
20
 
21
21
  def join_branch_versions_excluding_branch(provider_id, branch_name)
22
+ # Only check branches that have been active in the last N days
23
+ # to avoid old stale branches causing cartesian explosion.
24
+ # Filter by verification execution_date rather than version created_at
25
+ # to avoid incorrectly excluding old versions with recent verifications.
26
+ recent_branch_cutoff = DateTime.now - PactBroker.configuration.verified_by_other_branch_before_this_branch_look_back
27
+
22
28
  branch_versions_join = {
23
29
  Sequel[:verifications][:provider_version_id] => Sequel[:branch_versions][:version_id],
24
30
  Sequel[:branch_versions][:pacticipant_id] => provider_id
25
31
  }
26
- join(:branch_versions, branch_versions_join) do
27
- Sequel.lit("branch_versions.branch_name != ?", branch_name)
28
- end
32
+ join(:branch_versions, branch_versions_join)
33
+ .where { Sequel[:verifications][:execution_date] >= recent_branch_cutoff }
34
+ .where { Sequel.lit("branch_versions.branch_name != ?", branch_name) }
29
35
  end
30
36
 
31
37
  def join_provider_versions_for_provider_id_and_branch(provider_id, provider_version_branch)
@@ -45,10 +51,13 @@ module PactBroker
45
51
  end
46
52
 
47
53
  def successfully_verified_by_provider_branch_when_not_wip(provider_id, provider_version_branch)
54
+ # Only check verifications from last N days (old verifications unlikely relevant for WIP)
55
+ recent_cutoff = DateTime.now - PactBroker.configuration.verified_by_other_branch_before_this_branch_look_back
48
56
  successful_verifications = VerificationForWipCalculations
49
57
  .select(:pact_version_id)
50
58
  .distinct
51
59
  .successful_non_wip_by_provider(provider_id)
60
+ .where { Sequel[:verifications][:execution_date] >= recent_cutoff }
52
61
  .join_provider_versions_for_provider_id_and_branch(provider_id, provider_version_branch)
53
62
 
54
63
 
@@ -65,8 +74,8 @@ module PactBroker
65
74
  .select(:pact_version_id)
66
75
  .distinct
67
76
  .successful_non_wip_by_provider(provider_id)
68
- .join_branch_versions_excluding_branch(provider_id, provider_version_branch)
69
77
  .verified_before_creation_date_of(first_version_for_branch)
78
+ .join_branch_versions_excluding_branch(provider_id, provider_version_branch)
70
79
 
71
80
  from_self(alias: :pp)
72
81
  .select(Sequel[:pp].*)
@@ -57,7 +57,7 @@ module PactBroker
57
57
  end
58
58
 
59
59
  provider = pacticipant_repository.find_by_name(provider_name)
60
- wip_start_date = options.fetch(:include_wip_pacts_since)
60
+ wip_start_date = determine_wip_start_date(provider, options)
61
61
 
62
62
  wip_by_consumer_tags = find_wip_pact_versions_for_provider_by_provider_tags(
63
63
  provider,
@@ -80,6 +80,94 @@ module PactBroker
80
80
 
81
81
  private
82
82
 
83
+ # Determine the WIP start date based on configuration and options
84
+ def determine_wip_start_date(provider, options)
85
+ dynamic_enabled = PactBroker.configuration.dynamic_wip_window_enabled?
86
+ logger.debug("Dynamic WIP window: #{dynamic_enabled ? 'enabled' : 'disabled'}") if logger.debug?
87
+
88
+ if dynamic_enabled
89
+ calculate_wip_window(provider)
90
+ else
91
+ wip_start_date = options.fetch(:include_wip_pacts_since)
92
+ logger.debug("Using user-specified WIP window: #{wip_start_date}") if logger.debug?
93
+ wip_start_date
94
+ end
95
+ end
96
+
97
+ # Calculate optimal WIP window using P80 (80th percentile) of unverified pact ages
98
+ # Uses percentile instead of MAX to focus on active work and ignore abandoned pacts
99
+ # Returns: Date from N days ago (min 7 for weekly coverage, max 14 to align with query scope)
100
+ def calculate_wip_window(provider)
101
+ # Step 1: Get list of unverified pact ages in days (e.g., [2, 5, 7, 10, 12, 14])
102
+ unverified_ages = get_unverified_pact_ages_in_days(provider)
103
+
104
+ # Step 2: If no unverified pacts, use default configured window
105
+ if unverified_ages.empty?
106
+ default_window = PactBroker.configuration.default_wip_window_days
107
+ logger.debug("No unverified pacts found for #{provider.name}, using default #{default_window}-day window") if logger.debug?
108
+ return Date.today - default_window
109
+ end
110
+
111
+ # Step 3: Calculate 80th percentile (ignore oldest 20% as abandoned work)
112
+ p80_age = percentile_80(unverified_ages)
113
+
114
+ # Step 4: Ensure window is between configured min-max days, then return date
115
+ min_window = PactBroker.configuration.min_wip_window_days
116
+ max_window = PactBroker.configuration.max_wip_lookback_days
117
+ window_days = clamp_between(p80_age, min_window, max_window)
118
+ wip_start_date = Date.today - window_days
119
+
120
+ if logger.debug?
121
+ logger.debug("Dynamic WIP window for #{provider.name}: found #{unverified_ages.size} unverified pacts, P80=#{p80_age} days, window=#{window_days} days (#{wip_start_date})")
122
+ end
123
+
124
+ wip_start_date
125
+ rescue StandardError => e
126
+ default_window = PactBroker.configuration.default_wip_window_days
127
+ logger.error("Failed to calculate dynamic WIP window for provider #{provider.name}", error: e.class.name, message: e.message)
128
+ Date.today - default_window
129
+ end
130
+
131
+ # Get ages (in days) of pacts that haven't been successfully verified yet
132
+ # Only looks back the configured max_wip_lookback_days to keep query fast
133
+ def get_unverified_pact_ages_in_days(provider)
134
+ max_days = PactBroker.configuration.max_wip_lookback_days
135
+ cutoff_date = DateTime.now - max_days
136
+
137
+ # Use database-specific date arithmetic that works on both PostgreSQL and SQLite
138
+ # PostgreSQL: CURRENT_DATE - created_at::date returns integer days
139
+ # SQLite: julianday(date('now')) - julianday(date(created_at)) returns float days
140
+ db = PactPublication.db
141
+ age_expr = if db.database_type == :postgres
142
+ Sequel.lit("CURRENT_DATE - ?::date", Sequel[:pact_publications][:created_at])
143
+ else
144
+ # SQLite
145
+ Sequel.function(:julianday, Sequel.function(:date, "now")) -
146
+ Sequel.function(:julianday, Sequel.function(:date, Sequel[:pact_publications][:created_at]))
147
+ end
148
+
149
+ PactPublication
150
+ .where(Sequel[:pact_publications][:provider_id] => provider.id)
151
+ .where { Sequel[:pact_publications][:created_at] >= cutoff_date }
152
+ .left_join(:verifications, { pact_version_id: :pact_version_id, success: true })
153
+ .where(Sequel[:verifications][:id] => nil)
154
+ .select_map { Sequel.cast(age_expr, :integer).as(:age_days) }
155
+ .compact
156
+ end
157
+
158
+ # Calculate 80th percentile: find value where 80% of data points are less than or equal
159
+ # Example: [2,3,5,7,10,12,14,20] → 80% index = 6 → value = 14
160
+ def percentile_80(values)
161
+ sorted = values.sort
162
+ index = [(sorted.length * 0.80).ceil - 1, 0].max
163
+ sorted[index]
164
+ end
165
+
166
+ # Constrain value between min and max bounds
167
+ def clamp_between(value, min, max)
168
+ [[value, max].min, min].max
169
+ end
170
+
83
171
  # Note: created_at is coming back as a string for sqlite
84
172
  # Can't work out how to to tell Sequel that this should be a date
85
173
  def to_datetime string_or_datetime
@@ -227,7 +315,7 @@ module PactBroker
227
315
 
228
316
  def find_wip_pact_versions_for_provider_by_provider_branch(provider_name, provider_version_branch, explicitly_specified_verifiable_pacts, options)
229
317
  provider = pacticipant_repository.find_by_name(provider_name)
230
- wip_start_date = options.fetch(:include_wip_pacts_since)
318
+ wip_start_date = determine_wip_start_date(provider, options)
231
319
 
232
320
  potential_wip_by_consumer_branch = PactPublication.for_provider(provider).created_after(wip_start_date).for_all_branch_heads
233
321
  potential_wip_by_consumer_tag = PactPublication.for_provider(provider).created_after(wip_start_date).for_all_tag_heads
@@ -149,7 +149,7 @@ module PactBroker
149
149
  query = query.overall_latest
150
150
  end
151
151
 
152
- query.all.sort_by{ | p| p.consumer_name.downcase }.collect(&:to_head_pact)
152
+ query.all.sort.collect(&:to_head_pact)
153
153
  end
154
154
 
155
155
  def find_pacts_by_consumer_branch(provider_name, options = {})
@@ -179,7 +179,7 @@ module PactBroker
179
179
  query = query.for_branch_name(branch)
180
180
  end
181
181
  end
182
- query.all.sort_by{ | p| p.consumer_name.downcase }.collect(&:to_head_pact)
182
+ query.all.sort.collect(&:to_head_pact)
183
183
  end
184
184
 
185
185
  def find_for_verification(provider_name, consumer_version_selectors)
@@ -210,7 +210,7 @@ module PactBroker
210
210
 
211
211
  # When no publication for the given consumer/provider/consumer version number exists
212
212
  def create_pact(params, version, provider)
213
- logger.info("Creating new pact publication", params.without(:json_content))
213
+ logger.debug("Creating new pact publication", params.without(:json_content))
214
214
  logger.debug("Content #{params[:json_content]}")
215
215
  json_content = add_interaction_ids(params[:json_content])
216
216
  pact = pact_repository.create(
@@ -1,3 +1,3 @@
1
1
  module PactBroker
2
- VERSION = "2.118.0"
2
+ VERSION = "2.119.0"
3
3
  end
@@ -22,7 +22,7 @@ module PactBroker
22
22
  end
23
23
 
24
24
  def add_branch(version, branch_name, auto_created: false)
25
- PactBroker.logger.info("BranchVersionRepository#add_branch method called with version #{version.inspect} and branch_name '#{branch_name}'")
25
+ PactBroker.logger.debug("BranchVersionRepository#add_branch method called with version #{version.inspect} and branch_name '#{branch_name}'")
26
26
  Sequel::Model.db.transaction do
27
27
  branch = find_or_create_branch(version.pacticipant, branch_name)
28
28
  branch_version = version.branch_version_for_branch(branch)
@@ -56,7 +56,7 @@ module PactBroker
56
56
  logger.debug("Event detected", event_name: event.name, event_comment: event.comment)
57
57
  if event.triggered_webhooks&.any?
58
58
  triggered_webhook_descriptions = event.triggered_webhooks.collect{ |tw| { event_name: event.name, webhook_uuid: tw.webhook_uuid, triggered_webhook_uuid: tw.uuid, webhook_description: tw.webhook.description } }
59
- logger.info("Triggered webhooks for #{event.name}", triggered_webhooks: triggered_webhook_descriptions)
59
+ logger.debug("Triggered webhooks for #{event.name}", triggered_webhooks: triggered_webhook_descriptions)
60
60
  else
61
61
  logger.debug "No enabled webhooks found for event #{event.name}"
62
62
  end
@@ -53,6 +53,10 @@ module PactBroker
53
53
  with_updated_attribute(cert_store: value)
54
54
  end
55
55
 
56
+ def with_request_customizer(value)
57
+ with_updated_attribute(request_customizer: value)
58
+ end
59
+
56
60
  def webhook_context
57
61
  self[:webhook_context]
58
62
  end
@@ -7,12 +7,12 @@ module PactBroker
7
7
 
8
8
  using PactBroker::StringRefinements
9
9
 
10
- def redact_logs(logs, values)
11
- RedactLogs.call(logs, values)
10
+ def redact_logs(logs, values, pattern_substitutions = [])
11
+ RedactLogs.call(logs, values, pattern_substitutions)
12
12
  end
13
13
 
14
- def self.call logs, values
15
- substitutions = HEADER_SUBSTITUTIONS + value_substitutions(values)
14
+ def self.call logs, values, pattern_substitutions = []
15
+ substitutions = HEADER_SUBSTITUTIONS + pattern_substitutions + value_substitutions(values)
16
16
 
17
17
  substitutions.reduce(logs) do | agg_logs, (find, replace) |
18
18
  agg_logs.gsub(find, replace)
@@ -68,6 +68,7 @@ module Sequel
68
68
  end
69
69
 
70
70
  def manual_upsert(opts)
71
+ sync_deserialized_values_to_values
71
72
  # Can use slice when we drop support for Ruby 2.4
72
73
  query = values.select{ |k, _| self.class.upsert_plugin_identifying_columns.include?(k) }
73
74
  existing_record = model.where(query).single_record
@@ -79,6 +80,12 @@ module Sequel
79
80
  end
80
81
  end
81
82
 
83
+ def sync_deserialized_values_to_values
84
+ if respond_to?(:deserialized_values) && deserialized_values.is_a?(Hash)
85
+ deserialized_values.each { |k, v| values[k] = v }
86
+ end
87
+ end
88
+
82
89
  # naughty override of Sequel private method to
83
90
  # avoid having to rewrite the whole save method logic
84
91
  def _insert_dataset
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact_broker
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.118.0
4
+ version: 2.119.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bethany Skurrie
@@ -579,8 +579,13 @@ files:
579
579
  - db/migrations/20231002_add_version_id_index_to_released_version.rb
580
580
  - db/migrations/20231003_add_version_id_index_to_deployed_version.rb
581
581
  - db/migrations/20240112_add_client_language_verified_by_to_verification.rb
582
+ - db/migrations/20251106_add_branch_versions_version_id_branch_name_index.rb
582
583
  - db/migrations/20251202_add_has_messages_column_to_pact_versions.rb
583
584
  - db/migrations/20251202_populate_has_messages_in_pact_versions.rb
585
+ - db/migrations/20260119_add_index_on_consumer_id_provider_id_to_pact_versions.rb
586
+ - db/migrations/20260123_drop_branch_versions_branch_name_index.rb
587
+ - db/migrations/20260210_add_index_on_pact_version_id_to_latest_pact_publication.rb
588
+ - db/migrations/20260217_add_wip_query_optimization_indexes.rb
584
589
  - db/migrations/migration_helper.rb
585
590
  - docs/CONFIGURATION.md
586
591
  - docs/api/PACTICIPANTS.md
@@ -1290,7 +1295,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1290
1295
  - !ruby/object:Gem::Version
1291
1296
  version: '0'
1292
1297
  requirements: []
1293
- rubygems_version: 4.0.3
1298
+ rubygems_version: 4.0.10
1294
1299
  specification_version: 4
1295
1300
  summary: See description
1296
1301
  test_files: []