feat(tests): migrate fabro-cli fixtures and repo fabro.toml to v2

Stage 4 consumer migration: rewrite test fixtures across fabro-cli
integration tests and the repo's own fabro.toml + workflow.toml files
to use the v2 namespaced schema.

Fixtures migrated:
- repo fabro.toml: [fabro] root → [project] directory, [pull_request]
  → [run.pull_request], [sandbox] → [run.sandbox], daytona labels
  and snapshot moved under [run.sandbox.daytona], [[hooks]] →
  [[run.hooks]] with id, integer memory/disk → '8GB'/'20GB' Size
  values
- fabro/workflows/{implement-issue,implement-plan,gh-triage,smoke}/
  workflow.toml: version → _version, [github] →
  [server.integrations.github]
- fabro-cli integration tests: config.rs (settings/external fixtures),
  repo.rs, repo_init.rs, runner.rs, run.rs, store_dump.rs,
  workflow.rs, workflow_create.rs, support.rs
- fabro-server run_manifest.rs: prepare_manifest test constructs v2
  manifest configs (run.prepare.steps + server.integrations.github)
  and updated assertion to reflect v2 whole-list replacement of
  run.prepare.steps across layers

Validate command tests all green; ~10 tests remain that need targeted
fixes for specific behaviors that shifted between schemas.
This commit is contained in:
Bryan Helmkamp 2026-04-09 09:57:30 -04:00
parent eb077ed3a2
commit 4a48305fd2
15 changed files with 152 additions and 110 deletions

View file

@ -1,29 +1,26 @@
version = 1
_version = 1
[fabro]
root = "fabro/"
[project]
directory = "fabro/"
[features]
retros = false
[pull_request]
[run.pull_request]
enabled = true
draft = false
[sandbox]
[run.sandbox]
provider = "daytona"
[sandbox.daytona]
[run.sandbox.daytona]
auto_stop_interval = 30
[sandbox.daytona.labels]
[run.sandbox.daytona.labels]
repo = "fabro-sh/fabro"
[sandbox.daytona.snapshot]
[run.sandbox.daytona.snapshot]
name = "fabro-v6"
cpu = 4
memory = 8
disk = 20
memory = "8GB"
disk = "20GB"
dockerfile = """
FROM ubuntu:24.04
@ -52,9 +49,10 @@ ENV PATH="/root/.bun/bin:${PATH}"
WORKDIR /root
"""
[[hooks]]
[[run.hooks]]
id = "cargo-fmt"
name = "cargo-fmt"
event = "post_tool_use"
matcher = "write_file|edit_file|apply_patch"
command = "cargo fmt"
script = "cargo fmt"
blocking = true

View file

@ -1,4 +1,7 @@
version = 1
_version = 1
[github]
permissions = { pull_requests = "read", issues = "read" }
[server.integrations.github]
[server.integrations.github.permissions]
pull_requests = "read"
issues = "read"

View file

@ -1,4 +1,7 @@
version = 1
_version = 1
[github]
permissions = { issues = "read", pull_requests = "write" }
[server.integrations.github]
[server.integrations.github.permissions]
issues = "read"
pull_requests = "write"

View file

@ -1 +1 @@
version = 1
_version = 1

View file

@ -1 +1 @@
version = 1
_version = 1

View file

@ -562,10 +562,10 @@ mod tests {
std::fs::create_dir_all(workflow_dir.join("prompts")).unwrap();
std::fs::create_dir_all(workflow_dir.join("imports")).unwrap();
std::fs::create_dir_all(&child_dir).unwrap();
std::fs::write(project.join("fabro.toml"), "version = 1\n").unwrap();
std::fs::write(project.join("fabro.toml"), "_version = 1\n").unwrap();
std::fs::write(
workflow_dir.join("workflow.toml"),
"version = 1\ngraph = \"workflow.fabro\"\n",
"_version = 1\n\n[workflow]\ngraph = \"workflow.fabro\"\n",
)
.unwrap();
std::fs::write(

View file

@ -82,37 +82,44 @@ fn setup_settings_fixture(context: &fabro_test::TestContext) -> tempfile::TempDi
context.write_home(
".fabro/settings.toml",
r#"
verbose = true
_version = 1
[llm]
model = "cli-model"
[cli.output]
verbosity = "verbose"
[run.model]
name = "cli-model"
provider = "openai"
[vars]
[run.inputs]
cli_only = "1"
shared = "cli"
[checkpoint]
[run.checkpoint]
exclude_globs = ["cli-only", "shared"]
[[hooks]]
[[run.hooks]]
id = "shared"
name = "shared"
event = "run_start"
command = "echo cli"
script = "echo cli"
[mcp_servers.shared]
[run.agent.mcps.shared]
type = "stdio"
command = ["echo", "cli"]
[sandbox]
[run.sandbox]
provider = "daytona"
[sandbox.daytona]
labels = { cli_only = "1", shared = "cli" }
[sandbox.env]
[run.sandbox.env]
CLI_ONLY = "1"
SHARED = "cli"
[run.sandbox.daytona]
[run.sandbox.daytona.labels]
cli_only = "1"
shared = "cli"
"#,
);
@ -120,22 +127,23 @@ SHARED = "cli"
std::fs::write(
project.path().join("fabro.toml"),
r#"
version = 1
_version = 1
[fabro]
root = "fabro"
[project]
directory = "fabro"
[llm]
model = "project-model"
[run.model]
name = "project-model"
[vars]
[run.inputs]
project_only = "1"
shared = "project"
[[hooks]]
[[run.hooks]]
id = "project"
name = "project"
event = "run_complete"
command = "echo project"
script = "echo project"
"#,
)
.unwrap();
@ -145,44 +153,51 @@ command = "echo project"
std::fs::write(
workflow_dir.join("workflow.toml"),
r#"
version = 1
_version = 1
[run]
goal = "demo goal"
[llm]
model = "run-model"
[run.model]
name = "run-model"
provider = "anthropic"
[vars]
[run.inputs]
run_only = "1"
shared = "run"
[checkpoint]
[run.checkpoint]
exclude_globs = ["run-only", "shared"]
[[hooks]]
[[run.hooks]]
id = "shared"
name = "shared"
event = "run_start"
command = "echo run"
script = "echo run"
[[hooks]]
[[run.hooks]]
id = "run-only"
name = "run-only"
event = "run_complete"
command = "echo run-only"
script = "echo run-only"
[mcp_servers.shared]
[run.agent.mcps.shared]
type = "stdio"
command = ["echo", "run"]
[mcp_servers.run_only]
[run.agent.mcps.run_only]
type = "stdio"
command = ["echo", "run-only"]
[sandbox.daytona]
labels = { run_only = "1", shared = "run" }
[sandbox.env]
[run.sandbox.env]
RUN_ONLY = "1"
SHARED = "run"
[run.sandbox.daytona]
[run.sandbox.daytona.labels]
run_only = "1"
shared = "run"
"#,
)
.unwrap();
@ -208,11 +223,16 @@ fn setup_external_workflow_fixture(
".fabro/settings.toml",
format!(
r#"
storage_dir = "{}"
auto_approve = true
_version = 1
[setup]
commands = ["cli-setup"]
[server.storage]
root = "{}"
[run.execution]
approval = "auto"
[[run.prepare.steps]]
script = "cli-setup"
"#,
storage_dir.display()
),
@ -222,12 +242,12 @@ commands = ["cli-setup"]
std::fs::write(
project.path().join("fabro.toml"),
r#"
version = 1
_version = 1
[setup]
commands = ["project-setup"]
[[run.prepare.steps]]
script = "project-setup"
[sandbox]
[run.sandbox]
preserve = true
"#,
)
@ -248,15 +268,19 @@ digraph Test {
std::fs::write(
project.path().join("workflow.toml"),
r#"
version = 1
goal = "Ship it"
_version = 1
[workflow]
graph = "workflow.fabro"
[llm]
model = "claude-sonnet-4-6"
[run]
goal = "Ship it"
[setup]
commands = ["workflow-setup"]
[run.model]
name = "claude-sonnet-4-6"
[[run.prepare.steps]]
script = "workflow-setup"
"#,
)
.unwrap();

View file

@ -2,9 +2,9 @@ use fabro_test::{fabro_snapshot, test_context};
fn init_fabro_project(context: &fabro_test::TestContext) {
context
.write_temp("fabro.toml", "version = 1\n")
.write_temp("fabro.toml", "_version = 1\n")
.write_temp("fabro/workflows/hello/workflow.fabro", "digraph {}")
.write_temp("fabro/workflows/hello/workflow.toml", "version = 1\n");
.write_temp("fabro/workflows/hello/workflow.toml", "_version = 1\n");
}
#[test]

View file

@ -58,16 +58,13 @@ fn repo_init_creates_fabro_toml_and_hello_workflow() {
# Fabro project configuration
# https://docs.fabro.computer/getting-started/quick-start
version = 1
_version = 1
[fabro]
root = "fabro/"
# Disable retrospective analysis after workflow runs:
# retro = false
[project]
directory = "fabro/"
# Auto-create pull requests on successful workflow runs.
[pull_request]
[run.pull_request]
enabled = true
draft = true
# auto_merge = true
@ -94,10 +91,12 @@ fn repo_init_creates_fabro_toml_and_hello_workflow() {
std::fs::read_to_string(context.temp_dir.join("fabro/workflows/hello/workflow.toml"))
.unwrap(),
@r###"
version = 1
_version = 1
[workflow]
graph = "workflow.fabro"
[sandbox]
[run.sandbox]
provider = "local"
"###
);
@ -107,7 +106,7 @@ fn repo_init_creates_fabro_toml_and_hello_workflow() {
fn repo_init_rejects_already_initialized_repo() {
let context = test_context!();
context.git_init();
std::fs::write(context.temp_dir.join("fabro.toml"), "version = 1\n").unwrap();
std::fs::write(context.temp_dir.join("fabro.toml"), "_version = 1\n").unwrap();
let mut cmd = context.command();
cmd.args(["repo", "init"]);

View file

@ -454,18 +454,22 @@ fn local_foreground_run_prints_artifact_paths_from_server_artifact_list() {
);
context.write_temp(
"artifact-summary/run.toml",
r#"version = 1
r#"_version = 1
[workflow]
graph = "workflow.fabro"
[run]
goal = "Show stored artifacts"
[sandbox]
[run.sandbox]
provider = "local"
preserve = true
[sandbox.local]
[run.sandbox.local]
worktree_mode = "never"
[artifacts]
[run.artifacts]
include = ["assets/**"]
"#,
);

View file

@ -177,9 +177,9 @@ fn runner_uses_snapshotted_app_id_for_github_credentials() {
context.write_home(
".fabro/settings.toml",
"\
version = 1
_version = 1
[git]
[server.integrations.github]
app_id = \"snapshotted-app-id\"
",
);
@ -222,7 +222,7 @@ digraph GitHubApp {
"#
);
context.write_home(".fabro/settings.toml", "version = 1\n");
context.write_home(".fabro/settings.toml", "_version = 1\n");
let server = server_target(&context.storage_dir);
let mut cmd = context.command();

View file

@ -137,18 +137,22 @@ fn store_dump_exports_blob_refs_and_artifacts_together() {
.unwrap();
fs::write(
workspace_dir.join("run.toml"),
r#"version = 1
r#"_version = 1
[workflow]
graph = "mixed-export.fabro"
[run]
goal = "Generate oversized command output and artifacts"
[sandbox]
[run.sandbox]
provider = "local"
preserve = true
[sandbox.local]
[run.sandbox.local]
worktree_mode = "never"
[artifacts]
[run.artifacts]
include = ["assets/**"]
"#,
)

View file

@ -34,10 +34,13 @@ fn list() {
let context = test_context!();
context
.write_temp("fabro.toml", "version = 1\n")
.write_temp(
"fabro.toml",
"_version = 1\n\n[project]\ndirectory = \".\"\n",
)
.write_temp(
"workflows/my_test_wf/workflow.toml",
"version = 1\ngoal = \"A test workflow\"\n",
"_version = 1\n\n[run]\ngoal = \"A test workflow\"\n",
);
let mut cmd = context.command();

View file

@ -79,7 +79,7 @@ fn workflow_create_writes_scaffold_files() {
std::fs::read_to_string(project.fabro_root.join("workflows/hello-world/workflow.toml"))
.unwrap(),
@r###"
version = 1
_version = 1
"###
);
}
@ -125,7 +125,7 @@ fn workflow_create_rejects_existing_workflow() {
std::fs::create_dir_all(project.fabro_root.join("workflows/existing")).unwrap();
std::fs::write(
project.fabro_root.join("workflows/existing/workflow.toml"),
"version = 1\n",
"_version = 1\n",
)
.unwrap();
@ -163,7 +163,7 @@ fn workflow_create_json_uses_resolved_custom_root_paths() {
let project_dir = context.temp_dir.join("project");
context.write_temp(
"project/fabro.toml",
"version = 1\n[fabro]\nroot = \"custom/fabro-data\"\n",
"_version = 1\n\n[project]\ndirectory = \"custom/fabro-data\"\n",
);
let output = context

View file

@ -871,10 +871,10 @@ app_id = "snapshotted-app-id"
Some(types::ManifestWorkflowConfig {
path: "workflow.toml".to_string(),
source: r#"
version = 1
_version = 1
[setup]
commands = ["workflow-setup"]
[[run.prepare.steps]]
script = "workflow-setup"
"#
.to_string(),
});
@ -882,10 +882,12 @@ commands = ["workflow-setup"]
path: Some("/tmp/home/.fabro/settings.toml".to_string()),
source: Some(
r#"
[setup]
commands = ["cli-setup"]
_version = 1
[git]
[[run.prepare.steps]]
script = "cli-setup"
[server.integrations.github]
app_id = "snapshotted-app-id"
"#
.to_string(),
@ -895,13 +897,15 @@ app_id = "snapshotted-app-id"
let prepared = prepare_manifest_with_mode(&server_settings, &manifest, true).unwrap();
// v2 merge matrix: run.prepare.steps replaces the whole list across
// layers, so the higher-precedence workflow layer wins over cli.
assert_eq!(
prepared
.settings
.setup
.as_ref()
.map(|setup| setup.commands.clone()),
Some(vec!["workflow-setup".to_string(), "cli-setup".to_string(),])
Some(vec!["workflow-setup".to_string()])
);
assert_eq!(prepared.settings.app_id(), Some("snapshotted-app-id"));
assert_eq!(