bitfab 0.21.2 → 0.22.1

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: 910352d2c5434b3fae7c3c56ccfea74dc0a22ce35d0cb4d2cb9d463e4ba3660b
4
- data.tar.gz: 2e4e07a7447b75404e753f9a2d45350edfbee088ba100aff06031cf477cbc59c
3
+ metadata.gz: eb8d7ab7e95fed00c067b1653c4d8271c1814b6a9d42bc8ffbb320596ac2190e
4
+ data.tar.gz: 6050620ec20d4172045e7a7c29930349e488cd886132cb54758ca98d789be34f
5
5
  SHA512:
6
- metadata.gz: 1d197beb80ef3dcd1e57a8aebbe3aafd39ed000cadb0e1098ca71369d69ba53d4e805626f632b3bfdfb5f0cbe36d12e34d589f0b3def09be7e397bb1363e8b5e
7
- data.tar.gz: 2f35b7eeba42eb86005e8cb9af3f46654313a84bc375e3c0edbd04e716cd8c511d0d302c2626d5f679b663f3482a24d8ec9b91d9b653fb2da6412aea0da2280b
6
+ metadata.gz: c94a534717dfbf682ca6d4f1fb6e9501fba8df1057bd6390457c4f561616a23bf53092bfc4bc8cc966f67037d1a7a9b8f2eadc4edff92645a99e2b0a9ffcf33b
7
+ data.tar.gz: 7e416c3b5af6248ada3bda42d56d2853d68792e7adcf3bb4a1e1af98b5b4740ee92cd7e25ba8c86fee0bc0b0acaa5acd102bb1d8e561d03d0e669d24de877048
data/lib/bitfab/client.rb CHANGED
@@ -68,11 +68,11 @@ module Bitfab
68
68
  # A raising callback never crashes the run.
69
69
  # @return [Hash] with :items, :test_run_id, :test_run_url
70
70
  def replay(receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, max_concurrency: 10,
71
- code_change_description: nil, code_change_files: nil, experiment_group_id: nil, dataset_id: nil, mock: "none",
71
+ name: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, dataset_id: nil, mock: "none",
72
72
  adapt_inputs: nil, environment: nil, on_progress: nil)
73
73
  Replay.run(
74
74
  self, receiver, method_name,
75
- trace_function_key:, limit:, trace_ids:, max_concurrency:,
75
+ trace_function_key:, limit:, trace_ids:, name:, max_concurrency:,
76
76
  code_change_description:, code_change_files:, experiment_group_id:, dataset_id:, mock:, adapt_inputs:, environment:,
77
77
  on_progress:
78
78
  )
@@ -3,4 +3,8 @@
3
3
  module Bitfab
4
4
  DEFAULT_SERVICE_URL = "https://bitfab.ai"
5
5
  REPLAY_CONTEXT_KEY = :__bitfab_replay_context
6
+
7
+ # Wire prefix the Bitfab plugin scans for on stderr to report live progress
8
+ # while a replay runs. One trailing space, then the progress object as JSON.
9
+ BITFAB_PROGRESS_PREFIX = "@@bitfab:progress "
6
10
  end
@@ -107,10 +107,12 @@ module Bitfab
107
107
  # each as { path:, before:, after: } (use "" for new/deleted files)
108
108
  # @param experiment_group_id [String, nil] optional UUID grouping multiple
109
109
  # replay runs into a single experiment batch
110
+ # @param name [String, nil] optional display name for the resulting
111
+ # experiment/test run
110
112
  # @param dataset_id [String, nil] optional UUID of the dataset this replay
111
113
  # runs against, stored on the resulting experiment for durable attribution
112
114
  def start_replay(trace_function_key, limit, trace_ids: nil, code_change_description: nil,
113
- code_change_files: nil, experiment_group_id: nil, include_db_branch_lease: false, dataset_id: nil)
115
+ code_change_files: nil, experiment_group_id: nil, name: nil, include_db_branch_lease: false, dataset_id: nil)
114
116
  payload = {
115
117
  "traceFunctionKey" => trace_function_key
116
118
  }
@@ -118,6 +120,7 @@ module Bitfab
118
120
  # already determines the count), so it's omitted when nil.
119
121
  payload["limit"] = limit unless limit.nil?
120
122
  payload["traceIds"] = trace_ids if trace_ids
123
+ payload["name"] = name unless name.nil?
121
124
  payload["codeChangeDescription"] = code_change_description unless code_change_description.nil?
122
125
  payload["codeChangeFiles"] = normalize_code_change_files(code_change_files) unless code_change_files.nil?
123
126
  payload["experimentGroupId"] = experiment_group_id unless experiment_group_id.nil?
data/lib/bitfab/replay.rb CHANGED
@@ -82,6 +82,7 @@ module Bitfab
82
82
  # Ignored when trace_ids is passed (with a warning): an explicit ID list
83
83
  # already determines how many traces replay.
84
84
  # @param trace_ids [Array<String>, nil] optional list of trace IDs to replay (max 100)
85
+ # @param name [String, nil] optional display name for the resulting experiment/test run
85
86
  # @param max_concurrency [Integer, nil] max threads for parallel replay (default: 10)
86
87
  # @param code_change_description [String, nil] optional rationale for the
87
88
  # code change being tested in this replay (stored on the experiment)
@@ -102,11 +103,16 @@ module Bitfab
102
103
  # that item's :error rather than crashing the run.
103
104
  # @param on_progress [#call, nil] optional callback invoked once per item as
104
105
  # it finishes, with a running-totals hash { completed:, total:, succeeded:,
105
- # errored: }. Use it to render replay progress (e.g. a terminal progress
106
- # bar). A raising callback never crashes the run.
106
+ # errored:, item: } where item is { trace_id:, error:, duration_ms: } for
107
+ # the single item that just settled. trace_id is the SOURCE (historical)
108
+ # trace that was replayed, error is that item's replay error or nil, and
109
+ # duration_ms is how long that one trace took to replay. Use it to
110
+ # render replay progress (e.g. a per-trace log). A raising callback never
111
+ # crashes the run.
107
112
  # @return [Hash] with :items, :test_run_id, :test_run_url
108
- def run(client, receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, max_concurrency: 10,
109
- code_change_description: nil, code_change_files: nil, experiment_group_id: nil, dataset_id: nil, mock: "none",
113
+ def run(client, receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, name: nil,
114
+ max_concurrency: 10, code_change_description: nil, code_change_files: nil, experiment_group_id: nil,
115
+ dataset_id: nil, mock: "none",
110
116
  adapt_inputs: nil, environment: nil, on_progress: nil)
111
117
  unless MOCK_STRATEGIES.include?(mock.to_s)
112
118
  raise ArgumentError, "Invalid mock strategy '#{mock}'. Must be one of: #{MOCK_STRATEGIES.join(", ")}"
@@ -149,6 +155,7 @@ module Bitfab
149
155
  trace_function_key,
150
156
  effective_limit,
151
157
  trace_ids:,
158
+ name:,
152
159
  code_change_description:,
153
160
  code_change_files:,
154
161
  experiment_group_id:,
@@ -254,14 +261,23 @@ module Bitfab
254
261
  completed = 0
255
262
  succeeded = 0
256
263
  errored = 0
257
- report = lambda do |result|
264
+ # Each event carries the single item that just settled so a progress UI
265
+ # can render per-trace pass/fail as the run streams. trace_id is the
266
+ # SOURCE (historical) trace that was replayed, taken from the server
267
+ # item: the result's own :trace_id at this stage is the new replay
268
+ # trace id (assigned in run() after complete_replay), not the source.
269
+ report = lambda do |result, source_trace_id|
258
270
  return unless on_progress
259
271
 
260
272
  progress_mutex.synchronize do
261
273
  completed += 1
262
- result[:error].nil? ? (succeeded += 1) : (errored += 1)
274
+ error = result[:error]
275
+ error.nil? ? (succeeded += 1) : (errored += 1)
263
276
  begin
264
- on_progress.call({completed:, total:, succeeded:, errored:})
277
+ on_progress.call({
278
+ completed:, total:, succeeded:, errored:,
279
+ item: {trace_id: source_trace_id, error:, duration_ms: result[:duration_ms]}
280
+ })
265
281
  rescue => e
266
282
  warn "Bitfab: replay on_progress callback raised: #{e.message}"
267
283
  end
@@ -272,7 +288,7 @@ module Bitfab
272
288
  server_items.map do |item|
273
289
  result = process_single_item(http_client, item, receiver, method_name, test_run_id, mock_strategy,
274
290
  adapt_inputs, include_db_branch_lease)
275
- report.call(result)
291
+ report.call(result, item["traceId"])
276
292
  result
277
293
  end
278
294
  else
@@ -290,7 +306,7 @@ module Bitfab
290
306
  result = process_single_item(http_client, item, receiver, method_name, test_run_id, mock_strategy,
291
307
  adapt_inputs, include_db_branch_lease)
292
308
  results_mutex.synchronize { results[idx] = result }
293
- report.call(result)
309
+ report.call(result, item["traceId"])
294
310
  end
295
311
  end
296
312
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bitfab
4
- VERSION = "0.21.2"
4
+ VERSION = "0.22.1"
5
5
  end
data/lib/bitfab.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
4
+
3
5
  require_relative "bitfab/version"
4
6
  require_relative "bitfab/constants"
5
7
  require_relative "bitfab/warn_once"
@@ -103,5 +105,26 @@ module Bitfab
103
105
 
104
106
  CurrentTrace.new(entry[:trace_id])
105
107
  end
108
+
109
+ # A ready-made on_progress callback for replay: writes one @@bitfab:progress
110
+ # line per trace to stderr, which the Bitfab plugin polls to report live
111
+ # progress while the replay runs in the background, so replay scripts never
112
+ # hand-format the protocol. stdout stays the ReplayResult JSON. Never raises
113
+ # (progress must not crash a run). The progress hash's item ({ trace_id:,
114
+ # error:, duration_ms: }) is forwarded verbatim through to_json, so the
115
+ # plugin sees the source trace id, error, and duration of the item that just
116
+ # settled.
117
+ #
118
+ # @example
119
+ # Bitfab.client.replay(..., on_progress: Bitfab.method(:report_replay_progress))
120
+ #
121
+ # @param progress [Hash] running totals with keys completed, total,
122
+ # succeeded, errored, and item (the object replay already passes to
123
+ # on_progress)
124
+ def report_replay_progress(progress)
125
+ warn "#{BITFAB_PROGRESS_PREFIX}#{progress.to_json}"
126
+ rescue
127
+ nil
128
+ end
106
129
  end
107
130
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitfab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.2
4
+ version: 0.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harvest Team