diff --git a/docs/usage/config.md b/docs/usage/config.md index 4289c48..9f08d29 100644 --- a/docs/usage/config.md +++ b/docs/usage/config.md @@ -34,6 +34,7 @@ All keys are optional. | `sign_with` | enum | `auto` | Where `debsign` runs (see below). | | `sign_key` | string | — | GPG key ID/email for `debsign -k`. Required for container signing. | | `clean` | bool | `false` | Run `debian/rules clean` before building. Disabled by default; incompatible with `incremental`. | +| `shell_on_failure` | bool | `false` | On build or test failure, drop into an interactive shell in the environment when stdout is a TTY. | ### `source_sync_mode` diff --git a/packages/debmagic/src/build_intent.rs b/packages/debmagic/src/build_intent.rs index 533867b..088bab6 100644 --- a/packages/debmagic/src/build_intent.rs +++ b/packages/debmagic/src/build_intent.rs @@ -30,7 +30,7 @@ pub struct BuildIntentInput { pub clean: Option, pub no_clean: Option, pub source_sync: Option, - pub shell_on_failure: bool, + pub shell_on_failure: Option, pub driver_overrides: DriverOverrides, } @@ -124,11 +124,13 @@ pub fn resolve_build_intent(input: BuildIntentInput) -> anyhow::Result anyhow::Result<()> { let dir = std::env::temp_dir(); let mut input = base_input(dir); - input.shell_on_failure = true; + input.shell_on_failure = Some(true); + + let intent = resolve_build_intent(input)?; + assert!(intent.shell_on_failure); + Ok(()) + } + + #[test] + fn resolve_shell_on_failure_from_config() -> anyhow::Result<()> { + let dir = std::env::temp_dir(); + let mut input = base_input(dir); + input.config_file = None; + input.shell_on_failure = None; + + let config_path = std::env::temp_dir().join(format!( + "debmagic-shell-on-failure-{}.toml", + std::process::id() + )); + std::fs::write(&config_path, "shell_on_failure = true\n")?; + input.config_file = Some(config_path.clone()); let intent = resolve_build_intent(input)?; assert!(intent.shell_on_failure); + std::fs::remove_file(config_path)?; Ok(()) } diff --git a/packages/debmagic/src/cli.rs b/packages/debmagic/src/cli.rs index 5d20c5b..b083823 100644 --- a/packages/debmagic/src/cli.rs +++ b/packages/debmagic/src/cli.rs @@ -151,9 +151,9 @@ pub struct CommonBuildArgs { #[arg( long = "shell-on-failure", action = clap::ArgAction::SetTrue, - help = "On build failure, drop into an interactive shell in the build environment when stdout is a TTY" + help = "On build failure, drop into an interactive shell in the build environment when stdout is a TTY. Defaults to the 'shell_on_failure' setting in the config file (false if unset)." )] - pub shell_on_failure: bool, + pub shell_on_failure: Option, #[command(flatten)] pub common: CommonCli, @@ -266,9 +266,9 @@ pub struct TestSubcommandArgs { #[arg( long = "shell-on-failure", action = clap::ArgAction::SetTrue, - help = "On test failure, drop into an interactive shell in the test environment when stdout is a TTY" + help = "On test failure, drop into an interactive shell in the test environment when stdout is a TTY. Defaults to the 'shell_on_failure' setting in the config file (false if unset)." )] - pub shell_on_failure: bool, + pub shell_on_failure: Option, #[command(flatten)] pub common: CommonCli, diff --git a/packages/debmagic/src/config.rs b/packages/debmagic/src/config.rs index 8db86e5..9b6fc4b 100644 --- a/packages/debmagic/src/config.rs +++ b/packages/debmagic/src/config.rs @@ -32,6 +32,9 @@ pub struct Config { /// builds already stage a clean source tree and incremental builds preserve /// outputs intentionally. pub clean: bool, + /// On build or test failure, drop into an interactive shell in the + /// environment when stdout is a TTY. + pub shell_on_failure: bool, } impl Default for Config { @@ -46,6 +49,7 @@ impl Default for Config { sign_with: SignWith::default(), sign_key: None, clean: false, + shell_on_failure: false, } } } diff --git a/packages/debmagic/src/test/intent.rs b/packages/debmagic/src/test/intent.rs index 7cb486f..1cd7688 100644 --- a/packages/debmagic/src/test/intent.rs +++ b/packages/debmagic/src/test/intent.rs @@ -20,7 +20,7 @@ pub struct TestIntentInput { pub strict: bool, pub changes: Option, pub allow_host_test: bool, - pub shell_on_failure: bool, + pub shell_on_failure: Option, pub distro: Option, pub driver_overrides: DriverOverrides, } @@ -57,13 +57,15 @@ pub fn resolve_test_intent(input: TestIntentInput) -> anyhow::Result None }; + let shell_on_failure = input.shell_on_failure.unwrap_or(config.shell_on_failure); + Ok(TestIntent { source_dir, driver: input.driver, strict: input.strict, changes, allow_host_test: input.allow_host_test, - shell_on_failure: input.shell_on_failure, + shell_on_failure, distro: input.distro, config, driver_overrides: input.driver_overrides, @@ -95,7 +97,7 @@ mod tests { strict: false, changes: None, allow_host_test: false, - shell_on_failure: false, + shell_on_failure: None, distro: None, driver_overrides: DriverOverrides { apt_mirror: None, @@ -136,7 +138,7 @@ mod tests { fn resolve_passes_through_shell_on_failure() -> anyhow::Result<()> { let dir = std::env::temp_dir(); let mut input = base_input(dir); - input.shell_on_failure = true; + input.shell_on_failure = Some(true); let intent = resolve_test_intent(input)?; assert!(intent.shell_on_failure);