From f26039a9488994ca6370270f9bd012ace30fe2fe Mon Sep 17 00:00:00 2001 From: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com> Date: Sat, 3 Oct 2026 06:54:38 +0000 Subject: [PATCH 1/2] docs(config): say which commands stop on an invalid env override The help added in #4348 says invalid environment overrides are ignored with a warning while the valid ones apply. That holds for `wt list` and other tolerant loads, but `wt switch`, `wt merge`, `wt remove`, and the `wt step` commands load config strictly and exit 1 on the same override, as `test_eval_invalid_env_override_keeps_one_fatal_diagnosis` pins. Also refresh the `LoadError::Env` docstring: since #4348 it is pushed once per rejected setting, and `vars` lists only that setting's vars. --- docs/src/content/docs/config.md | 2 +- plugins/worktrunk/skills/worktrunk/reference/config.md | 2 +- skills/worktrunk/reference/config.md | 2 +- src/cli/mod.rs | 2 +- src/config/user/mod.rs | 6 +++--- ...egration__integration_tests__help__help_config_long.snap | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/src/content/docs/config.md b/docs/src/content/docs/config.md index 92df41f17..a9d6e776f 100644 --- a/docs/src/content/docs/config.md +++ b/docs/src/content/docs/config.md @@ -636,7 +636,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -Invalid environment overrides are ignored with a warning; other valid overrides still apply. +An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. ### Naming convention diff --git a/plugins/worktrunk/skills/worktrunk/reference/config.md b/plugins/worktrunk/skills/worktrunk/reference/config.md index 195afe19e..641692618 100644 --- a/plugins/worktrunk/skills/worktrunk/reference/config.md +++ b/plugins/worktrunk/skills/worktrunk/reference/config.md @@ -628,7 +628,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -Invalid environment overrides are ignored with a warning; other valid overrides still apply. +An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. ### Naming convention diff --git a/skills/worktrunk/reference/config.md b/skills/worktrunk/reference/config.md index 195afe19e..641692618 100644 --- a/skills/worktrunk/reference/config.md +++ b/skills/worktrunk/reference/config.md @@ -628,7 +628,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -Invalid environment overrides are ignored with a warning; other valid overrides still apply. +An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. ### Naming convention diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 3f90a9358..2826b1dd7 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -2595,7 +2595,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -Invalid environment overrides are ignored with a warning; other valid overrides still apply. +An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. ### Naming convention diff --git a/src/config/user/mod.rs b/src/config/user/mod.rs index e567d421d..ff3fc5879 100644 --- a/src/config/user/mod.rs +++ b/src/config/user/mod.rs @@ -85,9 +85,9 @@ pub use sections::{ pub enum LoadError { /// A file parser failed, retaining its source and raw diagnosis. File(super::ConfigParseError), - /// Config files parsed cleanly; applying env-var overrides failed. - /// `vars` lists the exact `WORKTRUNK_*` env vars that were parsed - /// as `(name, value)` pairs. + /// An env-var override setting was rejected; other settings' overrides + /// may still apply. `vars` lists the `WORKTRUNK_*` env vars forming the + /// rejected setting as `(name, value)` pairs. Env { err: String, vars: Vec<(String, String)>, diff --git a/tests/snapshots/integration__integration_tests__help__help_config_long.snap b/tests/snapshots/integration__integration_tests__help__help_config_long.snap index 763049d0d..b89a682ed 100644 --- a/tests/snapshots/integration__integration_tests__help__help_config_long.snap +++ b/tests/snapshots/integration__integration_tests__help__help_config_long.snap @@ -615,7 +615,7 @@ On first run without shell integration, Worktrunk offers to install it. On first Environment variables All user config options can be overridden with environment variables using the WORKTRUNK_ prefix. -Invalid environment overrides are ignored with a warning; other valid overrides still apply. +An invalid override is reported with a warning. wt list skips it and still applies the other valid overrides; commands such as wt switch, wt merge, and wt remove stop with an error instead. Naming convention From 7d1399d36695453312379fd5d69f766bbf316e10 Mon Sep 17 00:00:00 2001 From: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com> Date: Sat, 3 Oct 2026 07:12:42 +0000 Subject: [PATCH 2/2] fix(config): skip a rejected env override in every command Commands that load config through UserConfig::load() (wt switch, merge, remove, for-each, the wt step commands) treated a rejected WORKTRUNK_* override as fatal, after the startup prewarm had already warned that it was being ignored. load_with_cause now skips LoadError::Env, so every command falls back to the file layers for that setting and still applies the other overrides, as documented and as wt list already does. File, --config-set, and validation failures stay fatal. Reverts this branch's docs rewording, which described the strict path as intended. --- docs/src/content/docs/config.md | 2 +- .../skills/worktrunk/reference/config.md | 2 +- skills/worktrunk/reference/config.md | 2 +- src/cli/mod.rs | 2 +- src/config/user/mod.rs | 18 +++++++++++++----- tests/integration_tests/eval.rs | 13 ++++++------- ...eval__eval_skips_invalid_env_override.snap} | 3 --- ...egration_tests__help__help_config_long.snap | 2 +- 8 files changed, 24 insertions(+), 20 deletions(-) rename tests/snapshots/{integration__integration_tests__eval__eval_invalid_env_override_keeps_one_fatal_diagnosis.snap => integration__integration_tests__eval__eval_skips_invalid_env_override.snap} (67%) diff --git a/docs/src/content/docs/config.md b/docs/src/content/docs/config.md index a9d6e776f..92df41f17 100644 --- a/docs/src/content/docs/config.md +++ b/docs/src/content/docs/config.md @@ -636,7 +636,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. +Invalid environment overrides are ignored with a warning; other valid overrides still apply. ### Naming convention diff --git a/plugins/worktrunk/skills/worktrunk/reference/config.md b/plugins/worktrunk/skills/worktrunk/reference/config.md index 641692618..195afe19e 100644 --- a/plugins/worktrunk/skills/worktrunk/reference/config.md +++ b/plugins/worktrunk/skills/worktrunk/reference/config.md @@ -628,7 +628,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. +Invalid environment overrides are ignored with a warning; other valid overrides still apply. ### Naming convention diff --git a/skills/worktrunk/reference/config.md b/skills/worktrunk/reference/config.md index 641692618..195afe19e 100644 --- a/skills/worktrunk/reference/config.md +++ b/skills/worktrunk/reference/config.md @@ -628,7 +628,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. +Invalid environment overrides are ignored with a warning; other valid overrides still apply. ### Naming convention diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2826b1dd7..3f90a9358 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -2595,7 +2595,7 @@ On first run without shell integration, Worktrunk offers to install it. On first ## Environment variables All user config options can be overridden with environment variables using the `WORKTRUNK_` prefix. -An invalid override is reported with a warning. `wt list` skips it and still applies the other valid overrides; commands such as `wt switch`, `wt merge`, and `wt remove` stop with an error instead. +Invalid environment overrides are ignored with a warning; other valid overrides still apply. ### Naming convention diff --git a/src/config/user/mod.rs b/src/config/user/mod.rs index ff3fc5879..d503cc03c 100644 --- a/src/config/user/mod.rs +++ b/src/config/user/mod.rs @@ -78,9 +78,9 @@ pub use sections::{ /// identifies which layer failed so callers can emit targeted diagnostics /// (file errors with line/col vs env-var attribution). /// -/// Strict loading treats the first issue as fatal; best-effort -/// [`UserConfig::load_with_warnings()`] returns all issues alongside the -/// usable config. +/// Strict loading treats the first issue other than a rejected env-var +/// override as fatal; best-effort [`UserConfig::load_with_warnings()`] +/// returns all issues alongside the usable config. #[derive(Debug)] pub enum LoadError { /// A file parser failed, retaining its source and raw diagnosis. @@ -675,10 +675,18 @@ impl UserConfig { /// Like [`load()`](Self::load), but returns a [`LoadError`] that /// distinguishes file-level parse failures (with line/col) from - /// env-var override failures. + /// `--config-set` and validation failures. + /// + /// A rejected env-var override is not an error: like the tolerant load, + /// the setting falls back to the file layers and the other overrides + /// still apply. Its warning is emitted at startup by the user-config + /// prewarm, so every command reports it the same way. pub(crate) fn load_with_cause() -> Result { let (config, warnings) = Self::load_with_warnings(); - if let Some(err) = warnings.into_iter().next() { + if let Some(err) = warnings + .into_iter() + .find(|warning| !matches!(warning, LoadError::Env { .. })) + { return Err(err); } Ok(config) diff --git a/tests/integration_tests/eval.rs b/tests/integration_tests/eval.rs index 7a0859878..da0abf4c8 100644 --- a/tests/integration_tests/eval.rs +++ b/tests/integration_tests/eval.rs @@ -15,22 +15,21 @@ fn test_eval_branch(repo: TestRepo) { )); } -/// A strict command keeps the invalid override's diagnosis once in its fatal -/// block, independently of the earlier tolerant-load warning. +/// A command skips an invalid env override the way `wt list` does: the +/// startup warning names it once, and the command still runs. #[rstest] -fn test_eval_invalid_env_override_keeps_one_fatal_diagnosis(repo: TestRepo) { +fn test_eval_skips_invalid_env_override(repo: TestRepo) { repo.write_test_config("[list]\nbranches = true\n"); let mut cmd = repo.wt_command(); cmd.env("WORKTRUNK__LIST__BRANCHES", "not-a-bool") .args(["step", "eval", "{{ branch }}"]); let output = cmd.output().unwrap(); - assert_eq!(output.status.code(), Some(1)); - assert!(output.stdout.is_empty()); + assert!(output.status.success(), "{output:?}"); + assert_eq!(String::from_utf8_lossy(&output.stdout).trim(), "main"); let stderr = String::from_utf8_lossy(&output.stderr); let stderr = stderr.ansi_strip(); - let (_, fatal) = stderr.split_once("✗ Failed to load config").unwrap(); - assert_eq!(fatal.matches("invalid type:").count(), 1, "{stderr}"); + assert_eq!(stderr.matches("invalid type:").count(), 1, "{stderr}"); let settings = crate::common::setup_snapshot_settings(&repo); settings.bind(|| insta::assert_snapshot!(stderr)); diff --git a/tests/snapshots/integration__integration_tests__eval__eval_invalid_env_override_keeps_one_fatal_diagnosis.snap b/tests/snapshots/integration__integration_tests__eval__eval_skips_invalid_env_override.snap similarity index 67% rename from tests/snapshots/integration__integration_tests__eval__eval_invalid_env_override_keeps_one_fatal_diagnosis.snap rename to tests/snapshots/integration__integration_tests__eval__eval_skips_invalid_env_override.snap index 2b96a44b5..eb10cbaf3 100644 --- a/tests/snapshots/integration__integration_tests__eval__eval_invalid_env_override_keeps_one_fatal_diagnosis.snap +++ b/tests/snapshots/integration__integration_tests__eval__eval_skips_invalid_env_override.snap @@ -5,6 +5,3 @@ expression: stderr ▲ Ignoring env var overrides: WORKTRUNK__LIST__BRANCHES=not-a-bool invalid type: string "not-a-bool", expected a boolean in `list.branches` -✗ Failed to load config - invalid type: string "not-a-bool", expected a boolean - in `list.branches` diff --git a/tests/snapshots/integration__integration_tests__help__help_config_long.snap b/tests/snapshots/integration__integration_tests__help__help_config_long.snap index b89a682ed..763049d0d 100644 --- a/tests/snapshots/integration__integration_tests__help__help_config_long.snap +++ b/tests/snapshots/integration__integration_tests__help__help_config_long.snap @@ -615,7 +615,7 @@ On first run without shell integration, Worktrunk offers to install it. On first Environment variables All user config options can be overridden with environment variables using the WORKTRUNK_ prefix. -An invalid override is reported with a warning. wt list skips it and still applies the other valid overrides; commands such as wt switch, wt merge, and wt remove stop with an error instead. +Invalid environment overrides are ignored with a warning; other valid overrides still apply. Naming convention