Skip to content

Commit 58a5373

Browse files
KuShpszymkowiak
authored andcommitted
feat: take review into account
- Add validate_pnpm_filters() to warn when filters used with unsupported commands - Add comprehensive tests for all scenarios - Improve comments and use idiomatic rust
1 parent 7ce6777 commit 58a5373

1 file changed

Lines changed: 181 additions & 41 deletions

File tree

src/main.rs

Lines changed: 181 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,24 +1186,49 @@ fn shell_split(input: &str) -> Vec<String> {
11861186
tokens
11871187
}
11881188

1189-
/// Merge pnpm global filters args with other ones
1189+
/// Merge pnpm global filters args with other ones for standard String-based commands
11901190
fn merge_pnpm_args(filters: &[String], args: &[String]) -> Vec<String> {
11911191
filters
11921192
.iter()
11931193
.map(|filter| format!("--filter={}", filter))
1194-
.chain(args.iter().map(|arg| arg.to_string()))
1194+
.chain(args.iter().cloned())
11951195
.collect()
11961196
}
11971197

1198-
/// Merge pnpm global filters args with other ones
1198+
/// Merge pnpm global filters args with other ones, using OsString for passthrough compatibility
11991199
fn merge_pnpm_args_os(filters: &[String], args: &[OsString]) -> Vec<OsString> {
12001200
filters
12011201
.iter()
12021202
.map(|filter| OsString::from(format!("--filter={}", filter)))
1203-
.chain(args.iter().map(|arg| arg.to_os_string()))
1203+
.chain(args.iter().cloned())
12041204
.collect()
12051205
}
12061206

1207+
/// Validate that pnpm filters are only used in the global context, not before subcommands like build or tsc.
1208+
fn validate_pnpm_filters(filters: &[String], command: &PnpmCommands) -> Option<String> {
1209+
// Check if this is a Build or Typecheck command with filters
1210+
match command {
1211+
PnpmCommands::Build { .. } | PnpmCommands::Typecheck { .. } => {
1212+
// FIXME: if filters are present, we should find out which workspaces are build before running build
1213+
if !filters.is_empty() {
1214+
let cmd_name = match command {
1215+
PnpmCommands::Build { .. } => "build",
1216+
PnpmCommands::Typecheck { .. } => "tsc",
1217+
_ => unreachable!(),
1218+
};
1219+
let msg = format!(
1220+
"[rtk] warning: --filter is not yet supported for pnpm {}, filters preceding the subcommand will be ignored",
1221+
cmd_name
1222+
);
1223+
eprintln!("{}", msg);
1224+
return Some(msg);
1225+
}
1226+
None
1227+
}
1228+
_ => None,
1229+
}
1230+
}
1231+
12071232
fn main() -> Result<()> {
12081233
// Fire-and-forget telemetry ping (1/day, non-blocking)
12091234
telemetry::maybe_ping();
@@ -1426,42 +1451,49 @@ fn main() -> Result<()> {
14261451
psql_cmd::run(&args, cli.verbose)?;
14271452
}
14281453

1429-
Commands::Pnpm { filter, command } => match command {
1430-
PnpmCommands::List { depth, args } => {
1431-
pnpm_cmd::run(
1432-
pnpm_cmd::PnpmCommand::List { depth },
1433-
&merge_pnpm_args(&filter, &args),
1434-
cli.verbose,
1435-
)?;
1436-
}
1437-
PnpmCommands::Outdated { args } => {
1438-
pnpm_cmd::run(
1439-
pnpm_cmd::PnpmCommand::Outdated,
1440-
&merge_pnpm_args(&filter, &args),
1441-
cli.verbose,
1442-
)?;
1454+
Commands::Pnpm { filter, command } => {
1455+
// Warns user if filters are used with unsupported subcommands like build or typecheck
1456+
if let Some(warning) = validate_pnpm_filters(&filter, &command) {
1457+
eprintln!("{}", warning);
14431458
}
1444-
PnpmCommands::Install { packages, args } => {
1445-
pnpm_cmd::run(
1446-
pnpm_cmd::PnpmCommand::Install { packages },
1447-
&merge_pnpm_args(&filter, &args),
1448-
cli.verbose,
1449-
)?;
1450-
}
1451-
PnpmCommands::Build { args } => {
1452-
let mut build_args: Vec<String> = vec!["build".into()];
1453-
build_args.extend(args);
1454-
let os_args: Vec<OsString> = build_args.into_iter().map(OsString::from).collect();
1455-
pnpm_cmd::run_passthrough(&merge_pnpm_args_os(&filter, &os_args), cli.verbose)?;
1456-
}
1457-
PnpmCommands::Typecheck { args } => {
1458-
// FIXME: if filters are present, we should find out which workspaces are typechecked before running tsc
1459-
tsc_cmd::run(&args, cli.verbose)?;
1460-
}
1461-
PnpmCommands::Other(args) => {
1462-
pnpm_cmd::run_passthrough(&merge_pnpm_args_os(&filter, &args), cli.verbose)?;
1459+
1460+
match command {
1461+
PnpmCommands::List { depth, args } => {
1462+
pnpm_cmd::run(
1463+
pnpm_cmd::PnpmCommand::List { depth },
1464+
&merge_pnpm_args(&filter, &args),
1465+
cli.verbose,
1466+
)?;
1467+
}
1468+
PnpmCommands::Outdated { args } => {
1469+
pnpm_cmd::run(
1470+
pnpm_cmd::PnpmCommand::Outdated,
1471+
&merge_pnpm_args(&filter, &args),
1472+
cli.verbose,
1473+
)?;
1474+
}
1475+
PnpmCommands::Install { packages, args } => {
1476+
pnpm_cmd::run(
1477+
pnpm_cmd::PnpmCommand::Install { packages },
1478+
&merge_pnpm_args(&filter, &args),
1479+
cli.verbose,
1480+
)?;
1481+
}
1482+
PnpmCommands::Build { args } => {
1483+
let mut build_args: Vec<String> = vec!["build".into()];
1484+
build_args.extend(args);
1485+
let os_args: Vec<OsString> =
1486+
build_args.into_iter().map(OsString::from).collect();
1487+
pnpm_cmd::run_passthrough(&merge_pnpm_args_os(&filter, &os_args), cli.verbose)?;
1488+
}
1489+
PnpmCommands::Typecheck { args } => {
1490+
tsc_cmd::run(&args, cli.verbose)?;
1491+
}
1492+
PnpmCommands::Other(args) => {
1493+
pnpm_cmd::run_passthrough(&merge_pnpm_args_os(&filter, &args), cli.verbose)?;
1494+
}
14631495
}
1464-
},
1496+
}
14651497

14661498
Commands::Err { command } => {
14671499
let cmd = command.join(" ");
@@ -2511,6 +2543,14 @@ mod tests {
25112543
}
25122544
}
25132545

2546+
#[test]
2547+
fn test_merge_filters_with_no_args() {
2548+
let filters = vec![];
2549+
let args = vec!["--depth=0".to_string(), "--no-verbose".to_string()];
2550+
let expected_args = vec!["--depth=0", "--no-verbose"];
2551+
assert_eq!(merge_pnpm_args(&filters, &args), expected_args);
2552+
}
2553+
25142554
#[test]
25152555
fn test_merge_filters_with_args() {
25162556
let filters = vec!["@app1".to_string(), "@app2".to_string()];
@@ -2529,6 +2569,14 @@ mod tests {
25292569
assert_eq!(merge_pnpm_args(&filters, &args), expected_args);
25302570
}
25312571

2572+
#[test]
2573+
fn test_merge_filters_with_no_args_os() {
2574+
let filters = vec![];
2575+
let args = vec![OsString::from("--depth=0")];
2576+
let expected_args = vec![OsString::from("--depth=0")];
2577+
assert_eq!(merge_pnpm_args_os(&filters, &args), expected_args);
2578+
}
2579+
25322580
#[test]
25332581
fn test_merge_filters_with_args_os() {
25342582
let filters = vec!["@app1".to_string()];
@@ -2542,15 +2590,22 @@ mod tests {
25422590

25432591
#[test]
25442592
fn test_pnpm_subcommand_with_filter() {
2545-
let cli = Cli::try_parse_from(["rtk", "pnpm", "--filter", "@app1", "list"]).unwrap();
2593+
let cli = Cli::try_parse_from([
2594+
"rtk", "pnpm", "--filter", "@app1", "--filter", "@app2", "list", "--filter", "@app3",
2595+
"--filter", "@app4", "--prod",
2596+
])
2597+
.unwrap();
25462598
match cli.command {
25472599
Commands::Pnpm {
25482600
filter,
25492601
command: PnpmCommands::List { depth, args },
25502602
} => {
25512603
assert_eq!(depth, 0);
2552-
assert_eq!(filter, vec!["@app1"]);
2553-
assert!(args.is_empty());
2604+
assert_eq!(filter, vec!["@app1", "@app2"]);
2605+
assert_eq!(
2606+
args,
2607+
vec!["--filter", "@app3", "--filter", "@app4", "--prod"]
2608+
);
25542609
}
25552610
_ => panic!("Expected Pnpm List command"),
25562611
}
@@ -2568,4 +2623,89 @@ mod tests {
25682623
_ => panic!("Expected Pnpm command"),
25692624
}
25702625
}
2626+
2627+
#[test]
2628+
fn test_pnpm_build_without_filters() {
2629+
let cli = Cli::try_parse_from([
2630+
"rtk", "pnpm", "build", "--filter", "@app3", "--filter", "@app4",
2631+
])
2632+
.unwrap();
2633+
match cli.command {
2634+
Commands::Pnpm { filter, command } => {
2635+
let warning = validate_pnpm_filters(&filter, &command);
2636+
2637+
assert!(filter.is_empty());
2638+
assert!(warning.is_none())
2639+
}
2640+
_ => panic!("Expected Pnpm Build command"),
2641+
}
2642+
}
2643+
2644+
#[test]
2645+
fn test_pnpm_build_with_filters() {
2646+
let cli = Cli::try_parse_from([
2647+
"rtk", "pnpm", "--filter", "@app1", "--filter", "@app2", "build", "--filter", "@app3",
2648+
"--filter", "@app4",
2649+
])
2650+
.unwrap();
2651+
match cli.command {
2652+
Commands::Pnpm { filter, command } => {
2653+
let warning = validate_pnpm_filters(&filter, &command).unwrap();
2654+
2655+
assert_eq!(filter, vec!["@app1", "@app2"]);
2656+
assert_eq!(warning, "[rtk] warning: --filter is not yet supported for pnpm build, filters preceding the subcommand will be ignored")
2657+
}
2658+
_ => panic!("Expected Pnpm Build command"),
2659+
}
2660+
}
2661+
2662+
#[test]
2663+
fn test_pnpm_typecheck_without_filters() {
2664+
let cli = Cli::try_parse_from([
2665+
"rtk",
2666+
"pnpm",
2667+
"typecheck",
2668+
"--filter",
2669+
"@app3",
2670+
"--filter",
2671+
"@app4",
2672+
])
2673+
.unwrap();
2674+
match cli.command {
2675+
Commands::Pnpm { filter, command } => {
2676+
let warning = validate_pnpm_filters(&filter, &command);
2677+
2678+
assert!(filter.is_empty());
2679+
assert!(warning.is_none())
2680+
}
2681+
_ => panic!("Expected Pnpm Build command"),
2682+
}
2683+
}
2684+
2685+
#[test]
2686+
fn test_pnpm_typecheck_with_filters() {
2687+
let cli = Cli::try_parse_from([
2688+
"rtk",
2689+
"pnpm",
2690+
"--filter",
2691+
"@app1",
2692+
"--filter",
2693+
"@app2",
2694+
"typecheck",
2695+
"--filter",
2696+
"@app3",
2697+
"--filter",
2698+
"@app4",
2699+
])
2700+
.unwrap();
2701+
match cli.command {
2702+
Commands::Pnpm { filter, command } => {
2703+
let warning = validate_pnpm_filters(&filter, &command).unwrap();
2704+
2705+
assert_eq!(filter, vec!["@app1", "@app2"]);
2706+
assert_eq!(warning, "[rtk] warning: --filter is not yet supported for pnpm tsc, filters preceding the subcommand will be ignored")
2707+
}
2708+
_ => panic!("Expected Pnpm Build command"),
2709+
}
2710+
}
25712711
}

0 commit comments

Comments
 (0)