Open debankur1 opened 3 years ago
You have to use the flag.Changed
field to reset the flag.
Here is an example: https://github.com/spf13/cobra/blob/4590150168e93f4b017c6e33469e26590ba839df/completions_test.go#L185
I hope this helps.
You have to use the
flag.Changed
field to reset the flag. Here is an example:I hope this helps.
thanks for the quick response, I believe when we execute rootCmd.Execute() then cobra should do it automatically because if I need to set nonPersistentFlag.Changed = false, then I have to do for all the commands and their subcommands
@marckhouzam I tried
var testCmd = &cobra.Command{ Use: "tcmd", Short: "test cmd for cobra command", Run: func(cmd cobra.Command, args []string) { fmt.Println("Hello World") }, PostRun: func(cmd cobra.Command, args []string) { helpFlag := cmd.Flags().Lookup("help") helpFlag.Changed = false }, }
I think we need to take a step back and look at why you would want to do this @debankur1.
The uses of Cobra that I've seen do a single rootCmd.Execute
and then exit, so at each time all the flags start fresh.
What is your scenario that would require you to reset the flags manually?
@marckhouzam The scenario is simple, let us consider user want to use Interactive Shell (https://github.com/abiosoft/ishell)
func main(){ shell := ishell.New() shell.Println("Sample Interactive Shell") shell.AddCmd(&ishell.Cmd{ Name: "test", Help: "Test Command Help", Func: func(c *ishell.Context) { rootCmd.SetArgs(c.RawArgs) rootCmd.Execute() }, }) shell.Run() }
and user wants to run the cobra command from the interactive shell i.e. rootCmd.Execute() , but the problem is rootCmd.Execute() holds a reference to the memory once it is executed that is not correct. This is a pretty valid case where users may like to use the power of Cobra in an interactive way. Maybe post rootCmd.Execute() it should initialize once again so that all the flags are reset or it should behave as if a user is running a new command.
@marckhouzam I have found a workaround to reset the flag (in my case it is help) cmd.Flags().Lookup("help").Value.Set("false"), but the bug remains still valid because flag reset must happen automatically in
func (c Command) ExecuteC() (cmd Command, err error){ }
This issue is being marked as stale due to a long period of inactivity
@marckhouzam I stumbled on the same problem, in my case is in testing. I created a small example to show the problem.
main.go:
package main
import (
"github.com/spf13/cobra"
)
var (
cmd *cobra.Command
shouldContinue bool
)
func init() {
cmd = &cobra.Command{
Use: "debug",
Run: func(cmd *cobra.Command, args []string) {
cmd.Print("Step 1")
if shouldContinue {
cmd.Print("Step 2")
return
}
},
}
cmd.Flags().BoolVar(&shouldContinue, "continue", false, "test")
}
func main() {
cmd.Execute()
}
main_test.go:
package main
import (
"strings"
"testing"
"github.com/g14a/metana/pkg"
"github.com/stretchr/testify/assert"
)
func TestFull(t *testing.T) {
test := []struct {
args []string
output string
}{
{
args: []string{"--continue"},
output: strings.Join([]string{"Step 1", "Step 2"}, ""),
},
{
args: []string{},
output: strings.Join([]string{"Step 1"}, ""),
},
}
for i, tt := range test {
_, out, _ := pkg.ExecuteCommandC(cmd, tt.args...)
t.Log(i, out, tt.args)
assert.NotEmpty(t, out)
assert.Equal(t, tt.output, out)
}
}
PS.: I'm aware that changing the order in this test case would fix the problem, however in complex commands that might no be possible.
I'am facing the same issue in my tests. 😢
I've run into the same thing in my tests. I believe the issue is caused by the way Cobra uses global variables. I've tried rootCmd.ResetCommands()
and rootCmd.ResetFlags()
, but the issue is that flags are persisted in each subcommand, so each subcommand must be reset between. I found a similar issue in Github's CLI package:
https://github.com/cli/cli/issues/759
which has the workaround:
https://github.com/cli/cli/blob/c0c28622bd62b273b32838dfdfa7d5ffc739eeeb/command/pr_test.go#L55-L67
The alternative is to restructure each command into a factory and don't use the magic init()
and global variables, as the associated PR does.
When cobra command is executed via API e.g. rootCmd.Execute() in an interactive mode, it keeps the flags that were persisted from the previous command here are the code snippet and test results.
package main
import ( "bufio" "fmt" "github.com/spf13/cobra" "os" "strings" )
func main() { for { reader := bufio.NewReader(os.Stdin) input, , := reader.ReadLine() args := strings.Split(string(input), " ") rootCmd.SetArgs(args) rootCmd.Execute() fmt.Println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
}
var rootCmd = &cobra.Command{ Use: "cli", Short: "test app to test iShell like usage in cobra",
} var testCmd = &cobra.Command{ Use: "tcmd", Short: "test cmd for cobra command", Run: func(cmd *cobra.Command, args []string) { fmt.Println("Hello World") }, } func init() { rootCmd.AddCommand(testCmd) }
tcmd Hello World &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& tcmd -h test cmd for cobra command
Usage: cli tcmd [flags]
Flags: -h, --help help for tcmd &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& tcmd test cmd for cobra command
Usage: cli tcmd [flags]
Flags: -h, --help help for tcmd &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
As it can be clearly seen that after running the command with a flag -h or --help next time it uses the same flag , instead running the entire command.
Same thing I have testes with iShell
func main(){ shell := ishell.New() shell.Println("Sample Interactive Shell") shell.AddCmd(&ishell.Cmd{ Name: "test", Help: "Test Command Help", Func: func(c *ishell.Context) { rootCmd.SetArgs(c.RawArgs) rootCmd.Execute() }, }) shell.Run() } Have also tried the cmd.RestFlags() it didn't work. Any help is really appreciated.