Skip to content

Version-check banner is written to stdout in PersistentPostRun, corrupting generated shell completions #9028

@stv-io

Description

@stv-io

Summary

The "new release available" version-check banner is emitted via logrus.Infof to stdout, and the check runs in rootCmd.PersistentPostRun, which executes after every subcommand — including completion. As a result, when shell completions are generated (e.g. updatecli completion bash), the banner is captured into the completion script itself, producing an invalid file that breaks the user's shell on startup.

This is especially impactful for the Homebrew formula, which generates completions at install time. End users get a broken bash completion file and a syntax error on every new shell.

Version

  • updatecli v0.117.1 (latest release at time of writing)
  • Reproduced via the Homebrew-generated completion; the relevant code on main is unchanged.

Steps to reproduce

$ updatecli completion bash > updatecli.bash
$ tail -n 3 updatecli.bash
# ex: ts=4 sw=4 et filetype=sh
| A new release is available: "unknown" -> "v0.117.0"
| More information on https://www.updatecli.io/changelogs/updatecli/changelogs/v0.117.0/
$ bash -n updatecli.bash
updatecli.bash: line 427: syntax error near unexpected token `|'

When this file is installed as a bash completion (e.g. under /opt/homebrew/etc/bash_completion.d/), every new shell prints:

bash: /opt/homebrew/etc/bash_completion.d/updatecli: line 427: syntax error near unexpected token `|'
bash: /opt/homebrew/etc/bash_completion.d/updatecli: line 427: `| A new release is available: "unknown" -> "v0.117.0"'

Root cause

  1. cmd/root.go calls logrus.SetOutput(os.Stdout), so info-level logs (including the version banner) go to stdout rather than stderr.
  2. The version check is wired into rootCmd.PersistentPostRun, so it runs for all subcommands, including completion / __complete / docs / man:
    rootCmd.PersistentPostRun = func(cmd *cobra.Command, args []string) {
        err := engine.CheckLatestPublishedVersion()
        ...
    }
  3. CheckLatestPublishedVersion() in pkg/core/engine/version.go emits the banner with logrus.Infof("| A new release is available..."), which therefore lands on stdout and is captured by any command that redirects stdout (such as completion/doc generation).

Suggested fixes (any one, ideally a combination)

  • Route the banner to stderr. Informational/diagnostic output should not pollute stdout, which is reserved for the command's actual output (the completion script, generated docs, etc.).
  • Skip the version check for non-interactive/generator commands in PersistentPostRun — e.g. completion, __complete, __completeNoDesc, docs, man, jsonschema.
  • Add an opt-out env var / flag, e.g. UPDATECLI_DISABLE_VERSION_CHECK (mirroring the existing UPDATECLI_DISABLE_CHANGELOG), so it can be disabled in CI and by packagers.

Impact / workarounds

  • Affects anyone generating completions or docs from a release binary; Homebrew users hit it automatically.
  • Current workaround is to strip the banner from generated output, e.g. updatecli completion bash | sed '/^| /d', or manually delete the trailing | ... lines from the installed completion file. This does not survive package upgrades.

Happy to open a PR if a preferred direction is confirmed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions