diff --git a/doc/src/release-notes.md b/doc/src/release-notes.md index 27f169a..09e5db7 100644 --- a/doc/src/release-notes.md +++ b/doc/src/release-notes.md @@ -5,11 +5,15 @@ *Added:* * Edit links to documentation pages. +* New arguments to `show status` display actions that are in the requested states: + `--completed`, `--eligible`, `--submitted`, and `--waiting`. *Changed:* * Show `import` lines in Python examples. * Improve the verbose output from `submit`. +* `show status` hides actions with 0 directories by default. Pass `--all` to show all + actions. *Fixed:* diff --git a/doc/src/row/show/status.md b/doc/src/row/show/status.md index b43947c..2dfdf8d 100644 --- a/doc/src/row/show/status.md +++ b/doc/src/row/show/status.md @@ -5,7 +5,7 @@ Usage: row show status [OPTIONS] [DIRECTORIES] ``` -`row show status` prints a summary of all directories in the workspace. +`row show status` summarizes actions in the workflow. The summary includes the number of directories in each [status](../../guide/concepts/status.md) and an estimate of the remaining cost in either CPU-hours or GPU-hours based on the number of submitted, eligible, and waiting jobs and @@ -30,16 +30,40 @@ echo "dir1" | row show status - Set `--action ` to choose which actions to display by name. By default, **row** shows the status of all actions. `` is a wildcard pattern. +### `-all` + +Show all actions. By default, `show status` hides actions with 0 matching directories. + +### `--completed` + +Show actions with *completed* directories. + +### `--eligible` + +Show actions with *eligible* directories. + ### `--no-header` Hide the header in the output. +### `--submitted` + +Show actions with *submitted* directories. + +### `--waiting` + +Show actions with *waiting* directories. + ## Examples * Show the status of the entire workspace: ```bash row show status ``` +* Show the status of all actions with eligible directories: + ```bash + row show status --eligible + ``` * Show the status of a specific action: ```bash row show status --action=action diff --git a/src/cli.rs b/src/cli.rs index 3d95cfd..e575bf9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -70,7 +70,7 @@ pub enum ColorMode { pub enum ShowCommands { /// Show the current state of the workflow. /// - /// `row show status` prints a summary of all directories in the workspace. + /// `row show status` prints a summary of all actions in the workflow. /// The summary includes the number of directories in each status and an /// estimate of the remaining cost in either CPU-hours or GPU-hours based /// on the number of submitted, eligible, and waiting jobs and the @@ -82,6 +82,10 @@ pub enum ShowCommands { /// /// row show status /// + /// * Show the status of all actions with eligible directories + /// + /// row show status --eligible + /// /// * Show the status of a specific action: /// /// row show status --action=action diff --git a/src/cli/directories.rs b/src/cli/directories.rs index 631fa07..38d030a 100644 --- a/src/cli/directories.rs +++ b/src/cli/directories.rs @@ -43,7 +43,7 @@ pub struct Arguments { #[arg(long, display_order = 0)] completed: bool, - /// Show submitted + /// Show submitted directories. #[arg(long, display_order = 0)] submitted: bool, diff --git a/src/cli/status.rs b/src/cli/status.rs index 07085b1..ba47d3c 100644 --- a/src/cli/status.rs +++ b/src/cli/status.rs @@ -16,6 +16,7 @@ use row::project::{Project, Status}; use row::workflow::ResourceCost; use row::MultiProgressContainer; +#[allow(clippy::struct_excessive_bools)] #[derive(Args, Debug)] pub struct Arguments { /// Select the actions to summarize with a wildcard pattern. @@ -28,6 +29,26 @@ pub struct Arguments { /// Select directories to summarize (defaults to all). Use 'status -' to read from stdin. directories: Vec, + + /// Show actions with completed directories. + #[arg(long, display_order = 0, conflicts_with = "all")] + completed: bool, + + /// Show actions with submitted directories. + #[arg(long, display_order = 0, conflicts_with = "all")] + submitted: bool, + + /// Show actions with eligible directories. + #[arg(long, display_order = 0, conflicts_with = "all")] + eligible: bool, + + /// Show actions with waiting directories. + #[arg(long, display_order = 0, conflicts_with = "all")] + waiting: bool, + + /// Show all actions. + #[arg(long, display_order = 0)] + all: bool, } /// Format a status string for non-terminal outputs. @@ -84,6 +105,19 @@ pub fn status( output: &mut W, ) -> Result<(), Box> { debug!("Showing the workflow's status."); + + // Show directories with selected statuses. + let mut show_completed = args.completed; + let mut show_submitted = args.submitted; + let mut show_eligible = args.eligible; + let mut show_waiting = args.waiting; + if !show_completed && !show_submitted && !show_eligible && !show_waiting { + show_completed = true; + show_submitted = true; + show_eligible = true; + show_waiting = true; + } + let action_matcher = WildMatch::new(&args.action); let mut project = Project::open(options.io_threads, &options.cluster, multi_progress)?; @@ -134,9 +168,16 @@ pub fn status( cost = cost + action.resources.cost(group.len()); } - table - .rows - .push(Row::Items(make_row(action.name(), &status, &cost))); + if args.all + || (!status.completed.is_empty() && show_completed) + || (!status.submitted.is_empty() && show_submitted) + || (!status.eligible.is_empty() && show_eligible) + || (!status.waiting.is_empty() && show_waiting) + { + table + .rows + .push(Row::Items(make_row(action.name(), &status, &cost))); + } } if matching_action_count == 0 { diff --git a/tests/cli.rs b/tests/cli.rs index 08901b6..0ec30b6 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -44,6 +44,13 @@ name = "two" command = "touch workspace/{directory}/two" products = ["two"] previous_actions = ["one"] + +[[action]] +name = "three" +command = "touch workspace/{directory}/three" +products = ["three"] +[[action.group.include]] +condition = ["/v", "<", 0] "#, )?; @@ -141,7 +148,132 @@ fn status() -> Result<(), Box> { .assert() .success() .stdout(predicate::str::is_match("(?m)^one +0 +0 +10 +0")?) - .stdout(predicate::str::is_match("(?m)^two +0 +0 +0 +10")?); + .stdout(predicate::str::is_match("(?m)^two +0 +0 +0 +10")?) + .stdout(predicate::str::is_match("(?m)^three +0 +0 +0 +0")?.not()); + + Ok(()) +} + +#[test] +#[parallel] +fn status_waiting() -> Result<(), Box> { + let temp = TempDir::new()?; + let _ = setup_sample_workflow(&temp, 10); + + Command::cargo_bin("row")? + .args(["show", "status"]) + .args(["--cluster", "none"]) + .args(["--waiting"]) + .current_dir(temp.path()) + .env_remove("ROW_COLOR") + .env_remove("CLICOLOR") + .env("ROW_HOME", "/not/a/path") + .assert() + .success() + .stdout(predicate::str::is_match("(?m)^one +0 +0 +10 +0")?.not()) + .stdout(predicate::str::is_match("(?m)^two +0 +0 +0 +10")?) + .stdout(predicate::str::is_match("(?m)^three +0 +0 +0 +0")?.not()); + + Ok(()) +} + +#[test] +#[parallel] +fn status_eligible() -> Result<(), Box> { + let temp = TempDir::new()?; + let _ = setup_sample_workflow(&temp, 10); + + Command::cargo_bin("row")? + .args(["show", "status"]) + .args(["--cluster", "none"]) + .args(["--eligible"]) + .current_dir(temp.path()) + .env_remove("ROW_COLOR") + .env_remove("CLICOLOR") + .env("ROW_HOME", "/not/a/path") + .assert() + .success() + .stdout(predicate::str::is_match("(?m)^one +0 +0 +10 +0")?) + .stdout(predicate::str::is_match("(?m)^two +0 +0 +0 +10")?.not()) + .stdout(predicate::str::is_match("(?m)^three +0 +0 +0 +0")?.not()); + + Ok(()) +} + +#[test] +#[parallel] +fn status_submitted() -> Result<(), Box> { + let temp = TempDir::new()?; + let _ = setup_sample_workflow(&temp, 10); + + Command::cargo_bin("row")? + .args(["show", "status"]) + .args(["--cluster", "none"]) + .args(["--submitted"]) + .current_dir(temp.path()) + .env_remove("ROW_COLOR") + .env_remove("CLICOLOR") + .env("ROW_HOME", "/not/a/path") + .assert() + .success() + .stdout(predicate::str::is_match("(?m)^one +0 +0 +10 +0")?.not()) + .stdout(predicate::str::is_match("(?m)^two +0 +0 +0 +10")?.not()) + .stdout(predicate::str::is_match("(?m)^three +0 +0 +0 +0")?.not()); + + Ok(()) +} + +#[test] +#[parallel] +fn status_all() -> Result<(), Box> { + let temp = TempDir::new()?; + let _ = setup_sample_workflow(&temp, 10); + + Command::cargo_bin("row")? + .args(["show", "status"]) + .args(["--cluster", "none"]) + .args(["--all"]) + .current_dir(temp.path()) + .env_remove("ROW_COLOR") + .env_remove("CLICOLOR") + .env("ROW_HOME", "/not/a/path") + .assert() + .success() + .stdout(predicate::str::is_match("(?m)^one +0 +0 +10 +0")?) + .stdout(predicate::str::is_match("(?m)^two +0 +0 +0 +10")?) + .stdout(predicate::str::is_match("(?m)^three +0 +0 +0 +0")?); + + Ok(()) +} + +#[test] +#[parallel] +fn status_completed() -> Result<(), Box> { + let temp = TempDir::new()?; + let _ = setup_sample_workflow(&temp, 10); + + Command::cargo_bin("row")? + .arg("submit") + .args(["--cluster", "none"]) + .current_dir(temp.path()) + .env_remove("ROW_COLOR") + .env_remove("CLICOLOR") + .env("ROW_HOME", "/not/a/path") + .assert() + .success(); + + Command::cargo_bin("row")? + .args(["show", "status"]) + .args(["--cluster", "none"]) + .args(["--completed"]) + .current_dir(temp.path()) + .env_remove("ROW_COLOR") + .env_remove("CLICOLOR") + .env("ROW_HOME", "/not/a/path") + .assert() + .success() + .stdout(predicate::str::is_match("(?m)^one +10 +0 +0 +0")?) + .stdout(predicate::str::is_match("(?m)^two +0 +0 +10 +0")?.not()); Ok(()) }