diff --git a/lib/apps/fabro-cli/src/args.rs b/lib/apps/fabro-cli/src/args.rs index d9b487670..f6130530a 100644 --- a/lib/apps/fabro-cli/src/args.rs +++ b/lib/apps/fabro-cli/src/args.rs @@ -277,10 +277,6 @@ pub(crate) struct RunArgs { /// Run the workflow in the background and print the run ID #[arg(short = 'd', long)] pub(crate) detach: bool, - - /// Pre-generated run ID (used internally by --detach) - #[arg(long, hide = true)] - pub(crate) run_id: Option, } #[derive(Args)] diff --git a/lib/apps/fabro-cli/src/commands/run/create.rs b/lib/apps/fabro-cli/src/commands/run/create.rs index 159160d7e..3268d5b3b 100644 --- a/lib/apps/fabro-cli/src/commands/run/create.rs +++ b/lib/apps/fabro-cli/src/commands/run/create.rs @@ -33,13 +33,6 @@ pub(crate) async fn create_run( .ok_or_else(|| anyhow::anyhow!("--workflow is required"))?; let cli_args_config = run_args_overrides(args)?; let cwd = ctx.cwd().to_path_buf(); - let run_id = args - .run_id - .as_deref() - .map(str::parse::) - .transpose() - .context("invalid run ID")?; - let mut built = build_run_manifest(ManifestBuildInput { workflow: workflow_path.clone(), cwd, @@ -47,7 +40,7 @@ pub(crate) async fn create_run( cli_overrides: cli_args_config.cli, input_overrides: cli_args_config.input_overrides, args: run_manifest_args(args), - run_id, + run_id: None, environment_defaults: fabro_environment::seeded_catalog_layer(), user_settings_path: Some(active_settings_path(None)), })?; diff --git a/lib/apps/fabro-cli/tests/it/cmd/attach.rs b/lib/apps/fabro-cli/tests/it/cmd/attach.rs index 420bf7697..779157cdc 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/attach.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/attach.rs @@ -15,9 +15,10 @@ use fabro_test::{ use serde_json::Value; use super::support::{ - output_stdout, resolve_run, server_endpoint, wait_for_status, write_gated_workflow, + created_run_id, output_stdout, resolve_run, server_endpoint, wait_for_status, + write_gated_workflow, }; -use crate::support::{run_output_filters, unique_run_id}; +use crate::support::run_output_filters; const SHARED_DAEMON_TIMEOUT: Duration = Duration::from_secs(30); @@ -366,22 +367,20 @@ fn attach_reprompts_invalid_choice_then_accepts_valid_answer() { fn attach_replays_completed_detached_run() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let run = context .command() .args([ "run", "--dry-run", "--auto-approve", "--detach", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(run.get_output()); context .command() diff --git a/lib/apps/fabro-cli/tests/it/cmd/config.rs b/lib/apps/fabro-cli/tests/it/cmd/config.rs index ff36e155a..daa58168b 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/config.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/config.rs @@ -9,8 +9,7 @@ use fabro_test::{fabro_snapshot, test_context}; use httpmock::MockServer; use predicates::prelude::*; -use super::support::run_state; -use crate::support::unique_run_id; +use super::support::{created_run_id, run_state}; #[test] fn old_config_show_command_is_rejected() { @@ -310,10 +309,9 @@ fn create_explicit_workflow_path_uses_project_config_relative_to_workflow() { context.ensure_home_server_auth_methods(); let cwd = tempfile::tempdir().unwrap(); let workflow = project.path().join("workflow.toml"); - let run_id = unique_run_id(); // Remove FABRO_STORAGE_DIR so the CLI uses storage_dir from settings.toml - context + let create = context .command() .env_remove("FABRO_STORAGE_DIR") .current_dir(cwd.path()) @@ -322,12 +320,11 @@ fn create_explicit_workflow_path_uses_project_config_relative_to_workflow() { "--dry-run", "--model", "gpt-5.4-pro", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let runs_dir = storage_dir.join("scratch"); let run_dir = std::fs::read_dir(&runs_dir) diff --git a/lib/apps/fabro-cli/tests/it/cmd/create.rs b/lib/apps/fabro-cli/tests/it/cmd/create.rs index 488f6a1f5..48be32af7 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/create.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/create.rs @@ -4,8 +4,8 @@ use insta::assert_snapshot; use serde_json::json; use super::support::{ - fixture, output_stdout, remote_run_summary_json, resolve_run, run_count_for_test_case, - run_state, + created_run_id, fixture, output_stdout, remote_run_summary_json, resolve_run, + run_count_for_test_case, run_state, }; use crate::support::unique_run_id; @@ -271,7 +271,6 @@ fn create_cli_server_target_overrides_configured_server_target() { fn create_persists_directory_workflow_slug_and_cached_graph() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("sluggy/workflow.fabro"); context.write_temp( @@ -285,18 +284,17 @@ digraph BarBaz { ", ); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let run_dir = context.find_run_dir(&run_id); let state = run_state(&run_dir); @@ -328,7 +326,6 @@ digraph BarBaz { fn create_persists_file_stem_slug_for_standalone_file() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("alpha.fabro"); context.write_temp( @@ -342,18 +339,17 @@ digraph FooWorkflow { ", ); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let run_dir = context.find_run_dir(&run_id); let state = run_state(&run_dir); diff --git a/lib/apps/fabro-cli/tests/it/cmd/dump.rs b/lib/apps/fabro-cli/tests/it/cmd/dump.rs index 08b7712c2..cd8aff482 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/dump.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/dump.rs @@ -11,10 +11,10 @@ use fabro_test::{fabro_snapshot, test_context}; use insta::assert_snapshot; use super::support::{ - local_dev_token, server_target, setup_completed_dry_run, setup_seeded_completed_dry_run, - setup_seeded_created_dry_run, + local_dev_token, run_state, server_target, setup_completed_dry_run, + setup_seeded_completed_dry_run, setup_seeded_created_dry_run, }; -use crate::support::{LightweightCli, seed_dev_token_auth, unique_run_id}; +use crate::support::{LightweightCli, seed_dev_token_auth}; #[test] fn help() { @@ -99,11 +99,10 @@ fn dump_exports_large_command_output_backed_by_blob_refs() { ) .unwrap(); - let run_id = unique_run_id(); let mut run_cmd = context.run_cmd(); run_cmd.current_dir(&context.temp_dir); run_cmd.timeout(Duration::from_secs(30)); - run_cmd.args(["--run-id", run_id.as_str(), "--environment", "local"]); + run_cmd.args(["--environment", "local"]); run_cmd.arg(&workflow); let run_output = run_cmd.output().expect("command should execute"); assert!( @@ -112,6 +111,7 @@ fn dump_exports_large_command_output_backed_by_blob_refs() { String::from_utf8_lossy(&run_output.stdout), String::from_utf8_lossy(&run_output.stderr) ); + let run_id = run_state(&context.single_run_dir()).spec.run_id.to_string(); let mut inspect_cmd = context.command(); inspect_cmd.args(["inspect", "--json", &run_id]); @@ -186,17 +186,10 @@ include = ["assets/**"] ) .unwrap(); - let run_id = unique_run_id(); let mut run_cmd = context.run_cmd(); run_cmd.current_dir(&workspace_dir); run_cmd.timeout(Duration::from_secs(30)); - run_cmd.args([ - "--run-id", - run_id.as_str(), - "--environment", - "local", - "run.toml", - ]); + run_cmd.args(["--environment", "local", "run.toml"]); let run_output = run_cmd.output().expect("command should execute"); assert!( run_output.status.success(), @@ -204,6 +197,7 @@ include = ["assets/**"] String::from_utf8_lossy(&run_output.stdout), String::from_utf8_lossy(&run_output.stderr) ); + let run_id = run_state(&context.single_run_dir()).spec.run_id.to_string(); let mut inspect_cmd = context.command(); inspect_cmd.args(["inspect", "--json", &run_id]); diff --git a/lib/apps/fabro-cli/tests/it/cmd/run.rs b/lib/apps/fabro-cli/tests/it/cmd/run.rs index fe5d6c6cc..5f8ed902b 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/run.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/run.rs @@ -9,7 +9,9 @@ use fabro_vault::{SecretType, Vault}; use httpmock::MockServer; use serde_json::Value; -use super::support::{output_stderr, remote_run_summary_json, wait_for_event_names}; +use super::support::{ + created_run_id, output_stderr, remote_run_summary_json, run_state, wait_for_event_names, +}; use crate::support::{run_output_filters, run_projection_json, unique_run_id}; fn run_status_response(run_id: &str, status: &str) -> serde_json::Value { @@ -357,7 +359,6 @@ fn run_uses_vault_credentials_for_worker_execution() { ), ); context.isolated_server(); - let run_id = unique_run_id(); seed_anthropic_vault(&context.storage_dir); let llm_mock = llm_server.mock(|when, then| { @@ -410,8 +411,6 @@ digraph VaultWorkerLlm { .env_remove("OPENAI_BASE_URL") .env_remove("GEMINI_API_KEY") .args([ - "--run-id", - run_id.as_str(), "--auto-approve", "--environment", "local", @@ -436,7 +435,7 @@ digraph VaultWorkerLlm { ); llm_mock.assert(); - wait_for_event_names(&context.find_run_dir(&run_id), &["run.completed"]); + wait_for_event_names(&context.single_run_dir(), &["run.completed"]); } #[test] @@ -731,7 +730,6 @@ fn foreground_run_rejects_invalid_workflow_before_creating_remote_run() { #[test] fn local_foreground_run_prints_artifact_paths_from_server_artifact_list() { let context = test_context!(); - let run_id = unique_run_id(); let workspace_dir = context.temp_dir.join("artifact-summary"); context.write_temp( "artifact-summary/workflow.fabro", @@ -767,8 +765,6 @@ include = ["assets/**"] .current_dir(&workspace_dir) .env("OPENAI_API_KEY", "test") .args([ - "--run-id", - run_id.as_str(), "--auto-approve", "--environment", "local", @@ -890,7 +886,6 @@ fn dry_run_rejects_goal_and_goal_file_together() { fn dry_run_persists_event_history_in_store() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); context @@ -901,14 +896,13 @@ fn dry_run_persists_event_history_in_store() { "--auto-approve", "--environment", "local", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); - let run_dir = context.find_run_dir(&run_id); + let run_dir = context.single_run_dir(); + let run_id = run_state(&run_dir).spec.run_id.to_string(); wait_for_event_names(&run_dir, &["run.completed", "sandbox.stop.completed"]); let output = context .command() @@ -991,13 +985,13 @@ fn dry_run_persists_event_history_in_store() { } #[test] -fn run_id_passthrough_uses_provided_ulid() { +fn run_rejects_removed_run_id_flag() { let context = test_context!(); context.ensure_home_server_auth_methods(); let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let output = context .command() .args([ "run", @@ -1008,9 +1002,12 @@ fn run_id_passthrough_uses_provided_ulid() { workflow.to_str().unwrap(), ]) .assert() - .success(); - - context.find_run_dir(&run_id); + .failure(); + let stderr = String::from_utf8_lossy(&output.get_output().stderr); + assert!( + stderr.contains("unexpected argument '--run-id'"), + "{stderr}" + ); } #[test] @@ -1100,21 +1097,19 @@ fn detach_prints_ulid_and_exits() { #[test] fn detach_creates_run_dir_with_detach_log() { let context = test_context!(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let run = context .run_cmd() .args([ "--detach", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(run.get_output()); let run_dir = context.find_run_dir(&run_id); fabro_json_snapshot!( diff --git a/lib/apps/fabro-cli/tests/it/cmd/runner.rs b/lib/apps/fabro-cli/tests/it/cmd/runner.rs index 1d356f20f..ccb4bf4c3 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/runner.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/runner.rs @@ -20,8 +20,9 @@ use fabro_types::{EventBody, FailureReason, RunEvent, StageId}; use httpmock::MockServer; use super::support::{ - command_log_text, find_run_dir, local_dev_token, output_stderr, run_events, run_state, - server_endpoint, server_target, wait_for_event_names, wait_for_status, write_gated_workflow, + command_log_text, created_run_id, find_run_dir, local_dev_token, output_stderr, run_events, + run_state, server_endpoint, server_target, wait_for_event_names, wait_for_status, + write_gated_workflow, }; use crate::support::{issue_test_worker_jwt, seed_dev_token_auth, unique_run_id}; @@ -243,7 +244,6 @@ fn worker_requires_fabro_worker_token_env() { #[test] fn runner_uses_cached_graph_after_source_deleted() { let context = auth_context(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("workflow.fabro"); context.write_temp( @@ -257,18 +257,17 @@ digraph CachedGraph { ", ); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let run_dir = context.find_run_dir(&run_id); let server = server_target(&context.storage_dir); @@ -298,7 +297,6 @@ digraph CachedGraph { #[test] fn runner_local_dry_runs_ignore_github_app_configuration() { let context = auth_context(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("workflow.fabro"); context.write_home( @@ -324,18 +322,17 @@ digraph GitHubApp { ", ); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let run_dir = context.find_run_dir(&run_id); context.write_home(".fabro/settings.toml", "_version = 1\n"); @@ -361,7 +358,6 @@ digraph GitHubApp { #[test] fn runner_runs_without_run_json_when_run_id_is_explicit() { let context = auth_context(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("workflow.fabro"); context.write_temp( @@ -375,18 +371,17 @@ digraph DetachedStoreOnly { ", ); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let run_dir = context.find_run_dir(&run_id); let server = server_target(&context.storage_dir); @@ -469,7 +464,6 @@ methods = ["dev-token"] ) .expect("writing leak-probe workflow"); - let run_id = unique_run_id(); let dev_token = local_dev_token(&storage_dir).expect("managed server should have a dev token"); let target = ServerTarget::unix_socket_path(&socket_path).expect("socket path should parse"); seed_dev_token_auth(&context.home_dir, &target, &dev_token); @@ -478,8 +472,6 @@ methods = ["dev-token"] .args([ "--server", socket_path.to_str().expect("socket path should be UTF-8"), - "--run-id", - run_id.as_str(), "--detach", "--auto-approve", "--environment", @@ -496,6 +488,7 @@ methods = ["dev-token"] String::from_utf8_lossy(&run_output.stdout), String::from_utf8_lossy(&run_output.stderr) ); + let run_id = created_run_id(&run_output); let run_dir = find_run_dir(&storage_dir, &run_id).expect("leak-probe run dir should exist"); wait_for_status(&run_dir, &["succeeded"]); @@ -704,7 +697,6 @@ fn runner_reports_malformed_run_state_without_prefetching_events() { #[test] fn detached_run_answers_pending_question_without_interview_scratch_files() { let context = auth_context(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("human-gate.fabro"); context.write_temp( @@ -731,8 +723,6 @@ fn detached_run_answers_pending_question_without_interview_scratch_files() { .args([ "run", "--detach", - "--run-id", - run_id.as_str(), "--environment", "local", workflow_path.to_str().unwrap(), @@ -746,6 +736,7 @@ fn detached_run_answers_pending_question_without_interview_scratch_files() { String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); + let run_id = created_run_id(&output); let run_dir = context.find_run_dir(&run_id); let runtime = tokio::runtime::Runtime::new().expect("test runtime should build"); @@ -796,7 +787,6 @@ fn detached_run_answers_pending_question_without_interview_scratch_files() { #[test] fn detached_run_cancel_reaches_worker_over_control_websocket() { let context = auth_context(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("cancel-over-control-websocket.fabro"); let _gate = write_gated_workflow( &workflow_path, @@ -809,8 +799,6 @@ fn detached_run_cancel_reaches_worker_over_control_websocket() { .args([ "run", "--detach", - "--run-id", - run_id.as_str(), "--environment", "local", workflow_path.to_str().unwrap(), @@ -824,6 +812,7 @@ fn detached_run_cancel_reaches_worker_over_control_websocket() { String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); + let run_id = created_run_id(&output); let run_dir = context.find_run_dir(&run_id); wait_for_event_names(&run_dir, &["run.running"]); @@ -857,23 +846,21 @@ fn detached_run_cancel_reaches_worker_over_control_websocket() { #[test] fn worker_exits_after_sigterm_cancel_even_when_stdin_stays_open() { let context = auth_context(); - let run_id = unique_run_id(); let workflow_path = context.temp_dir.join("cancel-gated.fabro"); let _gate = write_gated_workflow(&workflow_path, "cancel_gated", "Wait for cancellation"); - context + let create = context .command() .args([ "create", "--auto-approve", "--environment", "local", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); let run_dir = context.find_run_dir(&run_id); let server = server_target(&context.storage_dir); diff --git a/lib/apps/fabro-cli/tests/it/cmd/start.rs b/lib/apps/fabro-cli/tests/it/cmd/start.rs index 950a708b9..b2e587a60 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/start.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/start.rs @@ -1,7 +1,8 @@ use fabro_test::{fabro_json_snapshot, fabro_snapshot, test_context}; -use super::support::{output_stdout, resolve_run, wait_for_status, write_gated_workflow}; -use crate::support::unique_run_id; +use super::support::{ + created_run_id, output_stdout, resolve_run, wait_for_status, write_gated_workflow, +}; const SHARED_DAEMON_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); @@ -37,21 +38,19 @@ fn help() { fn start_by_run_id_starts_created_run() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); context .command() @@ -89,21 +88,19 @@ fn start_by_run_id_starts_created_run() { fn start_by_run_id_starts_created_run_without_run_json_or_status_json() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); context .command() diff --git a/lib/apps/fabro-cli/tests/it/cmd/support.rs b/lib/apps/fabro-cli/tests/it/cmd/support.rs index b3c133695..0c838f0f7 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/support.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/support.rs @@ -105,6 +105,14 @@ pub(crate) fn output_stdout(output: &Output) -> String { stdout(output) } +pub(crate) fn created_run_id(output: &Output) -> String { + stdout(output) + .trim() + .parse::() + .expect("create command should print a run ID") + .to_string() +} + pub(crate) fn read_text(path: &Path) -> String { std::fs::read_to_string(path) .unwrap_or_else(|err| panic!("failed to read {}: {err}", path.display())) @@ -260,18 +268,10 @@ pub(crate) fn setup_seeded_created_dry_run(context: &TestContext) -> RunSetup { } fn run_completed_dry_run(context: &TestContext, workflow: &Path) -> RunSetup { - let run_id = unique_run_id(); let mut cmd = context.run_cmd(); cmd.current_dir(&context.temp_dir); cmd.timeout(command_timeout()); - cmd.args([ - "--run-id", - run_id.as_str(), - "--dry-run", - "--auto-approve", - "--environment", - "local", - ]); + cmd.args(["--dry-run", "--auto-approve", "--environment", "local"]); cmd.arg(workflow); let output = cmd.output().expect("command should execute"); if !output.status.success() { @@ -282,10 +282,7 @@ fn run_completed_dry_run(context: &TestContext, workflow: &Path) -> RunSetup { stderr(&output) ); } - let run_setup = RunSetup { - run_dir: context.find_run_dir(&run_id), - run_id, - }; + let run_setup = single_run_setup(context); wait_for_event_names(&run_setup.run_dir, &[ "run.completed", "sandbox.stop.completed", @@ -322,13 +319,10 @@ fn fast_simple_workflow(context: &TestContext) -> PathBuf { )] pub(crate) fn setup_detached_dry_run(context: &TestContext) -> RunSetup { let workflow = context.install_fixture("simple.fabro"); - let run_id = unique_run_id(); let mut cmd = context.run_cmd(); cmd.current_dir(&context.temp_dir); cmd.timeout(command_timeout()); cmd.args([ - "--run-id", - run_id.as_str(), "--detach", "--dry-run", "--auto-approve", @@ -345,7 +339,7 @@ pub(crate) fn setup_detached_dry_run(context: &TestContext) -> RunSetup { stderr(&output) ); } - assert_eq!(stdout(&output).trim(), run_id); + let run_id = created_run_id(&output); let run = resolve_run(context, &run_id); let deadline = Instant::now() + command_timeout(); while run_events(&run.run_dir).is_empty() { @@ -427,14 +421,11 @@ id = "local" } fn run_local_workflow(context: &TestContext, workspace_dir: &Path, workflow: &str) -> RunSetup { - let run_id = unique_run_id(); let mut cmd = context.run_cmd(); cmd.current_dir(workspace_dir); cmd.timeout(command_timeout()); cmd.env("OPENAI_API_KEY", "test"); cmd.args([ - "--run-id", - run_id.as_str(), "--auto-approve", "--environment", "local", @@ -451,10 +442,7 @@ fn run_local_workflow(context: &TestContext, workspace_dir: &Path, workflow: &st ); } - RunSetup { - run_dir: context.find_run_dir(&run_id), - run_id, - } + single_run_setup(context) } pub(crate) fn add_project_workflow( @@ -652,6 +640,12 @@ fn infer_run_id(run_dir: &Path) -> String { .expect("run directory name should contain run id suffix") } +fn single_run_setup(context: &TestContext) -> RunSetup { + let run_dir = context.single_run_dir(); + let run_id = infer_run_id(&run_dir); + RunSetup { run_id, run_dir } +} + fn block_on(future: impl std::future::Future) -> T { tokio::runtime::Builder::new_current_thread() .enable_all() diff --git a/lib/apps/fabro-cli/tests/it/cmd/worker_auth.rs b/lib/apps/fabro-cli/tests/it/cmd/worker_auth.rs index 5e66a9e82..1cfcbff72 100644 --- a/lib/apps/fabro-cli/tests/it/cmd/worker_auth.rs +++ b/lib/apps/fabro-cli/tests/it/cmd/worker_auth.rs @@ -23,7 +23,7 @@ use fabro_store::EventEnvelope; use fabro_test::{apply_test_isolation, expect_reqwest_json, isolated_storage_dir, test_context}; use fabro_vault::{SecretType, Vault}; -use super::support::{find_run_dir, output_stderr, output_stdout}; +use super::support::{created_run_id, find_run_dir, output_stderr}; use crate::support::{ TEST_SESSION_SECRET, issue_test_github_jwt, issue_test_worker_jwt, parse_event_envelopes, unique_run_id, @@ -299,14 +299,11 @@ async fn github_only_server_dispatched_worker_succeeds_without_worker_auth_store let workflow = context.temp_dir.join("worker-auth.fabro"); write_probe_workflow(&workflow); - let run_id = unique_run_id(); let output = context .run_cmd() .args([ "--server", &target, - "--run-id", - &run_id, "--detach", "--dry-run", "--auto-approve", @@ -323,7 +320,7 @@ async fn github_only_server_dispatched_worker_succeeds_without_worker_auth_store String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); - assert_eq!(output_stdout(&output).trim(), run_id); + let run_id = created_run_id(&output); let _run_dir = wait_for_run_dir(&server.storage_dir, &run_id); let events = wait_for_completed_events(&server.api_base_url, &run_id, &access_token).await; @@ -356,14 +353,11 @@ fn runner_rejects_bogus_worker_token_against_github_only_server() { let workflow = context.temp_dir.join("worker-auth-negative.fabro"); write_probe_workflow(&workflow); - let run_id = unique_run_id(); let create_output = context .create_cmd() .args([ "--server", &target, - "--run-id", - &run_id, "--dry-run", "--auto-approve", "--environment", @@ -379,7 +373,7 @@ fn runner_rejects_bogus_worker_token_against_github_only_server() { String::from_utf8_lossy(&create_output.stdout), String::from_utf8_lossy(&create_output.stderr) ); - assert_eq!(output_stdout(&create_output).trim(), run_id); + let run_id = created_run_id(&create_output); let run_dir = wait_for_run_dir(&server.storage_dir, &run_id); let worker_root = tempfile::tempdir_in("/tmp").unwrap(); diff --git a/lib/apps/fabro-cli/tests/it/scenario/lifecycle.rs b/lib/apps/fabro-cli/tests/it/scenario/lifecycle.rs index d7ef1d3b2..9f8e7b7a7 100644 --- a/lib/apps/fabro-cli/tests/it/scenario/lifecycle.rs +++ b/lib/apps/fabro-cli/tests/it/scenario/lifecycle.rs @@ -11,7 +11,7 @@ use fabro_test::{fabro_json_snapshot, test_context}; use serde_json::Value; use super::{fixture, run_state, timeout_for}; -use crate::support::unique_run_id; +use crate::cmd::support::created_run_id; #[fabro_macros::e2e_test()] fn local_run_lifecycle() { @@ -116,21 +116,19 @@ fn local_run_lifecycle() { fn dry_run_create_start_attach_works_with_default_run_lookup() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); context .command() @@ -181,22 +179,20 @@ fn dry_run_create_start_attach_works_with_default_run_lookup() { fn dry_run_detach_attach_works_with_default_run_lookup() { let context = test_context!(); context.ensure_home_server_auth_methods(); - let run_id = unique_run_id(); let workflow = context.install_fixture("simple.fabro"); - context + let run = context .command() .args([ "run", "--detach", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(run.get_output()); context .command() @@ -229,7 +225,6 @@ fn completed_run_can_be_attached_by_workflow_slug() { let project = tempfile::tempdir().unwrap(); let workflow_dir = project.path().join("workflows").join("sluggy"); let workflow_path = workflow_dir.join("workflow.fabro"); - let run_id = unique_run_id(); std::fs::create_dir_all(&workflow_dir).unwrap(); std::fs::write( @@ -244,19 +239,18 @@ digraph BarBaz { ) .unwrap(); - context + let create = context .command() .current_dir(project.path()) .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); context .command() .current_dir(project.path()) @@ -301,7 +295,6 @@ fn completed_run_can_be_attached_by_file_stem() { context.ensure_home_server_auth_methods(); let workflow_dir = tempfile::tempdir().unwrap(); let workflow_path = workflow_dir.path().join("alpha.fabro"); - let run_id = unique_run_id(); std::fs::write( &workflow_path, @@ -315,18 +308,17 @@ digraph FooWorkflow { ) .unwrap(); - context + let create = context .command() .args([ "create", "--dry-run", "--auto-approve", - "--run-id", - run_id.as_str(), workflow_path.to_str().unwrap(), ]) .assert() .success(); + let run_id = created_run_id(create.get_output()); context .command() .args(["start", "alpha"])