From 9b4b85725d7cfedf0451a4cbe001eafaeb3d7bab Mon Sep 17 00:00:00 2001 From: Martin Kuntz Jacobsen Date: Mon, 9 Nov 2026 16:45:59 +0100 Subject: [PATCH 1/2] dx: quiet Bazel progress when stdout is not a terminal (part of #10040) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Xut2hwESun1HL2eSVd1d5B --- cli/cli/src/main.rs | 3 ++- cli/plan/src/args/invocation.rs | 20 +++++++++++++++++--- cli/plan/src/args/parser.rs | 1 + docs/cli/commands/build-test-coverage.md | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/cli/cli/src/main.rs b/cli/cli/src/main.rs index 76bd478fc..b1a52a1be 100644 --- a/cli/cli/src/main.rs +++ b/cli/cli/src/main.rs @@ -8,7 +8,7 @@ ) )] -use std::io::{self, Write}; +use std::io::{self, IsTerminal, Write}; use std::path::Path; use dx_cli::bazel_restart::{RestartingQueryRunner, RestartingRunner}; @@ -248,6 +248,7 @@ fn run() -> i32 { return usage_error(code, &error.to_string(), json, command); } }; + invocation.piped = !io::stdout().is_terminal(); // LCOV_EXCL_STOP - reason: end thin run shim, issue: 1055, policy: docs/cli/commands/build-test-coverage.md dx_adopt::refresh_stale_pins_from_env(); dx_cli::exec::set_usage_command(invocation.command); diff --git a/cli/plan/src/args/invocation.rs b/cli/plan/src/args/invocation.rs index cbc26eaa4..f9fef306b 100644 --- a/cli/plan/src/args/invocation.rs +++ b/cli/plan/src/args/invocation.rs @@ -334,6 +334,8 @@ pub struct Invocation { pub bench_compare: Option, pub path_only: bool, pub agent: bool, + /// Stdout is not a terminal. + pub piped: bool, pub bazel_startup_options: Vec, } @@ -352,9 +354,10 @@ impl Invocation { self.command == Command::Update && self.targets.len() == 2 && is_version(&self.targets[1]) } - /// Bazel UI flags that silence progress output in agent JSON sessions. + /// Bazel UI flags that silence progress output in agent JSON sessions and piped runs; `-v` keeps Bazel output. pub fn agent_quiet_flags(&self) -> Vec { - if self.agent && self.output == OutputMode::Json { + let agent_json = self.agent && self.output == OutputMode::Json; + if (agent_json || self.piped) && !self.verbose { AGENT_QUIET_FLAGS .iter() .map(|flag| (*flag).to_owned()) @@ -364,7 +367,7 @@ impl Invocation { } } - /// Bazel options for the run: agent JSON sessions get no progress output. + /// Bazel options for the run: agent JSON sessions and piped runs get no progress output. pub fn quiet_bazel_options(&self) -> Vec { let mut options = self.agent_quiet_flags(); options.extend(self.bazel_options.iter().cloned()); @@ -743,6 +746,7 @@ mod tests { bench_compare: None, path_only: false, agent: false, + piped: false, bazel_startup_options: Vec::new(), } } @@ -1117,6 +1121,16 @@ mod tests { AGENT_QUIET_FLAGS.iter().map(ToString::to_string).collect() } + #[test] + fn piped_runs_are_quiet_unless_verbose() { + let mut inv = parsed(&["build"]); + assert!(inv.quiet_bazel_options().is_empty()); + inv.piped = true; + assert_eq!(inv.quiet_bazel_options(), quiet_flags()); + inv.verbose = true; + assert!(inv.quiet_bazel_options().is_empty()); + } + #[test] fn raw_bazel_options_never_carry_agent_quiet_flags() { let session = agent(&["build", "--output=json", "--", "--jobs=4"]); diff --git a/cli/plan/src/args/parser.rs b/cli/plan/src/args/parser.rs index 1d40f507c..fc5a47e94 100644 --- a/cli/plan/src/args/parser.rs +++ b/cli/plan/src/args/parser.rs @@ -747,6 +747,7 @@ fn parse_inner>( bench_compare: compare, path_only, agent, + piped: false, bazel_startup_options, }) } diff --git a/docs/cli/commands/build-test-coverage.md b/docs/cli/commands/build-test-coverage.md index 46fee4956..48a184c30 100644 --- a/docs/cli/commands/build-test-coverage.md +++ b/docs/cli/commands/build-test-coverage.md @@ -46,6 +46,8 @@ dx coverage [--here] [--affected] [--timings] [--min-coverage ] [--min- `--debug` and `--release` conflict. Both change compilation only. +When stdout is not a terminal, dx passes Bazel the quiet flags `--noshow_progress`, `--noshow_loading_progress`, `--noshow_timestamps`, `--curses=no`, `--ui_event_filters=-info,-debug` and `--test_summary=none`. `-v` keeps full Bazel output. + ## Scopes No scope means `//...`. Pass labels, patterns, files, or directories. A file runs its owning targets. For `test` and `coverage`, a file runs the tests that depend on its owners. A `manual` test runs only when it owns the file. From 8a2bc038bf2e9828b405c1e1159f47dda47f94b1 Mon Sep 17 00:00:00 2001 From: Martin Kuntz Jacobsen Date: Mon, 9 Nov 2026 17:19:31 +0100 Subject: [PATCH 2/2] dx: test piped requests carry quiet flags (part of #10040) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Xut2hwESun1HL2eSVd1d5B --- cli/plan/src/args/invocation.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cli/plan/src/args/invocation.rs b/cli/plan/src/args/invocation.rs index f9fef306b..26497a853 100644 --- a/cli/plan/src/args/invocation.rs +++ b/cli/plan/src/args/invocation.rs @@ -1160,6 +1160,20 @@ mod tests { ); } + #[test] + fn piped_requests_carry_quiet_flags_until_verbose() { + let mut inv = parsed(&["generate", "--", "--jobs=4"]); + inv.piped = true; + let mut want = quiet_flags(); + want.push("--jobs=4".to_owned()); + assert_eq!(inv.generate_request().expect("generate").bazel_options, want); + inv.verbose = true; + assert_eq!( + inv.generate_request().expect("generate").bazel_options, + vec!["--jobs=4".to_owned()] + ); + } + #[test] fn agent_quiet_generate_request_puts_quiet_flags_before_the_callers_options() { let generate = agent(&["generate", "--output=json", "--", "--jobs=4"])