From d192bb8106ad0b72618758cfe9c62241140502fa Mon Sep 17 00:00:00 2001 From: Clara Rostock Date: Fri, 19 Jun 2026 18:06:41 +0200 Subject: [PATCH 1/2] feat: use environment variables --- Cargo.toml | 2 +- src/cli.rs | 54 +++++++++++++++++++++++++++--------------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7854ab..0db0aec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "4", features = [ "wrap_help", "derive" ] } +clap = { version = "4", features = [ "wrap_help", "derive", "env" ] } dirs = "6" flexi_logger = "0.16" fork = "0.2" diff --git a/src/cli.rs b/src/cli.rs index 05c49c8..401dc82 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -25,91 +25,91 @@ use tokio::process::Command; #[command(version = "1.0", author = "Serokell ")] pub struct Opts { /// The flake to deploy - #[arg(group = "deploy")] + #[arg(group = "deploy", env = "DEPLOY_TARGET")] target: Option, /// A list of flakes to deploy alternatively - #[arg(long, group = "deploy", num_args = 1..)] + #[arg(long, group = "deploy", num_args = 1.., env = "DEPLOY_TARGETS")] targets: Option>, /// Treat targets as files instead of flakes - #[clap(short, long)] + #[clap(short, long, env = "DEPLOY_FILE")] file: Option, /// Check signatures when using `nix copy` - #[arg(short, long)] + #[arg(short, long, env = "DEPLOY_CHECKSIGS")] checksigs: bool, /// Use the interactive prompt before deployment - #[arg(short, long)] + #[arg(short, long, env = "DEPLOY_INTERACTIVE")] interactive: bool, /// Extra arguments to be passed to nix build - #[arg(last = true)] + #[arg(last = true, env = "DEPLOY_EXTRA_BUILD_ARGS")] extra_build_args: Vec, /// Print debug logs to output - #[arg(short, long)] + #[arg(short, long, env = "DEPLOY_DEBUG_LOGS")] debug_logs: bool, /// Directory to print logs to (including the background activation process) - #[arg(long)] + #[arg(long, env = "DEPLOY_LOG_DIR")] log_dir: Option, /// Keep the build outputs of each built profile - #[arg(short, long)] + #[arg(short, long, env = "DEPLOY_KEEP_RESULT")] keep_result: bool, /// Location to keep outputs from built profiles in - #[arg(short, long)] + #[arg(short, long, env = "DEPLOY_RESULT_PATH")] result_path: Option, /// Skip the automatic pre-build checks - #[arg(short, long)] + #[arg(short, long, env = "DEPLOY_SKIP_CHECKS")] skip_checks: bool, /// Build on remote host - #[arg(long)] + #[arg(long, env = "DEPLOY_REMOTE_BUILD")] remote_build: bool, /// Override the SSH user with the given value - #[arg(long)] + #[arg(long, env = "DEPLOY_SSH_USER")] ssh_user: Option, /// Override the profile user with the given value - #[arg(long)] + #[arg(long, env = "DEPLOY_PROFILE_USER")] profile_user: Option, /// Override the SSH options used - #[arg(long, allow_hyphen_values = true)] + #[arg(long, allow_hyphen_values = true, env = "DEPLOY_SSH_OPTS")] ssh_opts: Option, /// Override if the connecting to the target node should be considered fast - #[arg(long)] + #[arg(long, env = "DEPLOY_FAST_CONNECTION")] fast_connection: Option, /// Override if a rollback should be attempted if activation fails - #[arg(long)] + #[arg(long, env = "DEPLOY_AUTO_ROLLBACK")] auto_rollback: Option, /// Override hostname used for the node - #[arg(long)] + #[arg(long, env = "DEPLOY_HOSTNAME")] hostname: Option, /// Make activation wait for confirmation, or roll back after a period of time - #[arg(long)] + #[arg(long, env = "DEPLOY_MAGIC_ROLLBACK")] magic_rollback: Option, /// How long activation should wait for confirmation (if using magic-rollback) - #[arg(long)] + #[arg(long, env = "DEPLOY_CONFIRM_TIMEOUT")] confirm_timeout: Option, /// How long we should wait for profile activation - #[arg(long)] + #[arg(long, env = "DEPLOY_ACTIVATION_TIMEOUT")] activation_timeout: Option, /// Where to store temporary files (only used by magic-rollback) - #[arg(long)] + #[arg(long, env = "DEPLOY_TEMP_PATH")] temp_path: Option, /// Show what will be activated on the machines - #[arg(long)] + #[arg(long, env = "DEPLOY_DRY_ACTIVATE")] dry_activate: bool, /// Don't activate, but update the boot loader to boot into the new profile - #[arg(long)] + #[arg(long, env = "DEPLOY_BOOT")] boot: bool, /// Revoke all previously succeeded deploys when deploying multiple profiles - #[arg(long)] + #[arg(long, env = "DEPLOY_ROLLBACK_SUCCEEDED")] rollback_succeeded: Option, /// Which sudo command to use. Must accept at least two arguments: user name to execute commands as and the rest is the command to execute - #[arg(long)] + #[arg(long, env = "DEPLOY_SUDO")] sudo: Option, /// Prompt for sudo password during activation. - #[arg(long)] + #[arg(long, env = "DEPLOY_INTERACTIVE_SUDO")] interactive_sudo: Option, } From 9c5ad3b9ed5cecb64a53620dbcd6c196ce7ad76e Mon Sep 17 00:00:00 2001 From: Clara Rostock Date: Fri, 19 Jun 2026 18:07:01 +0200 Subject: [PATCH 2/2] doc: document environment variables --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index d51c991..337af3e 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,40 @@ If you require a signing key to push closures to your server, specify the path t Check out `deploy --help` for CLI flags! Remember to check there before making one-time changes to things like hostnames. +### Environment variables + +Every CLI flag can also be set through an environment variable. This is handy for CI or for keeping invocation-specific settings out of your shell history. The command line takes precedence over the environment. Each variable is named `DEPLOY_` followed by the flag in upper snake case: + +| Flag | Environment variable | +| --- | --- | +| `` | `DEPLOY_TARGET` | +| `--targets` | `DEPLOY_TARGETS` | +| `--file` | `DEPLOY_FILE` | +| `--checksigs` | `DEPLOY_CHECKSIGS` | +| `--interactive` | `DEPLOY_INTERACTIVE` | +| `-- ` | `DEPLOY_EXTRA_BUILD_ARGS` | +| `--debug-logs` | `DEPLOY_DEBUG_LOGS` | +| `--log-dir` | `DEPLOY_LOG_DIR` | +| `--keep-result` | `DEPLOY_KEEP_RESULT` | +| `--result-path` | `DEPLOY_RESULT_PATH` | +| `--skip-checks` | `DEPLOY_SKIP_CHECKS` | +| `--remote-build` | `DEPLOY_REMOTE_BUILD` | +| `--ssh-user` | `DEPLOY_SSH_USER` | +| `--profile-user` | `DEPLOY_PROFILE_USER` | +| `--ssh-opts` | `DEPLOY_SSH_OPTS` | +| `--fast-connection` | `DEPLOY_FAST_CONNECTION` | +| `--auto-rollback` | `DEPLOY_AUTO_ROLLBACK` | +| `--hostname` | `DEPLOY_HOSTNAME` | +| `--magic-rollback` | `DEPLOY_MAGIC_ROLLBACK` | +| `--confirm-timeout` | `DEPLOY_CONFIRM_TIMEOUT` | +| `--activation-timeout` | `DEPLOY_ACTIVATION_TIMEOUT` | +| `--temp-path` | `DEPLOY_TEMP_PATH` | +| `--dry-activate` | `DEPLOY_DRY_ACTIVATE` | +| `--boot` | `DEPLOY_BOOT` | +| `--rollback-succeeded` | `DEPLOY_ROLLBACK_SUCCEEDED` | +| `--sudo` | `DEPLOY_SUDO` | +| `--interactive-sudo` | `DEPLOY_INTERACTIVE_SUDO` | + There is also an `activate` binary though this should be ignored, it is only used internally (on the deployed system) and for testing/hacking purposes. ## Ideas