Skip to content

fix: keep completion subcommand order deterministic in help output#2374

Open
suzuki-shunsuke wants to merge 2 commits into
mainfrom
fix/completion-subcommand-order
Open

fix: keep completion subcommand order deterministic in help output#2374
suzuki-shunsuke wants to merge 2 commits into
mainfrom
fix/completion-subcommand-order

Conversation

@suzuki-shunsuke

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • bug

What this PR does / why we need it:

The completion command exposes each shell as its own subcommand (bash, zsh, fish, pwsh), introduced in #2279 (released in v3.9.1). The subcommands were generated by ranging over the shellCompletions map in buildCompletionCommand:

for shell, render := range shellCompletions {
    cmd.Commands = append(cmd.Commands, buildShellCompletionSubcommand(shell, render, appName))
}

Go randomizes map iteration order per process, so the order of these subcommands — and therefore the COMMANDS: section of completion --help — changed between runs. This breaks downstream projects that generate documentation from --help output and commit it via CI: the generated docs flip-flop depending on which run produced them, creating spurious diffs and noise commits. Real-world impact: suzuki-shunsuke/ghtkn#454

Changes:

  • completion.go: add completionShells = []string{"bash", "zsh", "fish", "pwsh"}, an explicitly ordered list of the supported shells, and iterate it (looking the renderer up in shellCompletions) instead of ranging over the map. The map stays as the renderer registry; the slice fixes the display order. The order is now deterministic on every run.
  • completion_test.go: add TestCompletionSubcommandOrder, which asserts the subcommand order is always bash, zsh, fish, pwsh and that every shell in shellCompletions is also present in completionShells (so the two cannot silently drift). TestCompletionShellRenderError and TestCompletionShellWriteError inject a custom shell into shellCompletions; they now also register it in completionShells (with restore) so the injected shell still becomes a subcommand.

Which issue(s) this PR fixes:

Fixes #2373

Special notes for your reviewer:

The display order is fixed to bash, zsh, fish, pwsh. If you would prefer alphabetical order instead, that is a one-line change to completionShells.

Testing

  • go test ./... passes.
  • The completion tests are stable across repeated go test invocations (separate processes), where the subcommand order previously varied.

Release Notes

Fix non-deterministic ordering of `completion` shell subcommands in help output; they now always appear as bash, zsh, fish, pwsh.

suzuki-shunsuke and others added 2 commits June 26, 2026 19:31
The completion command exposes each shell (bash, zsh, fish, pwsh) as a
subcommand. These were generated by ranging over the shellCompletions
map, whose iteration order Go randomizes per process. As a result the
order of subcommands in `completion --help` changed between runs, which
broke downstream projects that generate and commit documentation from
--help output.

Iterate over an explicitly ordered slice of shell names so the listing
is stable (bash, zsh, fish, pwsh) on every run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@suzuki-shunsuke suzuki-shunsuke marked this pull request as ready for review June 26, 2026 10:41
@suzuki-shunsuke suzuki-shunsuke requested a review from a team as a code owner June 26, 2026 10:41
Comment thread completion.go
// subcommands appear in help output. Iterating shellCompletions directly
// would use Go's randomized map order, making the listing nondeterministic.
// Keep this in sync with shellCompletions.
completionShells = []string{"bash", "zsh", "fish", "pwsh"}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it possible to get sorted list instead of maintaining hardcoded indexes?

@suzuki-shunsuke suzuki-shunsuke Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In case of the dictionary order, the order is changed.

  1. bash
  2. fish
  3. pwsh
  4. zsh

Is that okay?

I think the current order is more natural.

  1. bash
  2. zsh
  3. fish
  4. pwsh

https://cli.urfave.org/v3/examples/completions/shell-completions/

image

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.

completion subcommands appear in non-deterministic order in help output

2 participants