Skip to content

Commit 696bfc1

Browse files
committed
cargo-rail: updating/streamlining CLI; fixing the panic for unwrap/errors.
1 parent 89d5e2c commit 696bfc1

File tree

6 files changed

+96
-121
lines changed

6 files changed

+96
-121
lines changed

src/cargo/metadata.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl WorkspaceMetadata {
119119
/// - Feature dependency analysis: Understand feature activation chains
120120
/// - Feature optimization: Identify minimal feature sets for build times
121121
///
122-
/// TODO: Use this for `cargo rail audit` or `cargo rail graph` to inspect specific packages.
122+
/// TODO: Use this for `cargo rail audit` or `cargo rail inspect` to inspect specific packages.
123123
/// For global analysis (like unification), use `cargo_metadata` directly to avoid O(N) lookups.
124124
///
125125
/// # Example
@@ -210,7 +210,7 @@ impl WorkspaceMetadata {
210210
/// - License compliance: Check all dependency licenses
211211
/// - Duplicate detection: Find dependencies listed multiple times
212212
///
213-
/// TODO: Use this for `cargo rail graph` or `cargo rail audit` to inspect dependencies of a specific crate.
213+
/// TODO: Use this for `cargo rail inspect` or `cargo rail audit` to inspect dependencies of a specific crate.
214214
/// For global analysis, iterate `metadata.packages` directly.
215215
///
216216
/// # Example

src/commands/watch.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ fn run_with_bacon(_ctx: &WorkspaceContext, _config: TestConfig) -> RailResult<()
110110
println!(" Running: bacon test\n");
111111

112112
// Note: In the future, we could generate a custom bacon.toml that runs
113-
// `cargo rail graph test` instead of `cargo test` to get smart change detection
113+
// `cargo rail test` instead of `cargo test` to get smart change detection
114114
// while still benefiting from bacon's UI. For now, users get standard bacon behavior.
115115

116116
let status = Command::new("bacon")
@@ -133,8 +133,8 @@ fn run_with_cargo_watch(ctx: &WorkspaceContext, config: TestConfig) -> RailResul
133133
let mut cmd = Command::new("cargo-watch");
134134
cmd.current_dir(ctx.workspace_root());
135135

136-
// cargo-watch -x "rail graph test --since HEAD~1"
137-
let mut rail_cmd = String::from("rail graph test");
136+
// cargo-watch -x "rail test --since HEAD~1"
137+
let mut rail_cmd = String::from("rail test");
138138

139139
if let Some(ref since) = config.since {
140140
rail_cmd.push_str(&format!(" --since {}", since));

src/graph/core.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub struct WorkspaceGraph {
6464
/// - Feature analysis: Cross-reference cargo metadata with dependency graph
6565
/// - External dependency queries: Look up non-workspace packages efficiently
6666
///
67-
/// TODO: Expose this via a public method when implementing `cargo rail graph --resolve` or similar advanced analysis.
67+
/// TODO: Expose this via a public method when implementing `cargo rail resolve` or similar advanced analysis.
6868
#[allow(dead_code)]
6969
id_to_node: HashMap<PackageId, NodeIndex>,
7070

@@ -162,7 +162,7 @@ impl WorkspaceGraph {
162162
/// - Dependency analysis: Find immediate dependencies for auditing
163163
/// - Visualization: Generate dependency tree for a specific crate
164164
///
165-
/// TODO: Use this for `cargo rail graph` CLI command.
165+
/// TODO: Use this for `cargo rail inspect` CLI command.
166166
#[allow(dead_code)]
167167
pub fn direct_dependencies(&self, crate_name: &str) -> RailResult<Vec<String>> {
168168
let node_idx = self.find_node(crate_name)?;
@@ -186,7 +186,7 @@ impl WorkspaceGraph {
186186
/// - Impact analysis: See what breaks when modifying this crate
187187
/// - Reverse dependency tree: Understand crate usage across workspace
188188
///
189-
/// TODO: Use this for `cargo rail graph` or `cargo rail affected` CLI commands.
189+
/// TODO: Use this for `cargo rail inspect` or `cargo rail affected` CLI commands.
190190
#[allow(dead_code)]
191191
pub fn direct_dependents(&self, crate_name: &str) -> RailResult<Vec<String>> {
192192
let node_idx = self.find_node(crate_name)?;
@@ -381,7 +381,7 @@ impl WorkspaceGraph {
381381
/// - Audit dependency chains: Trace the path from app to vulnerable dependency
382382
/// - Refactoring decisions: Identify dependency paths to break or preserve
383383
///
384-
/// TODO: Implement `cargo rail graph --why` command using this method.
384+
/// TODO: Implement `cargo rail why` command using this method.
385385
///
386386
/// # Example
387387
/// ```ignore
@@ -443,7 +443,7 @@ impl WorkspaceGraph {
443443
/// - Visual debugging: See complex dependency relationships at a glance
444444
/// - Architecture analysis: Understand workspace structure visually
445445
///
446-
/// TODO: Implement `cargo rail graph --dot` command using this method.
446+
/// TODO: Implement `cargo rail graph` command (as a top-level visualization command) using this method.
447447
///
448448
/// # Example
449449
/// ```bash

src/main.rs

Lines changed: 70 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,46 @@ enum Commands {
2727
// ============================================================================
2828
// Graph-Aware CI Optimization
2929
// ============================================================================
30-
/// Graph-aware workspace operations
31-
#[command(subcommand)]
32-
Graph(GraphCommands),
30+
/// Show which crates are affected by changes
31+
Affected {
32+
/// Git ref to compare against (default: origin/main)
33+
#[arg(long, default_value = "origin/main")]
34+
since: String,
35+
/// Start ref (for SHA pair mode)
36+
#[arg(long, conflicts_with = "since")]
37+
from: Option<String>,
38+
/// End ref (for SHA pair mode)
39+
#[arg(long, requires = "from")]
40+
to: Option<String>,
41+
/// Output format: text, json, names-only
42+
#[arg(long, default_value = "text")]
43+
format: String,
44+
},
45+
46+
/// Run tests only for affected crates (smart test runner)
47+
Test {
48+
/// Git ref to compare against (auto-detects origin/main, origin/master, or HEAD~1)
49+
#[arg(long)]
50+
since: Option<String>,
51+
/// Use cargo-nextest if available
52+
#[arg(long)]
53+
nextest: bool,
54+
/// Show what would be tested without running tests
55+
#[arg(long)]
56+
dry_run: bool,
57+
/// Explain why tests are being run
58+
#[arg(long)]
59+
explain: bool,
60+
/// Watch for file changes and re-run tests automatically
61+
#[arg(long)]
62+
watch: bool,
63+
/// Watch mode backend: bacon, cargo-watch, auto (default: auto)
64+
#[arg(long, default_value = "auto")]
65+
watch_mode: String,
66+
/// Pass additional arguments to the test runner
67+
#[arg(last = true)]
68+
test_args: Vec<String>,
69+
},
3370

3471
// ============================================================================
3572
// Dependency Unification
@@ -107,50 +144,6 @@ enum Commands {
107144
},
108145
}
109146

110-
#[derive(Subcommand)]
111-
enum GraphCommands {
112-
/// Show which crates are affected by changes
113-
Affected {
114-
/// Git ref to compare against (default: origin/main)
115-
#[arg(long, default_value = "origin/main")]
116-
since: String,
117-
/// Start ref (for SHA pair mode)
118-
#[arg(long, conflicts_with = "since")]
119-
from: Option<String>,
120-
/// End ref (for SHA pair mode)
121-
#[arg(long, requires = "from")]
122-
to: Option<String>,
123-
/// Output format: text, json, names-only
124-
#[arg(long, default_value = "text")]
125-
format: String,
126-
},
127-
128-
/// Run tests only for affected crates (smart test runner)
129-
Test {
130-
/// Git ref to compare against (auto-detects origin/main, origin/master, or HEAD~1)
131-
#[arg(long)]
132-
since: Option<String>,
133-
/// Use cargo-nextest if available
134-
#[arg(long)]
135-
nextest: bool,
136-
/// Show what would be tested without running tests
137-
#[arg(long)]
138-
dry_run: bool,
139-
/// Explain why tests are being run
140-
#[arg(long)]
141-
explain: bool,
142-
/// Watch for file changes and re-run tests automatically
143-
#[arg(long)]
144-
watch: bool,
145-
/// Watch mode backend: bacon, cargo-watch, auto (default: auto)
146-
#[arg(long, default_value = "auto")]
147-
watch_mode: String,
148-
/// Pass additional arguments to the test runner
149-
#[arg(last = true)]
150-
test_args: Vec<String>,
151-
},
152-
}
153-
154147
#[derive(Subcommand)]
155148
enum UnifyCommands {
156149
/// Analyze dependencies and show unification plan (dry-run)
@@ -237,44 +230,42 @@ fn main() {
237230

238231
let result = match cli.command {
239232
// Graph Commands
240-
Commands::Graph(graph_cmd) => match graph_cmd {
241-
GraphCommands::Affected {
242-
since,
243-
from,
244-
to,
245-
format,
246-
} => commands::run_affected(&ctx, since, from, to, format, false),
247-
GraphCommands::Test {
233+
Commands::Affected {
234+
since,
235+
from,
236+
to,
237+
format,
238+
} => commands::run_affected(&ctx, since, from, to, format, false),
239+
Commands::Test {
240+
since,
241+
nextest,
242+
dry_run,
243+
explain,
244+
watch,
245+
watch_mode,
246+
test_args,
247+
} => {
248+
let config = commands::test::TestConfig {
248249
since,
249-
nextest,
250250
dry_run,
251251
explain,
252-
watch,
253-
watch_mode,
252+
prefer_nextest: nextest,
254253
test_args,
255-
} => {
256-
let config = commands::test::TestConfig {
257-
since,
258-
dry_run,
259-
explain,
260-
prefer_nextest: nextest,
261-
test_args,
262-
};
254+
};
263255

264-
if watch {
265-
// Parse watch mode
266-
let mode = match watch_mode.as_str() {
267-
"bacon" => commands::watch::WatchMode::Bacon,
268-
"cargo-watch" => commands::watch::WatchMode::CargoWatch,
269-
"auto" => commands::watch::WatchMode::Auto,
270-
_ => commands::watch::WatchMode::Auto,
271-
};
272-
commands::run_test_watch(&ctx, config, mode)
273-
} else {
274-
commands::run_test(&ctx, config)
275-
}
256+
if watch {
257+
// Parse watch mode
258+
let mode = match watch_mode.as_str() {
259+
"bacon" => commands::watch::WatchMode::Bacon,
260+
"cargo-watch" => commands::watch::WatchMode::CargoWatch,
261+
"auto" => commands::watch::WatchMode::Auto,
262+
_ => commands::watch::WatchMode::Auto,
263+
};
264+
commands::run_test_watch(&ctx, config, mode)
265+
} else {
266+
commands::run_test(&ctx, config)
276267
}
277-
},
268+
}
278269

279270
// Dependency Unification
280271
Commands::Unify(unify_cmd) => match unify_cmd {

tests/integration/test_affected.rs

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Integration tests for `cargo rail graph affected` command
1+
//! Integration tests for `cargo rail affected` command
22
33
use crate::helpers::{TestWorkspace, git, run_cargo_rail};
44
use anyhow::Result;
@@ -19,7 +19,7 @@ fn test_affected_basic() -> Result<()> {
1919
ws.commit("Modify lib-a")?;
2020

2121
// Run affected command
22-
let output = run_cargo_rail(&ws.path, &["rail", "graph", "affected", "--since", "origin/main"])?;
22+
let output = run_cargo_rail(&ws.path, &["rail", "affected", "--since", "origin/main"])?;
2323
let stdout = String::from_utf8_lossy(&output.stdout);
2424

2525
// Should show lib-a as directly affected and lib-b as dependent
@@ -40,7 +40,7 @@ fn test_affected_no_changes() -> Result<()> {
4040
git(&ws.path, &["branch", "origin/main"])?;
4141

4242
// Run affected with no changes
43-
let output = run_cargo_rail(&ws.path, &["rail", "graph", "affected", "--since", "origin/main"])?;
43+
let output = run_cargo_rail(&ws.path, &["rail", "affected", "--since", "origin/main"])?;
4444
let stdout = String::from_utf8_lossy(&output.stdout);
4545

4646
// Should indicate no changes
@@ -69,15 +69,7 @@ fn test_affected_json_output() -> Result<()> {
6969
// Run with --format json
7070
let output = run_cargo_rail(
7171
&ws.path,
72-
&[
73-
"rail",
74-
"graph",
75-
"affected",
76-
"--since",
77-
"origin/main",
78-
"--format",
79-
"json",
80-
],
72+
&["rail", "affected", "--since", "origin/main", "--format", "json"],
8173
)?;
8274
let stdout = String::from_utf8_lossy(&output.stdout);
8375

@@ -105,15 +97,7 @@ fn test_affected_names_only() -> Result<()> {
10597
// Run with --format names
10698
let output = run_cargo_rail(
10799
&ws.path,
108-
&[
109-
"rail",
110-
"graph",
111-
"affected",
112-
"--since",
113-
"origin/main",
114-
"--format",
115-
"names",
116-
],
100+
&["rail", "affected", "--since", "origin/main", "--format", "names"],
117101
)?;
118102
let stdout = String::from_utf8_lossy(&output.stdout);
119103

@@ -137,7 +121,7 @@ fn test_affected_sha_pair_mode() -> Result<()> {
137121
let sha2 = ws.commit("Update lib-a")?;
138122

139123
// Run with --from/--to
140-
let output = run_cargo_rail(&ws.path, &["rail", "graph", "affected", "--from", &sha1, "--to", &sha2])?;
124+
let output = run_cargo_rail(&ws.path, &["rail", "affected", "--from", &sha1, "--to", &sha2])?;
141125
let stdout = String::from_utf8_lossy(&output.stdout);
142126

143127
assert!(stdout.contains("lib-a"), "lib-a should be affected");

0 commit comments

Comments
 (0)