Repository navigation
fix(cli): reject unsupported go test flags #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,26 @@ pub enum CliExit { | |||||
| UnknownFlag, | ||||||
| } | ||||||
|
|
||||||
| /// Whether an argument is a package pattern rather than a flag value. | ||||||
| /// | ||||||
| /// Go flag values can be anything, so this is a heuristic based on `go help packages`: | ||||||
| /// relative or absolute paths, `...` wildcards, the reserved words, and domain-style | ||||||
| /// import paths (`github.com/x/y`). A bare `/` is not enough, since subtest patterns | ||||||
| /// such as `-run TestX/sub` use it too, and a bare dot is not enough either (`cpu.out`). | ||||||
| fn looks_like_package(arg: &str) -> bool { | ||||||
| if matches!(arg, "." | ".." | "all" | "std" | "cmd") { | ||||||
| return true; | ||||||
| } | ||||||
| if arg.starts_with("./") || arg.starts_with("../") || arg.starts_with('/') { | ||||||
| return true; | ||||||
| } | ||||||
| if arg.contains("...") { | ||||||
| return true; | ||||||
| } | ||||||
| arg.split_once('/') | ||||||
| .is_some_and(|(host, _)| host.contains('.')) | ||||||
| } | ||||||
|
|
||||||
| #[derive(Debug)] | ||||||
| pub struct Cli { | ||||||
| /// Run only benchmarks matching regexp | ||||||
|
|
@@ -48,7 +68,8 @@ impl Cli { | |||||
| /// | ||||||
| /// We can't do this with clap/structopt, because they only support single dashes for single-letter | ||||||
| /// flags (e.g., `-h`), and double dashes for multi-letter flags (e.g., `--help`). | ||||||
| fn parse_args(mut args: impl Iterator<Item = String>) -> Result<Self, CliExit> { | ||||||
| fn parse_args(args: impl Iterator<Item = String>) -> Result<Self, CliExit> { | ||||||
| let mut args = args.peekable(); | ||||||
| let mut instance = Self::default(); | ||||||
|
|
||||||
| // We currently only support the `test` subcommand. | ||||||
|
|
@@ -109,6 +130,15 @@ UNSUPPORTED FLAGS (will be warned about): | |||||
| eprintln!( | ||||||
| "warning: flag '{s}' is not supported by CodSpeed Go runner, ignoring" | ||||||
| ); | ||||||
| if s.contains('=') { | ||||||
| continue; | ||||||
| } | ||||||
| // The flag's arity is unknown. A bare token that does not look like a | ||||||
| // package is the flag's value, and must not be collected as a package. | ||||||
| let is_flag_value = |a: &String| !a.starts_with('-') && !looks_like_package(a); | ||||||
| if let Some(value) = args.next_if(is_flag_value) { | ||||||
| eprintln!("warning: ignoring value '{value}' of unsupported flag '{s}'"); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new warning uses
Suggested change
Rule Used: Never use Prompt To Fix With AIThis is a comment left during a code review.
Path: go-runner/src/cli.rs
Line: 140
Comment:
**Warning bypasses tracing**
The new warning uses `eprintln!`, but the repository rule prohibits `println!` and `eprintln!` in Rust and requires tracing macros instead. Use `tracing::warn!` here to satisfy that requirement before merging.
```suggestion
tracing::warn!("ignoring value '{value}' of unsupported flag '{s}'");
```
**Rule Used:** Never use `println!`/`eprintln!` in Rust; use tracing macros (`info!`/`debug!`/`warn!`/`error!`). ([source](https://app.greptile.com/codspeed/-/custom-context?memory=f04f734b-e556-482b-98b9-64c7ce663663))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||||||
| } | ||||||
| } | ||||||
| _ => { | ||||||
| // Collect package arguments for filtering | ||||||
|
|
@@ -128,6 +158,7 @@ UNSUPPORTED FLAGS (will be warned about): | |||||
| #[cfg(test)] | ||||||
| mod tests { | ||||||
| use super::*; | ||||||
| use rstest::rstest; | ||||||
|
|
||||||
| fn str_to_iter(cmd: &str) -> Result<Cli, CliExit> { | ||||||
| let args: Vec<String> = if cmd.trim().is_empty() { | ||||||
|
|
@@ -210,9 +241,36 @@ mod tests { | |||||
|
|
||||||
| let result = str_to_iter("go-runner test -benchtime"); | ||||||
| assert!(matches!(result, Err(CliExit::MissingArgument))); | ||||||
| } | ||||||
|
|
||||||
| // Unknown flags now generate warnings but don't cause errors | ||||||
| let result = str_to_iter("go-runner test -unknown"); | ||||||
| assert!(result.is_ok()); | ||||||
| #[rstest] | ||||||
| // Value flags: the flag and its separate value are dropped. | ||||||
| #[case::separate_p("-p 1 ./... -bench Foo", &["./...", "-bench", "Foo"])] | ||||||
| #[case::count("-count 5 ./pkg", &["./pkg"])] | ||||||
| #[case::timeout("-timeout 10m ./...", &["./..."])] | ||||||
| #[case::cpu_list("-cpu 1,2,4 ./...", &["./..."])] | ||||||
| #[case::tags("-tags integration ./...", &["./..."])] | ||||||
| #[case::cpuprofile("-cpuprofile cpu.out ./...", &["./..."])] | ||||||
| #[case::run_regex("-run ^$ ./...", &["./..."])] | ||||||
| #[case::run_subtest("-run TestX/sub ./...", &["./..."])] | ||||||
| #[case::unknown_with_value("-unknown value ./...", &["./..."])] | ||||||
| // Inline values: only the single token is dropped. | ||||||
| #[case::attached_p("-p=1 ./...", &["./..."])] | ||||||
| // Boolean flags followed by a package: the package is kept. | ||||||
| #[case::benchmem("-benchmem ./...", &["./..."])] | ||||||
| #[case::verbose_then_relative("-v ./pkg", &["./pkg"])] | ||||||
| #[case::verbose_then_parent("-v ../pkg", &["../pkg"])] | ||||||
| #[case::verbose_then_absolute("-v /abs/pkg", &["/abs/pkg"])] | ||||||
| #[case::verbose_then_dot("-v .", &["."])] | ||||||
| #[case::verbose_then_wildcard("-v pkg/...", &["pkg/..."])] | ||||||
| #[case::verbose_then_import_path("-v github.com/x/y", &["github.com/x/y"])] | ||||||
| #[case::verbose_then_std("-v std", &["std"])] | ||||||
| // Boolean flag followed by another flag: nothing extra is consumed. | ||||||
| #[case::flag_then_flag("-v -bench Foo", &["./..."])] | ||||||
| // Unsupported flag at the end of the arguments. | ||||||
| #[case::trailing_flag("-p", &["./..."])] | ||||||
| fn test_cli_drops_unsupported_flags(#[case] args: &str, #[case] packages: &[&str]) { | ||||||
| let cli = str_to_iter(&format!("go-runner test {args}")).unwrap(); | ||||||
| assert_eq!(cli.packages, packages, "{args}"); | ||||||
| } | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With
test -v fmt, the new code consumesfmtas a flag value and runs the default./...instead of the requested package. Conversely,test -cpuprofile ./cpu.out ./...keeps./cpu.outas a package, leaving the original failure unfixed.Return
CliExit::UnknownFlagbefore Go runs, as the PR description requires, rather than guessing which arguments belong to unsupported flags. Update the tests to expect rejection.Prompt To Fix With AI