From f1b8fe152766d633183d3d8a7b23d9da41bc729b Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 28 Apr 2025 18:18:36 +0200 Subject: [PATCH 1/8] Simpler top-level context detection for fish completions. Previously, completions checked against all levels of subcommands. This change has it look only for top-level commands, which must necessarily be present before their children. It also adds hidden top-level commands to the list. --- fish.go | 21 ++++++++++++--------- testdata/expected-fish-full.fish | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fish.go b/fish.go index b1086ebc9e..4407fceb9b 100644 --- a/fish.go +++ b/fish.go @@ -30,16 +30,15 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { if err != nil { return err } - allCommands := []string{} // Add global flags - completions := cmd.prepareFishFlags(cmd.VisibleFlags(), allCommands) + completions := cmd.prepareFishFlags(cmd.VisibleFlags(), []string{}) // Add help flag if !cmd.HideHelp { completions = append( completions, - cmd.prepareFishFlags([]Flag{HelpFlag}, allCommands)..., + cmd.prepareFishFlags([]Flag{HelpFlag}, []string{})..., ) } @@ -47,24 +46,29 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { if !cmd.HideVersion { completions = append( completions, - cmd.prepareFishFlags([]Flag{VersionFlag}, allCommands)..., + cmd.prepareFishFlags([]Flag{VersionFlag}, []string{})..., ) } // Add commands and their flags completions = append( completions, - cmd.prepareFishCommands(cmd.VisibleCommands(), &allCommands, []string{})..., + cmd.prepareFishCommands(cmd.VisibleCommands(), []string{})..., ) + toplevelCommandNames := []string{} + for _, child := range cmd.Commands { + toplevelCommandNames = append(toplevelCommandNames, child.Names()...) + } + return t.ExecuteTemplate(w, name, &fishCommandCompletionTemplate{ Command: cmd, Completions: completions, - AllCommands: allCommands, + AllCommands: toplevelCommandNames, }) } -func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string { +func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands []string) []string { completions := []string{} for _, command := range commands { var completion strings.Builder @@ -88,7 +92,6 @@ func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]stri ) } - *allCommands = append(*allCommands, command.Names()...) completions = append(completions, completion.String()) completions = append( completions, @@ -100,7 +103,7 @@ func (cmd *Command) prepareFishCommands(commands []*Command, allCommands *[]stri completions = append( completions, cmd.prepareFishCommands( - command.Commands, allCommands, command.Names(), + command.Commands, command.Names(), )..., ) } diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index f586c66fda..25329b4636 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -2,7 +2,7 @@ function __fish_greet_no_subcommand --description 'Test if there has been any subcommand yet' for i in (commandline -opc) - if contains -- $i config c sub-config s ss info i in some-command usage u sub-usage su + if contains -- $i config c info i in some-command hidden-command usage u return 1 end end From 55db2a0b66d452738e508415083263196b792ce2 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 28 Apr 2025 21:50:54 +0200 Subject: [PATCH 2/8] Fish completions need not add their own help commands. --- fish.go | 24 ------------------------ testdata/expected-fish-full.fish | 8 -------- 2 files changed, 32 deletions(-) diff --git a/fish.go b/fish.go index 4407fceb9b..8d7af2797a 100644 --- a/fish.go +++ b/fish.go @@ -34,22 +34,6 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { // Add global flags completions := cmd.prepareFishFlags(cmd.VisibleFlags(), []string{}) - // Add help flag - if !cmd.HideHelp { - completions = append( - completions, - cmd.prepareFishFlags([]Flag{HelpFlag}, []string{})..., - ) - } - - // Add version flag - if !cmd.HideVersion { - completions = append( - completions, - cmd.prepareFishFlags([]Flag{VersionFlag}, []string{})..., - ) - } - // Add commands and their flags completions = append( completions, @@ -84,14 +68,6 @@ func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands [] " -d '%s'", escapeSingleQuotes(command.Usage)) } - - if !command.HideHelp { - completions = append( - completions, - cmd.prepareFishFlags([]Flag{HelpFlag}, command.Names())..., - ) - } - completions = append(completions, completion.String()) completions = append( completions, diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index 25329b4636..42aee6d188 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -14,24 +14,16 @@ complete -c greet -n '__fish_greet_no_subcommand' -f -l flag -s fl -s f -r complete -c greet -n '__fish_greet_no_subcommand' -f -l another-flag -s b -d 'another usage text' complete -c greet -n '__fish_greet_no_subcommand' -l logfile -r complete -c greet -n '__fish_greet_no_subcommand' -l foofile -r -complete -c greet -n '__fish_greet_no_subcommand' -f -l help -s h -d 'show help' -complete -c greet -n '__fish_greet_no_subcommand' -f -l version -s v -d 'print the version' -complete -c greet -n '__fish_seen_subcommand_from config c' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'config c' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from config c' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from config c' -f -l another-flag -s b -d 'another usage text' -complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss' -a 'sub-config s ss' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-flag -s sub-fl -s s -r complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-command-flag -s s -d 'some usage text' -complete -c greet -n '__fish_seen_subcommand_from info i in' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'info i in' -d 'retrieve generic information' -complete -c greet -n '__fish_seen_subcommand_from some-command' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'some-command' -complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage u' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text' -complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l help -s h -d 'show help' complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su' -a 'sub-usage su' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l sub-command-flag -s s -d 'some usage text' From 66d871f8b5bf2b55bcbf72f70b81eba421eca602 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 28 Apr 2025 22:38:16 +0200 Subject: [PATCH 3/8] Fish completions for commands and flags inside hidden command. --- command_test.go | 26 +++++++++++++++++++++++++- fish.go | 28 +++++++++++++++------------- testdata/expected-fish-full.fish | 1 + 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/command_test.go b/command_test.go index b44ed07932..f346294339 100644 --- a/command_test.go +++ b/command_test.go @@ -98,6 +98,11 @@ func buildExtendedTestCommand() *Command { }, { Name: "hidden-command", Hidden: true, + Flags: []Flag{ + &BoolFlag{ + Name: "completable", + }, + }, }, { Aliases: []string{"u"}, Flags: []Flag{ @@ -4876,7 +4881,26 @@ func TestJSONExportCommand(t *testing.T) { "defaultCommand": "", "category": "", "commands": null, - "flags": null, + "flags": [ + { + "name": "completable", + "category": "", + "defaultText": "", + "usage": "", + "required": false, + "hidden": false, + "hideDefault": false, + "local": false, + "defaultValue": false, + "aliases": null, + "takesFileArg": false, + "config": { + "Count": null + }, + "onlyOnce": false, + "validateDefaults": false + } + ], "hideHelp": false, "hideHelpCommand": false, "hideVersion": false, diff --git a/fish.go b/fish.go index 8d7af2797a..93d4d4aab1 100644 --- a/fish.go +++ b/fish.go @@ -37,7 +37,7 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { // Add commands and their flags completions = append( completions, - cmd.prepareFishCommands(cmd.VisibleCommands(), []string{})..., + cmd.prepareFishCommands(cmd.Commands, []string{})..., ) toplevelCommandNames := []string{} @@ -55,20 +55,22 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands []string) []string { completions := []string{} for _, command := range commands { - var completion strings.Builder - fmt.Fprintf(&completion, - "complete -x -c %s -n '%s' -a '%s'", - cmd.Name, - cmd.fishSubcommandHelper(previousCommands, commands), - strings.Join(command.Names(), " "), - ) - - if command.Usage != "" { + if !command.Hidden { + var completion strings.Builder fmt.Fprintf(&completion, - " -d '%s'", - escapeSingleQuotes(command.Usage)) + "complete -x -c %s -n '%s' -a '%s'", + cmd.Name, + cmd.fishSubcommandHelper(previousCommands, commands), + strings.Join(command.Names(), " "), + ) + + if command.Usage != "" { + fmt.Fprintf(&completion, + " -d '%s'", + escapeSingleQuotes(command.Usage)) + } + completions = append(completions, completion.String()) } - completions = append(completions, completion.String()) completions = append( completions, cmd.prepareFishFlags(command.VisibleFlags(), command.Names())..., diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index 42aee6d188..eb29d69b0d 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -22,6 +22,7 @@ complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-fla complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-command-flag -s s -d 'some usage text' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'info i in' -d 'retrieve generic information' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'some-command' +complete -c greet -n '__fish_seen_subcommand_from hidden-command' -f -l completable complete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage u' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text' From 9de83fa9fe6be9a9cac74f1f1e83fd92c010c514 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 5 May 2025 20:42:39 +0200 Subject: [PATCH 4/8] Fish completion presents only the canonical name of suggested command. --- fish.go | 2 +- testdata/expected-fish-full.fish | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fish.go b/fish.go index 93d4d4aab1..dcfe2087b6 100644 --- a/fish.go +++ b/fish.go @@ -61,7 +61,7 @@ func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands [] "complete -x -c %s -n '%s' -a '%s'", cmd.Name, cmd.fishSubcommandHelper(previousCommands, commands), - strings.Join(command.Names(), " "), + command.Name, ) if command.Usage != "" { diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index eb29d69b0d..2c07007b6c 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -14,17 +14,17 @@ complete -c greet -n '__fish_greet_no_subcommand' -f -l flag -s fl -s f -r complete -c greet -n '__fish_greet_no_subcommand' -f -l another-flag -s b -d 'another usage text' complete -c greet -n '__fish_greet_no_subcommand' -l logfile -r complete -c greet -n '__fish_greet_no_subcommand' -l foofile -r -complete -x -c greet -n '__fish_greet_no_subcommand' -a 'config c' -d 'another usage test' +complete -x -c greet -n '__fish_greet_no_subcommand' -a 'config' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from config c' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from config c' -f -l another-flag -s b -d 'another usage text' -complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss' -a 'sub-config s ss' -d 'another usage test' +complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss' -a 'sub-config' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-flag -s sub-fl -s s -r complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-command-flag -s s -d 'some usage text' -complete -x -c greet -n '__fish_greet_no_subcommand' -a 'info i in' -d 'retrieve generic information' +complete -x -c greet -n '__fish_greet_no_subcommand' -a 'info' -d 'retrieve generic information' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'some-command' complete -c greet -n '__fish_seen_subcommand_from hidden-command' -f -l completable -complete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage u' -d 'standard usage text' +complete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text' -complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su' -a 'sub-usage su' -d 'standard usage text' +complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su' -a 'sub-usage' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l sub-command-flag -s s -d 'some usage text' From 86cbfed30aac073b492f008c4234765cf3703f65 Mon Sep 17 00:00:00 2001 From: Bittrance Date: Mon, 5 May 2025 20:34:17 +0200 Subject: [PATCH 5/8] Fish completion tests now include command setup. This allows the completions to depend on parent-child relations, making several method signatures simpler. --- fish.go | 52 +++++++++++++++----------------- fish_test.go | 1 + testdata/expected-fish-full.fish | 18 +++++++++-- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/fish.go b/fish.go index dcfe2087b6..481b665e85 100644 --- a/fish.go +++ b/fish.go @@ -32,12 +32,12 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { } // Add global flags - completions := cmd.prepareFishFlags(cmd.VisibleFlags(), []string{}) + completions := prepareFishFlags(cmd.Name, cmd) // Add commands and their flags completions = append( completions, - cmd.prepareFishCommands(cmd.Commands, []string{})..., + prepareFishCommands(cmd.Name, cmd)..., ) toplevelCommandNames := []string{} @@ -52,15 +52,16 @@ func (cmd *Command) writeFishCompletionTemplate(w io.Writer) error { }) } -func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands []string) []string { +func prepareFishCommands(binary string, parent *Command) []string { + commands := parent.Commands completions := []string{} for _, command := range commands { if !command.Hidden { var completion strings.Builder fmt.Fprintf(&completion, "complete -x -c %s -n '%s' -a '%s'", - cmd.Name, - cmd.fishSubcommandHelper(previousCommands, commands), + binary, + fishSubcommandHelper(binary, parent, commands), command.Name, ) @@ -73,31 +74,28 @@ func (cmd *Command) prepareFishCommands(commands []*Command, previousCommands [] } completions = append( completions, - cmd.prepareFishFlags(command.VisibleFlags(), command.Names())..., + prepareFishFlags(binary, command)..., ) // recursively iterate subcommands - if len(command.Commands) > 0 { - completions = append( - completions, - cmd.prepareFishCommands( - command.Commands, command.Names(), - )..., - ) - } + completions = append( + completions, + prepareFishCommands(binary, command)..., + ) } return completions } -func (cmd *Command) prepareFishFlags(flags []Flag, previousCommands []string) []string { +func prepareFishFlags(binary string, owner *Command) []string { + flags := owner.VisibleFlags() completions := []string{} for _, f := range flags { completion := &strings.Builder{} fmt.Fprintf(completion, "complete -c %s -n '%s'", - cmd.Name, - cmd.fishFlagHelper(previousCommands), + binary, + fishFlagHelper(binary, owner), ) fishAddFileFlag(f, completion) @@ -146,28 +144,28 @@ func fishAddFileFlag(flag Flag, completion *strings.Builder) { completion.WriteString(" -f") } -func (cmd *Command) fishSubcommandHelper(allCommands []string, siblings []*Command) string { - fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", cmd.Name) - if len(allCommands) > 0 { +func fishSubcommandHelper(binary string, command *Command, siblings []*Command) string { + fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", binary) + if len(command.Lineage()) > 1 { var siblingNames []string - for _, command := range siblings { - siblingNames = append(siblingNames, command.Names()...) + for _, sibling := range siblings { + siblingNames = append(siblingNames, sibling.Names()...) } fishHelper = fmt.Sprintf( "__fish_seen_subcommand_from %s; and not __fish_seen_subcommand_from %s", - strings.Join(allCommands, " "), + strings.Join(command.Names(), " "), strings.Join(siblingNames, " "), ) } return fishHelper } -func (cmd *Command) fishFlagHelper(allCommands []string) string { - fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", cmd.Name) - if len(allCommands) > 0 { +func fishFlagHelper(binary string, command *Command) string { + fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", binary) + if len(command.Lineage()) > 1 { fishHelper = fmt.Sprintf( "__fish_seen_subcommand_from %s", - strings.Join(allCommands, " "), + strings.Join(command.Names(), " "), ) } return fishHelper diff --git a/fish_test.go b/fish_test.go index 0a5dfb7f55..492b516b75 100644 --- a/fish_test.go +++ b/fish_test.go @@ -19,6 +19,7 @@ func TestFishCompletion(t *testing.T) { Name: "foofile", TakesFile: true, }) + cmd.setupCommandGraph() oldTemplate := FishCompletionTemplate defer func() { FishCompletionTemplate = oldTemplate }() diff --git a/testdata/expected-fish-full.fish b/testdata/expected-fish-full.fish index 2c07007b6c..e02a659efb 100644 --- a/testdata/expected-fish-full.fish +++ b/testdata/expected-fish-full.fish @@ -17,14 +17,28 @@ complete -c greet -n '__fish_greet_no_subcommand' -l foofile -r complete -x -c greet -n '__fish_greet_no_subcommand' -a 'config' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from config c' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from config c' -f -l another-flag -s b -d 'another usage text' -complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss' -a 'sub-config' -d 'another usage test' +complete -c greet -n '__fish_seen_subcommand_from config c' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss help h' -a 'sub-config' -d 'another usage test' complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-flag -s sub-fl -s s -r complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l sub-command-flag -s s -d 'some usage text' +complete -c greet -n '__fish_seen_subcommand_from sub-config s ss' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from sub-config s ss; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command' +complete -x -c greet -n '__fish_seen_subcommand_from config c; and not __fish_seen_subcommand_from sub-config s ss help h' -a 'help' -d 'Shows a list of commands or help for one command' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'info' -d 'retrieve generic information' +complete -c greet -n '__fish_seen_subcommand_from info i in' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from info i in; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'some-command' +complete -c greet -n '__fish_seen_subcommand_from some-command' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from some-command; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command' complete -c greet -n '__fish_seen_subcommand_from hidden-command' -f -l completable +complete -c greet -n '__fish_seen_subcommand_from hidden-command' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from hidden-command; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command' complete -x -c greet -n '__fish_greet_no_subcommand' -a 'usage' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text' -complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su' -a 'sub-usage' -d 'standard usage text' +complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su help h' -a 'sub-usage' -d 'standard usage text' complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l sub-command-flag -s s -d 'some usage text' +complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l help -s h -d 'show help' +complete -x -c greet -n '__fish_seen_subcommand_from sub-usage su; and not __fish_seen_subcommand_from help h' -a 'help' -d 'Shows a list of commands or help for one command' +complete -x -c greet -n '__fish_seen_subcommand_from usage u; and not __fish_seen_subcommand_from sub-usage su help h' -a 'help' -d 'Shows a list of commands or help for one command' From ac40eb5c18f7ca8b4fb205e7fe6b47e5cf0bf661 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 09:30:01 +0800 Subject: [PATCH 6/8] chore(deps): bump golangci/golangci-lint-action from 7 to 8 (#2123) Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 7 to 8. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](https://github.com/golangci/golangci-lint-action/compare/v7...v8) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index df83344481..31de0895fd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,6 +27,6 @@ jobs: go-version: stable - name: Run golangci-lint - uses: golangci/golangci-lint-action@v7 + uses: golangci/golangci-lint-action@v8 with: version: latest From cf14b66ff7e4ecb7b4cfaf93cd704e612f38c6a0 Mon Sep 17 00:00:00 2001 From: Nicholas Jackson Date: Fri, 9 May 2025 18:03:58 -0700 Subject: [PATCH 7/8] fix: off-by-one in timestamp parsing Timestamps without dates would infer the correct date based on the local time. This can lead to bugs where the current local date is different than the date in the timezone of the original value. Fix this by using time.Now().In() to adjust the timezone. --- flag_timestamp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flag_timestamp.go b/flag_timestamp.go index f442951929..413a2f0e48 100644 --- a/flag_timestamp.go +++ b/flag_timestamp.go @@ -86,7 +86,7 @@ func (t *timestampValue) Set(value string) error { defaultTS, _ := time.ParseInLocation(time.TimeOnly, time.TimeOnly, timestamp.Location()) - n := time.Now() + n := time.Now().In(timestamp.Location()) // If format is missing date (or year only), set it explicitly to current if timestamp.Truncate(time.Hour*24).UnixNano() == defaultTS.Truncate(time.Hour*24).UnixNano() { From d6d1fe5b4acea05167e9608f42fdae4467116bc0 Mon Sep 17 00:00:00 2001 From: Naveen Gogineni Date: Sat, 10 May 2025 19:53:57 -0400 Subject: [PATCH 8/8] Fix docs --- docs/go.mod | 10 +++++----- docs/go.sum | 5 +++++ docs/v3/examples/flags/value-sources.md | 6 ++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/go.mod b/docs/go.mod index b53a2b002e..08fbe8bbed 100644 --- a/docs/go.mod +++ b/docs/go.mod @@ -1,16 +1,16 @@ module github.com/urfave/cli/docs/v3 -go 1.18 +go 1.23.2 replace github.com/urfave/cli/v3 => ../ require ( - github.com/urfave/cli-altsrc/v3 v3.0.0-alpha2 - github.com/urfave/cli/v3 v3.0.0-alpha9 + github.com/urfave/cli-altsrc/v3 v3.0.1 + github.com/urfave/cli/v3 v3.1.1 ) require ( - github.com/BurntSushi/toml v1.3.2 // indirect - github.com/stretchr/testify v1.9.0 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/stretchr/testify v1.10.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/docs/go.sum b/docs/go.sum index 7c5c22143a..a36c208bb8 100644 --- a/docs/go.sum +++ b/docs/go.sum @@ -1,13 +1,18 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli-altsrc/v3 v3.0.0-alpha2 h1:j4SaBpPB8++L0c0KuTnz/Yus3UQoWJ54hQjhIMW8rCM= github.com/urfave/cli-altsrc/v3 v3.0.0-alpha2/go.mod h1:Q79oyIY/z4jtzIrKEK6MUeWC7/szGr46x4QdOaOAIWc= +github.com/urfave/cli-altsrc/v3 v3.0.1 h1:v+gHk59syLk8ao9rYybZs43+D5ut/gzj0omqQ1XYl8k= +github.com/urfave/cli-altsrc/v3 v3.0.1/go.mod h1:8UtsKKcxFVzvaoySFPfvQOk413T+IXJhaCWyyoPW3yM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/docs/v3/examples/flags/value-sources.md b/docs/v3/examples/flags/value-sources.md index a7e5ee1a81..f9d588db7a 100644 --- a/docs/v3/examples/flags/value-sources.md +++ b/docs/v3/examples/flags/value-sources.md @@ -159,6 +159,7 @@ import ( "github.com/urfave/cli/v3" "github.com/urfave/cli-altsrc/v3" + yaml "github.com/urfave/cli-altsrc/v3/yaml" ) func main() { @@ -168,7 +169,7 @@ func main() { Name: "password", Aliases: []string{"p"}, Usage: "password for the mysql database", - Sources: altsrc.YAML("somekey", altsrc.StringSourcer("/path/to/filename")), + Sources: cli.NewValueSourceChain(yaml.YAML("somekey", altsrc.StringSourcer("/path/to/filename"))), }, }, } @@ -193,6 +194,7 @@ import ( "github.com/urfave/cli/v3" "github.com/urfave/cli-altsrc/v3" + yaml "github.com/urfave/cli-altsrc/v3/yaml" ) func main() { @@ -210,7 +212,7 @@ func main() { Name: "password", Aliases: []string{"p"}, Usage: "password for the mysql database", - Sources: altsrc.YAML("somekey", altsrc.NewStringPtrSourcer(&filename)), + Sources: cli.NewValueSourceChain(yaml.YAML("somekey", altsrc.NewStringPtrSourcer(&filename))), }, }, }