From 041eb6d2aab5a612c0191f750e9402fd846e3997 Mon Sep 17 00:00:00 2001 From: Noam Gottlieb Date: Tue, 11 Feb 2025 01:09:48 +0200 Subject: [PATCH] feat: Added dry-run flag to pixi run + docs + test --- docs/reference/cli.md | 3 +++ src/cli/run.rs | 22 ++++++++++++++++++++++ tests/integration_python/test_run_cli.py | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 89df0b07d..3f0434ac3 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -297,6 +297,7 @@ You cannot run `pixi run source setup.bash` as `source` is not available in the - `--concurrent-downloads`: The number of concurrent downloads to use when installing packages. Defaults to 50. - `--concurrent-solves`: The number of concurrent solves to use when installing packages. Defaults to the number of cpu threads. - `--skip-deps`: Skip the dependencies of the task, which where defined in the `depends-on` field of the task. +- `--dry-run (-n)`: Run the task in dry-run mode (only print the command that would run) ```shell pixi run python @@ -310,6 +311,8 @@ pixi run build pixi run task argument1 argument2 # Skip dependencies of the task pixi run --skip-deps task +# Run in dry-run mode to see the commands that would be run +pixi run --dry-run task # If you have multiple environments you can select the right one with the --environment flag. pixi run --environment cuda python diff --git a/src/cli/run.rs b/src/cli/run.rs index 4f9604900..bf0928e28 100644 --- a/src/cli/run.rs +++ b/src/cli/run.rs @@ -66,6 +66,10 @@ pub struct Args { #[arg(long)] pub skip_deps: bool, + /// Run the task in dry-run mode (only print the command that would run) + #[clap(short = 'n', long)] + pub dry_run: bool, + #[clap(long, action = clap::ArgAction::HelpLong)] pub help: Option, @@ -151,6 +155,18 @@ pub async fn execute(args: Args) -> miette::Result<()> { tracing::info!("Task graph: {}", task_graph); + // Print dry-run message if dry-run mode is enabled + if args.dry_run { + eprintln!( + "{}{}", + console::Emoji("🌵 ", ""), + console::style("Dry-run mode enabled - no tasks will be executed.") + .yellow() + .bold(), + ); + eprintln!(); + } + // Traverse the task graph in topological order and execute each individual // task. let mut task_idx = 0; @@ -196,6 +212,12 @@ pub async fn execute(args: Args) -> miette::Result<()> { ); } + // on dry-run mode, we just print the command and skip the execution + if args.dry_run { + task_idx += 1; + continue; + } + // check task cache let task_cache = match executable_task .can_skip(&lock_file.lock_file) diff --git a/tests/integration_python/test_run_cli.py b/tests/integration_python/test_run_cli.py index b0ff26452..2cea6d777 100644 --- a/tests/integration_python/test_run_cli.py +++ b/tests/integration_python/test_run_cli.py @@ -352,3 +352,23 @@ def test_run_help(pixi: Path, tmp_pixi_workspace: Path) -> None: [pixi, "run", "python", "--help"], stdout_contains="python", ) + + +def test_run_dry_run(pixi: Path, tmp_pixi_workspace: Path) -> None: + manifest = tmp_pixi_workspace.joinpath("pixi.toml") + toml = f""" + {EMPTY_BOILERPLATE_PROJECT} + [activation.env] + DRY_RUN_TEST_VAR = "WET" + [tasks] + dry-run-task = "echo $DRY_RUN_TEST_VAR" + """ + manifest.write_text(toml) + + # Run the task with --dry-run flag + verify_cli_command( + [pixi, "run", "--manifest-path", manifest, "--dry-run", "dry-run-task"], + stderr_contains="$DRY_RUN_TEST_VAR", + stdout_excludes="WET", + stderr_excludes="WET", + )