bitfab 0.70.0 → 0.71.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/lib/bitfab/client.rb +12 -5
- data/lib/bitfab/cloudReplay.py +32 -3
- data/lib/bitfab/replay.rb +44 -16
- data/lib/bitfab/replay_registry.rb +14 -5
- data/lib/bitfab/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a84477fef0e70e513ab93e7ef81a0ef9021d5f09adefe8021075d89fbb26a64d
|
|
4
|
+
data.tar.gz: 39795db6575ecc859004b3db5af4d35b13747234d8fafd43f444819c4e2425dc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0327c9092bb7b6d9071546c6a54ae5f64e49083518c6e35c3049eb04455b32eed4fa976df0c35a7d59d9231d0107cff212eca5a8287f5d4d043d1e566b5e1a58
|
|
7
|
+
data.tar.gz: bab39d209b61f795eb681bafdf7e5e19b6707977864e6c7a5b72d5ee02af449a8c1f0a3b8c29a06229ef32f099326dfe3c6ba1890156cdf9a37308daab137bf9
|
data/lib/bitfab/client.rb
CHANGED
|
@@ -147,16 +147,22 @@ module Bitfab
|
|
|
147
147
|
# diff against the branch this one was cut from, such as the branch below
|
|
148
148
|
# it in a stack, else the default branch; "default-branch" the diff
|
|
149
149
|
# against where HEAD split from the default branch (origin/HEAD, else
|
|
150
|
-
# origin/main, origin/master, main, master); "
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
#
|
|
150
|
+
# origin/main, origin/master, main, master); "ref" the diff against where
|
|
151
|
+
# HEAD split from the branch or commit in code_change_base; "skip" no code
|
|
152
|
+
# change, such as for a baseline run; "manual" the files in
|
|
153
|
+
# code_change_files. The four git choices include uncommitted edits and
|
|
154
|
+
# untracked files, and warn and attach nothing when they find no changed
|
|
155
|
+
# files.
|
|
154
156
|
# @param code_change_description [String, nil] description of the code
|
|
155
157
|
# change, stored on the experiment. Defaults to one generated from the
|
|
156
158
|
# captured files. Not accepted with "skip".
|
|
157
159
|
# @param code_change_files [Array<Hash>, nil] the edited files when
|
|
158
160
|
# code_change is "manual", and only then, each as { path:, before:, after: }
|
|
159
161
|
# (use "" for new/deleted files).
|
|
162
|
+
# @param code_change_base [String, nil] the branch or commit to diff
|
|
163
|
+
# against when code_change is "ref", and only then, such as "dev",
|
|
164
|
+
# "release/2.3", or a commit SHA. A branch that exists only on the remote
|
|
165
|
+
# is read as origin/<name>. A name git cannot resolve raises ArgumentError.
|
|
160
166
|
# @param experiment_group_id [String, nil] optional UUID grouping multiple
|
|
161
167
|
# replay runs into a single experiment batch. The run joins that group,
|
|
162
168
|
# and an id no group has yet creates it
|
|
@@ -222,7 +228,7 @@ module Bitfab
|
|
|
222
228
|
# @return [Hash] with :items, :experiment_id, :experiment_url, and the
|
|
223
229
|
# deprecated aliases :test_run_id and :test_run_url carrying the same values
|
|
224
230
|
def replay(receiver, method_name = nil, trace_function_key:, limit: nil, trace_ids: nil, concurrency: nil, max_concurrency: ReplayConcurrency::UNSET,
|
|
225
|
-
name: nil, notes: nil, metadata: nil, code_change: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, experiment_group_name: nil, dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
231
|
+
name: nil, notes: nil, metadata: nil, code_change: nil, code_change_description: nil, code_change_files: nil, code_change_base: nil, experiment_group_id: nil, experiment_group_name: nil, dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
226
232
|
adapt_inputs: nil, mock_override: nil, db_branch: nil, on_item_start: nil, on_item_finish: nil, on_progress: nil,
|
|
227
233
|
on_experiment_start: nil, experimental_selective_replay: nil)
|
|
228
234
|
Replay.run(
|
|
@@ -245,6 +251,7 @@ module Bitfab
|
|
|
245
251
|
code_change:,
|
|
246
252
|
code_change_description:,
|
|
247
253
|
code_change_files:,
|
|
254
|
+
code_change_base:,
|
|
248
255
|
experiment_group_id:,
|
|
249
256
|
experiment_group_name:,
|
|
250
257
|
dataset_id:,
|
data/lib/bitfab/cloudReplay.py
CHANGED
|
@@ -149,7 +149,10 @@ RENAMED_FLAGS = {
|
|
|
149
149
|
SEED_FLAGS = ("--seed", "--cases", "--from-trace", "--run")
|
|
150
150
|
PATH_FLAGS = ("--registry", "--params", "--code-change-file")
|
|
151
151
|
CODE_CHANGE_FLAG = "--code-change"
|
|
152
|
-
|
|
152
|
+
CODE_CHANGE_BASE_FLAG = "--code-change-base"
|
|
153
|
+
BRANCH_CODE_CHANGES = ("last-branch", "default-branch", "ref")
|
|
154
|
+
GIT_CODE_CHANGES = ("working-tree", *BRANCH_CODE_CHANGES)
|
|
155
|
+
DESCRIBED_REF = re.compile(r"[^\x00-\x1f\x7f]{1,200}")
|
|
153
156
|
CHECKOUT_DEPTH = 2
|
|
154
157
|
CODE_CHANGE_PATH_ENV = "BITFAB_CODE_CHANGE_PATH"
|
|
155
158
|
CODE_CHANGE_MAX_FILES = 60
|
|
@@ -220,7 +223,9 @@ Options added by --cloud:
|
|
|
220
223
|
checkout of the repository, with GitHub access that can
|
|
221
224
|
read it and run Actions (a job token needs contents: read
|
|
222
225
|
and actions: write, passed as GH_TOKEN), and a workflow on
|
|
223
|
-
BRANCH that declares a request input.
|
|
226
|
+
BRANCH that declares a request input. With no snapshot
|
|
227
|
+
there is nothing to diff against, so it takes
|
|
228
|
+
--code-change skip or manual, as does a dispatched run.
|
|
224
229
|
|
|
225
230
|
A workflow can also dispatch bitfab-replay.yml itself on any branch other than a
|
|
226
231
|
bitfab-replay/ snapshot branch, passing the replay as JSON in the request input:
|
|
@@ -1029,8 +1034,30 @@ def default_branch_point(root):
|
|
|
1029
1034
|
return {"sha": sha, "ref": default} if sha else None
|
|
1030
1035
|
|
|
1031
1036
|
|
|
1037
|
+
def chosen_base_point(root, chosen):
|
|
1038
|
+
if not chosen or chosen.startswith("-"):
|
|
1039
|
+
return None
|
|
1040
|
+
for ref in (chosen, f"origin/{chosen}"):
|
|
1041
|
+
if quiet_git(root, "rev-parse", "--verify", "-q", f"{ref}^{{commit}}"):
|
|
1042
|
+
sha = quiet_git(root, "merge-base", "HEAD", ref)
|
|
1043
|
+
return {"sha": sha, "ref": chosen} if sha else None
|
|
1044
|
+
raise ValueError(
|
|
1045
|
+
f"{CODE_CHANGE_BASE_FLAG} {chosen} names no branch or commit in this repository; pass a branch name or a commit SHA, and fetch it first if it only exists on the remote"
|
|
1046
|
+
)
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
def refuse_git_code_change(replay, where):
|
|
1050
|
+
kind = flag_value(replay, CODE_CHANGE_FLAG)
|
|
1051
|
+
if kind in GIT_CODE_CHANGES:
|
|
1052
|
+
raise ValueError(
|
|
1053
|
+
f"{where} as it is on GitHub, with no snapshot of a checkout, so --code-change {kind} has nothing to compare against there; pass --code-change skip, or --code-change manual with --code-change-file, or start it with bitfab-replay --cloud and no --cloud-ref, which resolves {kind} from your checkout before upload"
|
|
1054
|
+
)
|
|
1055
|
+
|
|
1056
|
+
|
|
1032
1057
|
def code_change_base(root, replay):
|
|
1033
1058
|
kind = flag_value(replay, CODE_CHANGE_FLAG)
|
|
1059
|
+
if kind == "ref":
|
|
1060
|
+
return chosen_base_point(root, flag_value(replay, CODE_CHANGE_BASE_FLAG))
|
|
1034
1061
|
if kind == "last-branch":
|
|
1035
1062
|
return branch_point(root)
|
|
1036
1063
|
if kind == "default-branch":
|
|
@@ -1839,6 +1866,7 @@ def submit_as_is(root, repo, workflow, parsed, path):
|
|
|
1839
1866
|
branch = parsed["cloud"]["--cloud-ref"]
|
|
1840
1867
|
request, _ = replay_request(root, parsed)
|
|
1841
1868
|
check_arguments(parsed["replay"])
|
|
1869
|
+
refuse_git_code_change(parsed["replay"], f"--cloud-ref replays {branch}")
|
|
1842
1870
|
sha = branch_head(repo, branch)
|
|
1843
1871
|
if "--cloud-preview" in parsed["switches"]:
|
|
1844
1872
|
return {
|
|
@@ -2089,6 +2117,7 @@ def dispatched_request():
|
|
|
2089
2117
|
raise ValueError("The request id does not match the execution_id input")
|
|
2090
2118
|
args = request.get("args")
|
|
2091
2119
|
validate_arguments(args)
|
|
2120
|
+
refuse_git_code_change(args, f"A dispatched replay runs {branch}")
|
|
2092
2121
|
if request.get("check") is True and "--dry-run" not in args:
|
|
2093
2122
|
args = [*args, "--dry-run"]
|
|
2094
2123
|
normalized = {
|
|
@@ -2227,7 +2256,7 @@ def branch_code_change(root, base, commit, request):
|
|
|
2227
2256
|
isinstance(sha, str)
|
|
2228
2257
|
and SHA.fullmatch(sha)
|
|
2229
2258
|
and isinstance(ref, str)
|
|
2230
|
-
and
|
|
2259
|
+
and DESCRIBED_REF.fullmatch(ref)
|
|
2231
2260
|
and (
|
|
2232
2261
|
sha == base
|
|
2233
2262
|
or quiet_git(root, "rev-parse", "--verify", "-q", f"{commit}^2") == sha
|
data/lib/bitfab/replay.rb
CHANGED
|
@@ -143,11 +143,11 @@ module Bitfab
|
|
|
143
143
|
# Replay historical traces through a traced method and create an experiment.
|
|
144
144
|
module Replay
|
|
145
145
|
# The values Client#replay accepts for +code_change:+.
|
|
146
|
-
CODE_CHANGE_TYPES = %w[working-tree last-branch default-branch skip manual].freeze
|
|
146
|
+
CODE_CHANGE_TYPES = %w[working-tree last-branch default-branch ref skip manual].freeze
|
|
147
147
|
# The +code_change:+ choices, as named in the errors that refuse a replay.
|
|
148
148
|
CODE_CHANGE_CHOICES = '"working-tree" (uncommitted changes vs HEAD), "last-branch" (the diff against the ' \
|
|
149
|
-
'branch this one was cut from), "default-branch" (the diff against the default branch), "
|
|
150
|
-
'change), or "manual" (pass the files yourself)'
|
|
149
|
+
'branch this one was cut from), "default-branch" (the diff against the default branch), "ref" (the diff ' \
|
|
150
|
+
'against a branch or commit you name), "skip" (no code change), or "manual" (pass the files yourself)'
|
|
151
151
|
UNSET_DEFAULT = Object.new.freeze
|
|
152
152
|
OPTION_DEFAULTS = {mock: "marked"}.freeze
|
|
153
153
|
PERSISTENCE_TIMEOUT_SECONDS = 30.0
|
|
@@ -237,16 +237,22 @@ module Bitfab
|
|
|
237
237
|
# diff against the branch this one was cut from, such as the branch below
|
|
238
238
|
# it in a stack, else the default branch; "default-branch" the diff
|
|
239
239
|
# against where HEAD split from the default branch (origin/HEAD, else
|
|
240
|
-
# origin/main, origin/master, main, master); "
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
#
|
|
240
|
+
# origin/main, origin/master, main, master); "ref" the diff against where
|
|
241
|
+
# HEAD split from the branch or commit in code_change_base; "skip" no code
|
|
242
|
+
# change, such as for a baseline run; "manual" the files in
|
|
243
|
+
# code_change_files. The four git choices include uncommitted edits and
|
|
244
|
+
# untracked files, and warn and attach nothing when they find no changed
|
|
245
|
+
# files.
|
|
244
246
|
# @param code_change_description [String, nil] description of the code
|
|
245
247
|
# change, stored on the experiment. Defaults to one generated from the
|
|
246
248
|
# captured files. Not accepted with "skip".
|
|
247
249
|
# @param code_change_files [Array<Hash>, nil] the edited files when
|
|
248
250
|
# code_change is "manual", and only then, each as { path:, before:, after: }
|
|
249
251
|
# (empty string for new/deleted files).
|
|
252
|
+
# @param code_change_base [String, nil] the branch or commit to diff
|
|
253
|
+
# against when code_change is "ref", and only then, such as "dev",
|
|
254
|
+
# "release/2.3", or a commit SHA. A branch that exists only on the remote
|
|
255
|
+
# is read as origin/<name>. A name git cannot resolve raises ArgumentError.
|
|
250
256
|
# @param experiment_group_id [String, nil] optional UUID grouping multiple
|
|
251
257
|
# replay runs into a single experiment batch. The run joins that group,
|
|
252
258
|
# and an id no group has yet creates it
|
|
@@ -313,11 +319,11 @@ module Bitfab
|
|
|
313
319
|
# The experiment fields are nil for a dry run, which creates no experiment,
|
|
314
320
|
# and progress events then carry a nil :experiment_id too.
|
|
315
321
|
def run(client, receiver, method_name, trace_function_key:, limit: nil, trace_ids: nil, name: nil, notes: nil, metadata: nil,
|
|
316
|
-
concurrency: nil, max_concurrency: ReplayConcurrency::UNSET, code_change: nil, code_change_description: nil, code_change_files: nil, experiment_group_id: nil, experiment_group_name: nil,
|
|
322
|
+
concurrency: nil, max_concurrency: ReplayConcurrency::UNSET, code_change: nil, code_change_description: nil, code_change_files: nil, code_change_base: nil, experiment_group_id: nil, experiment_group_name: nil,
|
|
317
323
|
dataset_id: nil, dataset_ids: nil, grader_ids: nil, mock: "marked", attempts: ReplayConcurrency::UNSET, only_with_assertions: false, skip_assertion_judging: false, judge_assertions: nil, dry_run: false,
|
|
318
324
|
adapt_inputs: nil, mock_override: nil, db_branch: nil, on_item_start: nil, on_item_finish: nil, on_progress: nil,
|
|
319
325
|
on_experiment_start: nil, experimental_selective_replay: nil)
|
|
320
|
-
validate_code_change(code_change, code_change_description, code_change_files)
|
|
326
|
+
validate_code_change(code_change, code_change_description, code_change_files, code_change_base)
|
|
321
327
|
explicit_options = method(:run).parameters.filter_map { |type, option| [option, binding.local_variable_get(option)] if type == :key }
|
|
322
328
|
skip_assertion_judging = resolve_skip_assertion_judging(skip_assertion_judging, judge_assertions)
|
|
323
329
|
concurrency_options = ReplayConcurrency.resolve(concurrency, attempts, max_concurrency)
|
|
@@ -396,7 +402,7 @@ module Bitfab
|
|
|
396
402
|
|
|
397
403
|
include_db_branch_lease = db_branch_enabled?(db_branch) && !dry_run
|
|
398
404
|
|
|
399
|
-
code_change_description, code_change_files = resolve_code_change(code_change, code_change_description, code_change_files, name)
|
|
405
|
+
code_change_description, code_change_files = resolve_code_change(code_change, code_change_description, code_change_files, name, code_change_base)
|
|
400
406
|
|
|
401
407
|
resolved_db_branch_settings = db_branch_settings(db_branch)
|
|
402
408
|
replay_data = http_client.start_replay(
|
|
@@ -655,7 +661,7 @@ module Bitfab
|
|
|
655
661
|
settings.empty? ? nil : settings
|
|
656
662
|
end
|
|
657
663
|
|
|
658
|
-
def validate_code_change(code_change, description, files)
|
|
664
|
+
def validate_code_change(code_change, description, files, base = nil)
|
|
659
665
|
if code_change.nil?
|
|
660
666
|
raise ArgumentError, "replay needs a code_change naming the code this run tests: #{CODE_CHANGE_CHOICES}."
|
|
661
667
|
end
|
|
@@ -669,17 +675,24 @@ module Bitfab
|
|
|
669
675
|
if code_change != "manual" && !files.nil?
|
|
670
676
|
raise ArgumentError, "code_change_files only applies with code_change \"manual\" (got \"#{code_change}\")."
|
|
671
677
|
end
|
|
678
|
+
if code_change == "ref" && !(base.is_a?(String) && !base.strip.empty? && !base.strip.start_with?("-"))
|
|
679
|
+
raise ArgumentError,
|
|
680
|
+
'code_change "ref" needs code_change_base: the branch or commit to diff against, such as "dev" or a commit SHA.'
|
|
681
|
+
end
|
|
682
|
+
if code_change != "ref" && !base.nil?
|
|
683
|
+
raise ArgumentError, "code_change_base only applies with code_change \"ref\" (got \"#{code_change}\")."
|
|
684
|
+
end
|
|
672
685
|
if code_change == "skip" && !description.nil?
|
|
673
686
|
raise ArgumentError, 'code_change "skip" attaches no code change, so it cannot take a code_change_description.'
|
|
674
687
|
end
|
|
675
688
|
code_change
|
|
676
689
|
end
|
|
677
690
|
|
|
678
|
-
def resolve_code_change(code_change, description, files, label = nil)
|
|
691
|
+
def resolve_code_change(code_change, description, files, label = nil, base = nil)
|
|
679
692
|
return [nil, nil] if code_change == "skip"
|
|
680
693
|
return [description, files] if code_change == "manual"
|
|
681
694
|
|
|
682
|
-
captured = read_code_change_file || capture_code_change_from_git(Dir.pwd, code_change, label)
|
|
695
|
+
captured = read_code_change_file || capture_code_change_from_git(Dir.pwd, code_change, label, base&.strip)
|
|
683
696
|
if captured.nil? || captured[1].nil? || captured[1].empty?
|
|
684
697
|
warn "Bitfab: code_change \"#{code_change}\" found no changed files, so this replay has no code change attached."
|
|
685
698
|
return [description, nil]
|
|
@@ -713,8 +726,21 @@ module Bitfab
|
|
|
713
726
|
!git(root, ["rev-parse", "--verify", "#{ref}^{object}"]).nil?
|
|
714
727
|
end
|
|
715
728
|
|
|
716
|
-
def
|
|
729
|
+
def cc_resolve_chosen_base(root, chosen)
|
|
730
|
+
[chosen, "origin/#{chosen}"].each do |ref|
|
|
731
|
+
next unless cc_ref_exists?(root, "#{ref}^{commit}")
|
|
732
|
+
|
|
733
|
+
base = (git(root, ["merge-base", "HEAD", ref]) || "").strip
|
|
734
|
+
return base.empty? ? nil : [base, "vs #{chosen}"]
|
|
735
|
+
end
|
|
736
|
+
raise ArgumentError,
|
|
737
|
+
"code_change_base \"#{chosen}\" names no branch or commit in this repository. Pass a branch name, such as " \
|
|
738
|
+
"\"dev\", or a commit SHA; fetch it first if it only exists on the remote."
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def cc_resolve_base(root, type, chosen = nil)
|
|
717
742
|
case type
|
|
743
|
+
when "ref" then chosen ? cc_resolve_chosen_base(root, chosen) : nil
|
|
718
744
|
when "last-branch" then cc_resolve_branch_point(root)
|
|
719
745
|
when "default-branch" then cc_resolve_default_branch_point(root)
|
|
720
746
|
else cc_ref_exists?(root, "HEAD") ? ["HEAD", "uncommitted (vs HEAD)"] : nil
|
|
@@ -809,12 +835,12 @@ module Bitfab
|
|
|
809
835
|
0
|
|
810
836
|
end
|
|
811
837
|
|
|
812
|
-
def capture_code_change_from_git(cwd, type, label = nil)
|
|
838
|
+
def capture_code_change_from_git(cwd, type, label = nil, chosen = nil)
|
|
813
839
|
root = git(cwd, ["rev-parse", "--show-toplevel"])
|
|
814
840
|
return nil if root.nil? || root.strip.empty?
|
|
815
841
|
|
|
816
842
|
root = root.strip
|
|
817
|
-
resolved = cc_resolve_base(root, type)
|
|
843
|
+
resolved = cc_resolve_base(root, type, chosen)
|
|
818
844
|
return nil if resolved.nil?
|
|
819
845
|
|
|
820
846
|
entries = cc_list_changes(root, resolved[0])
|
|
@@ -849,6 +875,8 @@ module Bitfab
|
|
|
849
875
|
head = ((label && !label.strip.empty?) ? label.strip : nil) || (subject.empty? ? nil : subject) || "Working-tree change"
|
|
850
876
|
word = (files.length == 1) ? "file" : "files"
|
|
851
877
|
["#{head} (#{files.length} #{word} changed #{against})", files]
|
|
878
|
+
rescue ArgumentError
|
|
879
|
+
raise
|
|
852
880
|
rescue
|
|
853
881
|
nil
|
|
854
882
|
end
|
|
@@ -204,6 +204,7 @@ module Bitfab
|
|
|
204
204
|
end
|
|
205
205
|
|
|
206
206
|
options[:code_change] = args.fetch(:code_change)
|
|
207
|
+
options[:code_change_base] = args[:code_change_base] if args[:code_change_base]
|
|
207
208
|
if args[:code_change_file]
|
|
208
209
|
code_change = load_code_change(args[:code_change_file])
|
|
209
210
|
options[:code_change_description] = code_change.fetch("description")
|
|
@@ -337,10 +338,11 @@ module Bitfab
|
|
|
337
338
|
options.on("--max-concurrency N", Integer) do |value|
|
|
338
339
|
args[:max_concurrency] = positive_integer("--max-concurrency", value)
|
|
339
340
|
end
|
|
340
|
-
options.on("--code-change working-tree|last-branch|default-branch|skip|manual",
|
|
341
|
+
options.on("--code-change working-tree|last-branch|default-branch|ref|skip|manual",
|
|
341
342
|
"Required: the code change this run tests; working-tree is the uncommitted changes vs HEAD, " \
|
|
342
343
|
"last-branch the diff against the branch this one was cut from, default-branch the diff against the " \
|
|
343
|
-
"default branch, skip none, manual the edits in
|
|
344
|
+
"default branch, ref the diff against --code-change-base, skip none, manual the edits in " \
|
|
345
|
+
"--code-change-file.") do |value|
|
|
344
346
|
unless Replay::CODE_CHANGE_TYPES.include?(value)
|
|
345
347
|
raise ArgumentError,
|
|
346
348
|
"Unknown --code-change '#{value}'. Pass #{Replay::CODE_CHANGE_CHOICES}. " \
|
|
@@ -350,6 +352,8 @@ module Bitfab
|
|
|
350
352
|
end
|
|
351
353
|
options.on("--code-change-file PATH",
|
|
352
354
|
"With --code-change manual: a JSON file of { description, files }.") { |value| args[:code_change_file] = value }
|
|
355
|
+
options.on("--code-change-base BRANCH|COMMIT",
|
|
356
|
+
"With --code-change ref: the branch or commit to diff against.") { |value| args[:code_change_base] = value }
|
|
353
357
|
options.on("--experiment-group-id UUID",
|
|
354
358
|
"Add this run to an experiment group. A UUID no group has yet creates the group.") { |value| args[:experiment_group_id] = value }
|
|
355
359
|
options.on("--experiment-group-name NAME",
|
|
@@ -390,12 +394,17 @@ module Bitfab
|
|
|
390
394
|
def require_code_change(args)
|
|
391
395
|
if args[:code_change].nil?
|
|
392
396
|
raise ArgumentError,
|
|
393
|
-
"--code-change is required: #{Replay::CODE_CHANGE_CHOICES}. \"
|
|
397
|
+
"--code-change is required: #{Replay::CODE_CHANGE_CHOICES}. \"ref\" takes the branch or commit from " \
|
|
398
|
+
"--code-change-base, and \"manual\" takes the edits from --code-change-file PATH."
|
|
394
399
|
end
|
|
395
|
-
|
|
400
|
+
unless (args[:code_change] == "manual") == !args[:code_change_file].nil?
|
|
401
|
+
raise ArgumentError,
|
|
402
|
+
"--code-change-file goes with --code-change manual, and --code-change manual needs --code-change-file PATH."
|
|
403
|
+
end
|
|
404
|
+
return args if (args[:code_change] == "ref") == !args[:code_change_base].nil?
|
|
396
405
|
|
|
397
406
|
raise ArgumentError,
|
|
398
|
-
"--code-change-
|
|
407
|
+
"--code-change-base goes with --code-change ref, and --code-change ref needs --code-change-base BRANCH|COMMIT."
|
|
399
408
|
end
|
|
400
409
|
|
|
401
410
|
def registry_dataset_ids(options)
|
data/lib/bitfab/version.rb
CHANGED