mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Diagnostics have carried a `fix` field all along, but the CLI renderer never printed it — the suggestion was only reachable through --json. The actionable half of every validation failure was invisible to the person running the command. print_diagnostics now emits the fix as a dim-labelled continuation line under any diagnostic that has one, at both error and warning severity. Gating it behind --verbose would defeat the point, and printing it only for errors would read as "this warning has no fix" — the warning suggestions are useful on their own. Diagnostics that set no fix simply omit the line. The severity match moved into print_diagnostic so the fix line is appended once in the loop rather than copied into all five arms; the rest of the diff is reindentation. print_diagnostics is shared by validate, preflight, graph, exec, and dry-run, so this covers all five. Eleven inline snapshots across four files gain a fix line; every change is additive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
129 lines
3.6 KiB
Rust
129 lines
3.6 KiB
Rust
use fabro_test::{fabro_snapshot, test_context};
|
||
|
||
use super::support::{fixture, read_text};
|
||
|
||
#[test]
|
||
fn help() {
|
||
let context = test_context!();
|
||
let mut cmd = context.command();
|
||
cmd.args(["graph", "--help"]);
|
||
fabro_snapshot!(context.filters(), cmd, @"
|
||
success: true
|
||
exit_code: 0
|
||
----- stdout -----
|
||
Render a workflow graph as SVG
|
||
|
||
Usage: fabro graph [OPTIONS] <WORKFLOW>
|
||
|
||
Arguments:
|
||
<WORKFLOW>
|
||
Path to the .fabro workflow file, .toml task config, or project workflow name
|
||
|
||
Options:
|
||
--json
|
||
Output as JSON
|
||
|
||
[env: FABRO_JSON=]
|
||
|
||
--server <SERVER>
|
||
Fabro server target: http(s) URL or absolute Unix socket path
|
||
|
||
[env: FABRO_SERVER=]
|
||
|
||
--debug
|
||
Enable DEBUG-level logging (default is INFO)
|
||
|
||
[env: FABRO_DEBUG=]
|
||
|
||
--format <FORMAT>
|
||
Output format
|
||
|
||
[default: svg]
|
||
[possible values: svg]
|
||
|
||
--no-upgrade-check
|
||
Disable automatic upgrade check
|
||
|
||
[env: FABRO_NO_UPGRADE_CHECK=true]
|
||
|
||
-o, --output <OUTPUT>
|
||
Output file path (defaults to stdout)
|
||
|
||
-d, --direction <DIRECTION>
|
||
Graph layout direction (overrides the DOT file's rankdir)
|
||
|
||
Possible values:
|
||
- lr: Left to right
|
||
- tb: Top to bottom
|
||
|
||
--quiet
|
||
Suppress non-essential output
|
||
|
||
[env: FABRO_QUIET=]
|
||
|
||
--allow-invalid
|
||
Render even when workflow validation reports errors
|
||
|
||
--verbose
|
||
Enable verbose output
|
||
|
||
[env: FABRO_VERBOSE=]
|
||
|
||
-h, --help
|
||
Print help (see a summary with '-h')
|
||
----- stderr -----
|
||
");
|
||
}
|
||
|
||
#[test]
|
||
fn graph_allow_invalid_renders_after_diagnostics() {
|
||
let context = test_context!();
|
||
let workflow = fixture("invalid.fabro");
|
||
let output_path = context.temp_dir.join("invalid.svg");
|
||
let mut cmd = context.command();
|
||
cmd.args([
|
||
"graph",
|
||
"--allow-invalid",
|
||
"-o",
|
||
output_path.to_str().unwrap(),
|
||
workflow.to_str().unwrap(),
|
||
]);
|
||
|
||
fabro_snapshot!(context.filters(), cmd, @"
|
||
success: true
|
||
exit_code: 0
|
||
----- stdout -----
|
||
----- stderr -----
|
||
error: Pipeline must have exactly one start node (shape=Mdiamond or id start/Start) (start_node)
|
||
fix: Add a node with shape=Mdiamond or id 'start'
|
||
error [node: exit]: Exit node 'exit' has 1 outgoing edge(s) but must have none (exit_no_outgoing)
|
||
fix: Remove outgoing edges from the exit node
|
||
");
|
||
|
||
let svg = read_text(&output_path);
|
||
assert!(
|
||
svg.contains("<svg") && svg.contains("Invalid"),
|
||
"expected invalid workflow to render as SVG, got: {}",
|
||
&svg[..svg.len().min(200)]
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn graph_invalid_workflow_fails_after_diagnostics() {
|
||
let context = test_context!();
|
||
let workflow = fixture("invalid.fabro");
|
||
let mut cmd = context.command();
|
||
cmd.args(["graph", workflow.to_str().unwrap()]);
|
||
|
||
fabro_snapshot!(context.filters(), cmd, @"
|
||
success: false
|
||
exit_code: 1
|
||
----- stdout -----
|
||
----- stderr -----
|
||
error: Pipeline must have exactly one start node (shape=Mdiamond or id start/Start) (start_node)
|
||
fix: Add a node with shape=Mdiamond or id 'start'
|
||
error [node: exit]: Exit node 'exit' has 1 outgoing edge(s) but must have none (exit_no_outgoing)
|
||
fix: Remove outgoing edges from the exit node
|
||
× Validation failed
|
||
");
|
||
}
|