Skip to content

Add global --quiet, --no-input, and --yes flags#4726

Open
simonfaltum wants to merge 14 commits intomainfrom
simonfaltum/global-interaction-flags
Open

Add global --quiet, --no-input, and --yes flags#4726
simonfaltum wants to merge 14 commits intomainfrom
simonfaltum/global-interaction-flags

Conversation

@simonfaltum
Copy link
Member

@simonfaltum simonfaltum commented Mar 12, 2026

Why

CLI users in CI/CD pipelines and scripts need control over the CLI's interactive behavior. Currently there's no way to suppress progress output, prevent prompts from blocking automation, or auto-approve confirmations without per-command flags.

Changes

Before: No global flags for controlling output verbosity, interactivity, or confirmations. Scripts had to work around interactive prompts.
Now: Three new global flags on the root command, stored in the cmdio Capabilities struct alongside existing TTY detection:

  • --quiet / -q (env: DATABRICKS_QUIET): Suppresses non-essential output. Spinners become no-ops, LogString/Log calls are silenced, and only Error-severity diagnostics render. Data output (stdout) is never affected.
  • --no-input (env: DATABRICKS_NO_INPUT): Disables all interactive prompts. Prompt functions return ErrNoInput (or the default value if one exists).
  • --yes / -y (env: DATABRICKS_YES): Auto-approves all yes/no confirmation prompts. Precedence: --yes (approve) > --no-input (error) > normal prompting. Non-interactive guards in deploy/destroy/completion/bind are updated to also check --yes.

apps import already had its own local -q/--quiet flag that suppresses informational messages during import. The two flags are bridged: passing the global --quiet also sets the local quiet behavior in apps import, and passing the local -q on apps import also activates the global cmdio quiet mode (suppressing spinners, etc.). Both flags continue to work as before.

Post-review fixes

  • Gate promptForProfile in cmd/auth/login.go on --no-input (was only checking IsPromptSupported)
  • Gate profile selection prompt in cmd/root/bundle.go on --no-input
  • Improve logout error message: "prompting is disabled" instead of "non-interactive mode" (accurate for both TTY detection and explicit --no-input)
  • Add HasError() early return in RenderDiagnostics quiet mode to avoid unnecessary allocation
  • Add doc comment on Prompt() noting callers must check IsNoInput(ctx) before calling Run()

Open items

  • API field deny list: The flag names quiet, no_input, yes should be added to a global reject list for top-level field names in auto-generated API commands, so future API parameters don't collide with these global flags. This needs a change in the codegen pipeline (or universe API linters), tracked separately.
  • I/O completeness audit: All output in the CLI currently goes through cmdio (LogString, Log, Render, spinners). A follow-up could add a lint rule or test verifying no direct fmt.Fprintf(os.Stderr, ...) calls bypass cmdio, so --quiet is truly global.
  • Broader --no-input audit: ~25 other IsPromptSupported call sites in the codebase don't check --no-input. A follow-up could fold noInput into SupportsPrompt() so all prompt paths automatically respect --no-input.

Test plan

  • Unit tests for all gated functions (LogString, Log, spinner, diagnostics, Ask, AskYesOrNo, AskSelect, Select, Secret, RunSelect)
  • Unit tests for flag precedence (--yes > --no-input > normal)
  • Unit tests for env var support (DATABRICKS_QUIET, DATABRICKS_NO_INPUT, DATABRICKS_YES)
  • Unit tests for Ask() returning default value when --no-input + default provided
  • Data output (Render) not affected by --quiet
  • Command-level test for --yes wiring through completion install
  • make lintfull passes
  • make checks passes

Add three new global flags to control CLI interaction behavior in
CI/CD pipelines and scripts:

- --quiet/-q (DATABRICKS_QUIET): suppresses non-essential output
  (spinners, LogString/Log calls, non-error diagnostics)
- --no-input (DATABRICKS_NO_INPUT): disables all interactive prompts,
  returning ErrNoInput or default values where available
- --yes/-y (DATABRICKS_YES): auto-approves yes/no confirmation prompts

Precedence for AskYesOrNo: --yes > --no-input > normal prompting.

Non-interactive guards in deploy, destroy, and completion install are
updated to also accept --yes as an alternative to --auto-approve.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot
Copy link
Collaborator

eng-dev-ecosystem-bot commented Mar 12, 2026

Commit: cfe4169

Run: 23165196655

Env ❌​FAIL 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 7 1 9 268 792 10:17
🟨​ aws windows 7 1 9 270 790 8:32
💚​ aws-ucws linux 8 9 365 707 9:16
💚​ aws-ucws windows 8 9 367 705 7:11
💚​ azure linux 2 11 271 790 9:33
🔄​ azure windows 2 11 273 788 7:27
💚​ azure-ucws linux 2 11 370 703 11:08
💚​ azure-ucws windows 2 11 372 701 9:06
💚​ gcp linux 2 11 267 793 8:42
❌​ gcp windows 2 1 1 1 11 266 791 7:53
20 interesting tests: 9 SKIP, 7 KNOWN, 2 FAIL, 2 flaky
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🟨​ TestAccept 🟨​K 🟨​K 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 🟨​K
❌​ TestAccept/bundle/resources/jobs/check-metadata ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
🔄​ TestAccept/bundle/resources/jobs/check-metadata/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p 🔄​f
❌​ TestAccept/bundle/resources/jobs/check-metadata/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ❌​F
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_projects/update_display_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestAccept/ssh/connection 💚​R 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 💚​R
Top 41 slowest tests (at least 2 minutes):
duration env testname
6:04 azure-ucws windows TestAccept/ssh/connection
5:52 aws-ucws linux TestAccept/ssh/connection
5:49 aws-ucws windows TestAccept/ssh/connection
5:27 azure-ucws linux TestAccept/ssh/connection
4:56 aws linux TestAccept/ssh/connection
4:43 aws windows TestAccept/ssh/connection
4:18 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:16 aws linux TestSecretsPutSecretStringValue
4:13 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
4:07 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
4:06 azure-ucws linux TestSecretsPutSecretStringValue
4:03 azure-ucws windows TestSecretsPutSecretStringValue
3:47 azure linux TestAccept/ssh/connection
3:44 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:43 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:28 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:18 azure linux TestSecretsPutSecretStringValue
3:07 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:06 gcp windows TestAccept/ssh/connection
2:50 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:49 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:49 aws windows TestSecretsPutSecretStringValue
2:46 gcp linux TestSecretsPutSecretStringValue
2:45 gcp linux TestAccept/ssh/connection
2:43 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:42 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:42 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:42 azure-ucws linux TestAccept
2:41 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:36 aws-ucws linux TestAccept
2:35 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:34 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:32 gcp windows TestSecretsPutSecretStringValue
2:27 gcp linux TestAccept
2:24 azure linux TestAccept
2:16 azure linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:11 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:06 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:06 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:05 azure windows TestSecretsPutSecretStringValue
2:04 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct

Add --no-input, --quiet, and --yes to all help output golden files.
Update error messages to mention --auto-approve or --yes.

Co-authored-by: Isaac
Copy link
Contributor

@shreyas-goenka shreyas-goenka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This review was posted by Claude (AI assistant). Shreyas will do a separate, more thorough review pass.

Priority: LOW-MEDIUM — Strong implementation with minor issues

LOW: Description casing inconsistency

Flag descriptions use inconsistent casing (some start with uppercase, others lowercase). Minor but worth standardizing.

LOW: tools/gofumpt artifact

There appears to be a formatting change from tools/gofumpt mixed into this PR. Consider separating formatting-only changes.

What looks good

  • Clean implementation of --quiet, --no-input, and --yes flags
  • Good integration with existing cmdio capabilities system
  • Proper propagation through the command tree
  • Well-structured capability checks
  • Correct interaction between the three flags

Overall a solid PR. The issues are minor.

Use env.GetBool for the global interaction flags and derive new cmdio contexts when quiet, no-input, or yes is enabled so commands do not mutate shared I/O state.
…ands

Fix four issues with the global interaction flags:

1. configure: check IsNoInput alongside IsPromptSupported so --no-input
   correctly routes to the non-interactive path.

2. auth prompts: add IsNoInput checks to promptForHost, promptForAccountID,
   and promptForWorkspaceID so --no-input prevents raw promptui prompts.

3. logout: allow --yes to bypass the prompt-supported guard so
   AskYesOrNo can auto-approve in non-interactive environments.

4. apps import: remove local --quiet flag that shadowed the root
   persistent --quiet, and read from cmdio.IsQuiet(ctx) instead.

Also revert the unrelated tools/gofumpt addition to .gitignore.
promptForProfile (login), resolveProfileAmbiguity (bundle), and
the logout profile picker all check IsPromptSupported but did not
check IsNoInput. On an interactive terminal with --no-input these
functions would still show a prompt. Add the missing guard.

Also rephrase the logout error from "non-interactive environment"
to "prompting is disabled" so the message is accurate for both
non-interactive terminals and explicit --no-input usage.

Co-authored-by: Isaac
In quiet mode, skip the allocation of errorsOnly slice when there
are no errors. Add a doc comment to Prompt() noting that callers
must check IsNoInput themselves.

Co-authored-by: Isaac
libs/cmdio/io.go Outdated
Comment on lines +99 to +100
teaProgram: c.teaProgram,
teaDone: c.teaDone,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're shallow cloning teaProgram but not reusing its mutex. A cloned cmdIO instance with a different mutex can race on teaProgram and teaDone with the original

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye on the mutex, but I think this is safe as-is. clone() is only called from withCapabilities(), which is only called from SetQuiet/SetNoInput/SetYes. These run once during flag initialization in PersistentPreRunE, before any spinner or Bubble Tea program is ever started. At that point both teaProgram and teaDone are nil.

After the clone, the new cmdIO replaces the old one in the context (InContext(ctx, c)), and nobody holds a reference to the old instance anymore. So there's no window where two cmdIO instances with separate mutexes are concurrently operating on the same tea state.

That said, copying nil fields that we never actually need is a bit misleading. I'll remove the teaProgram and teaDone lines from clone() to make the intent clearer (they're always nil at clone time, so no behavioral change).

These fields are always nil at clone time (clone only runs during flag
init, before any Bubble Tea program starts). Removing them makes it
clear the clone does not share tea lifecycle state with the original.

Co-authored-by: Isaac
Copy link
Contributor

@shreyas-goenka shreyas-goenka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: --quiet. We already have the --log-level flag. Worth looking into whether we should repurpose it or a new flag is warrented.

re: --no-input, what's the usecase? Today the CLI dynamically detects whether interactive input is possible and errors when that is not supported (like in CI)

re: --yes. We use the --auto-approve flag in other contexts. Let's not add a new --yes flag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants