fix: address verified review findings (completion-target-ref-1)

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-18 17:40:30 +02:00
1 parent 432d139071
commit be3b8a1ced
10 files changed
+166 -34

No files matched your search

+52 -13
View File
@@ -7,6 +7,7 @@ import (
"context"
"errors"
"maps"
"net/url"
"slices"
"strconv"
"strings"
@@ -228,7 +229,21 @@ func (a *application) gitRemotes(ctx context.Context) [][2]string {
func (a *application) completeRemotes(cmd *cobra.Command, _ []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
ctx, cancel := completionContext(cmd)
defer cancel()
return matching(describe(a.gitRemotes(ctx), func(remote [2]string) (string, string) { return remote[0], remote[1] }), toComplete), cobra.ShellCompDirectiveNoFileComp
return matching(describe(a.gitRemotes(ctx), func(remote [2]string) (string, string) { return remote[0], withoutCredentials(remote[1]) }), toComplete), cobra.ShellCompDirectiveNoFileComp
}
// withoutCredentials drops the user info and query of a remote URL, which can embed a password or
// token that the shell would print in its menu. An unparsable URL shows nothing.
func withoutCredentials(raw string) string {
if !strings.Contains(raw, "://") {
return raw // scp-like addresses carry no password.
}
u, err := url.Parse(raw)
if err != nil {
return ""
}
u.User, u.RawQuery, u.Fragment = nil, "", ""
return u.String()
}
// completeLocalBranches completes the branches of the local checkout.
@@ -264,18 +279,25 @@ func (a *application) completeConfig(cmd *cobra.Command, args []string, toComple
return a.completeHosts(cmd, args, toComplete)
case args[0] == "remote":
return a.completeRemotes(cmd, args, toComplete)
case args[0] == "ssh_key":
return completeFiles(cmd, args, toComplete)
}
return matching(configValues[args[0]], toComplete), cobra.ShellCompDirectiveNoFileComp
}
// apiCompletion completes the values that list fetches from the selected instance, except those
// already given. It never prompts, refreshes or retries, and failures complete nothing rather than
// file names.
// apiCompletion completes the values that list fetches from the selected instance. It never
// prompts, refreshes or retries, and failures complete nothing rather than file names.
func (a *application) apiCompletion(requireRepo bool, list func(ctx context.Context, t target, toComplete string) ([]cobra.Completion, error)) cobra.CompletionFunc {
return a.apiCompletionIn("", requireRepo, list)
}
// apiCompletionIn is apiCompletion for the repository that a command argument names, such as the
// one of a run URL; an empty repo selects the repository like any other command.
func (a *application) apiCompletionIn(repo string, requireRepo bool, list func(ctx context.Context, t target, toComplete string) ([]cobra.Completion, error)) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
ctx, cancel := completionContext(cmd)
defer cancel()
t, err := a.completionTarget(ctx, requireRepo)
t, err := a.completionTarget(ctx, repo, requireRepo)
var values []cobra.Completion
if err == nil {
values, err = list(ctx, t, toComplete)
@@ -284,18 +306,14 @@ func (a *application) apiCompletion(requireRepo bool, list func(ctx context.Cont
cobra.CompDebugln("tea: "+err.Error(), false)
return nil, cobra.ShellCompDirectiveNoFileComp
}
values = slices.DeleteFunc(values, func(value cobra.Completion) bool {
name, _, _ := strings.Cut(value, "\t")
return slices.Contains(args, name)
})
return matching(values, toComplete), cobra.ShellCompDirectiveNoFileComp
}
}
// completionTarget resolves an API completion's target like resolve, but never prompts or rotates
// credentials: an expired OAuth token or an encrypted SSH key completes nothing.
func (a *application) completionTarget(ctx context.Context, requireRepo bool) (target, error) {
t, err := a.resolveTarget(ctx, requireRepo, false)
func (a *application) completionTarget(ctx context.Context, repo string, requireRepo bool) (target, error) {
t, err := a.resolveRequest(ctx, targetRequest{requireRepo: requireRepo, repo: repo, repoSource: "argument"})
if err != nil {
return t, err
}
@@ -515,19 +533,27 @@ func (a *application) completeVariables(scope func() services.ActionScope) cobra
// actionScope applies the target's repository to a scope without organization or account.
func actionScope(scope func() services.ActionScope, t target) services.ActionScope {
selected := scope()
if selected.Organization == "" && !selected.Account {
if inRepository(selected) {
selected.Repository = t.Repo
}
return selected
}
// inRepository reports whether the scope is the repository's, which discovery must then select.
func inRepository(scope services.ActionScope) bool {
return scope.Organization == "" && !scope.Account
}
// pathFlags take local file paths, like every flag whose name ends in -file.
var pathFlags = []string{"asset", "attachment", "file", "input", "ssh-key"}
var pathFlags = []string{"asset", "attachment", "file", "input", "output", "ssh-key"}
// completeDefaults completes paths only where a command takes them: path flags and flags marked
// with MarkFlagFilename. Everything else without a completer completes nothing, by the root's
// default directive, rather than file names.
func completeDefaults(cmd *cobra.Command) {
if cmd.ValidArgsFunction != nil {
cmd.ValidArgsFunction = withoutGiven(cmd.ValidArgsFunction)
}
for _, flags := range []*pflag.FlagSet{cmd.Flags(), cmd.PersistentFlags()} {
flags.VisitAll(func(flag *pflag.Flag) {
if _, registered := cmd.GetFlagCompletionFunc(flag.Name); registered {
@@ -546,6 +572,19 @@ func completeDefaults(cmd *cobra.Command) {
}
}
// withoutGiven drops the positional completions that the arguments already name. Flag values are not
// filtered: Cobra passes the positional arguments to their completers as well, and a job ID may equal
// its run ID.
func withoutGiven(complete cobra.CompletionFunc) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
values, directive := complete(cmd, args, toComplete)
return slices.DeleteFunc(values, func(value cobra.Completion) bool {
name, _, _ := strings.Cut(value, "\t")
return slices.Contains(args, name)
}), directive
}
}
// completeFiles leaves the completion of file paths to the shell.
func completeFiles(*cobra.Command, []string, string) ([]cobra.Completion, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveDefault