mirror of
https://github.com/spf13/cobra
synced 2024-11-04 21:07:19 +00:00
Merge 8e2c9596e1
into bd914e58d6
This commit is contained in:
commit
e067c98fad
2 changed files with 93 additions and 6 deletions
|
@ -1058,7 +1058,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
||||||
|
|
||||||
// Regardless of what command execute is called on, run on Root only
|
// Regardless of what command execute is called on, run on Root only
|
||||||
if c.HasParent() {
|
if c.HasParent() {
|
||||||
return c.Root().ExecuteC()
|
return c.Root().ExecuteContextC(c.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// windows hook
|
// windows hook
|
||||||
|
@ -1108,11 +1108,8 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
|
||||||
cmd.commandCalledAs.name = cmd.Name()
|
cmd.commandCalledAs.name = cmd.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to pass global context to children command
|
// Pass context of root command to child command.
|
||||||
// if context is present on the parent command.
|
cmd.ctx = c.ctx
|
||||||
if cmd.ctx == nil {
|
|
||||||
cmd.ctx = c.ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.execute(flags)
|
err = cmd.execute(flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -232,6 +232,96 @@ func TestExecuteContextC(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This tests that the context passed to the root command propagates to its children
|
||||||
|
// not only on the first execution but also subsequent calls.
|
||||||
|
// Calling the same command multiple times is common when testing cobra applications.
|
||||||
|
func TestExecuteContextMultiple(t *testing.T) {
|
||||||
|
var key string
|
||||||
|
|
||||||
|
// Define unique contexts so we can tell them apart below.
|
||||||
|
ctxs := []context.Context{
|
||||||
|
context.WithValue(context.Background(), &key, "1"),
|
||||||
|
context.WithValue(context.Background(), &key, "2"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared reference to the context in the current iteration.
|
||||||
|
var currentCtx context.Context
|
||||||
|
|
||||||
|
ctxRun := func(cmd *Command, args []string) {
|
||||||
|
if cmd.Context() != currentCtx {
|
||||||
|
t.Errorf("Command %q must have context with value %s", cmd.Use, currentCtx.Value(&key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun}
|
||||||
|
childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun}
|
||||||
|
granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun}
|
||||||
|
|
||||||
|
childCmd.AddCommand(granchildCmd)
|
||||||
|
rootCmd.AddCommand(childCmd)
|
||||||
|
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
currentCtx = ctxs[i]
|
||||||
|
|
||||||
|
if _, err := executeCommandWithContext(currentCtx, rootCmd, ""); err != nil {
|
||||||
|
t.Errorf("Root command must not fail: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := executeCommandWithContext(currentCtx, rootCmd, "child"); err != nil {
|
||||||
|
t.Errorf("Subcommand must not fail: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := executeCommandWithContext(currentCtx, rootCmd, "child", "grandchild"); err != nil {
|
||||||
|
t.Errorf("Command child must not fail: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tests that the context passed to a subcommand propagates to the root.
|
||||||
|
// If the entry point happens to be different from the root command, the
|
||||||
|
// context should still propagate throughout the execution.
|
||||||
|
func TestExecuteContextOnSubcommand(t *testing.T) {
|
||||||
|
var key string
|
||||||
|
|
||||||
|
// Define unique contexts so we can tell them apart below.
|
||||||
|
ctxs := []context.Context{
|
||||||
|
context.WithValue(context.Background(), &key, "1"),
|
||||||
|
context.WithValue(context.Background(), &key, "2"),
|
||||||
|
context.WithValue(context.Background(), &key, "3"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared reference to the context in the current iteration.
|
||||||
|
var currentCtx context.Context
|
||||||
|
|
||||||
|
ctxRun := func(cmd *Command, args []string) {
|
||||||
|
if cmd.Context() != currentCtx {
|
||||||
|
t.Errorf("Command %q must have context with value %s", cmd.Use, currentCtx.Value(&key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun}
|
||||||
|
childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun}
|
||||||
|
granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun}
|
||||||
|
|
||||||
|
childCmd.AddCommand(granchildCmd)
|
||||||
|
rootCmd.AddCommand(childCmd)
|
||||||
|
|
||||||
|
currentCtx = ctxs[0]
|
||||||
|
if _, err := executeCommandWithContext(currentCtx, rootCmd, ""); err != nil {
|
||||||
|
t.Errorf("Root command must not fail: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCtx = ctxs[1]
|
||||||
|
if _, err := executeCommandWithContext(currentCtx, childCmd, "child"); err != nil {
|
||||||
|
t.Errorf("Subcommand must not fail: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCtx = ctxs[2]
|
||||||
|
if _, err := executeCommandWithContext(currentCtx, granchildCmd, "child", "grandchild"); err != nil {
|
||||||
|
t.Errorf("Command child must not fail: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestExecute_NoContext(t *testing.T) {
|
func TestExecute_NoContext(t *testing.T) {
|
||||||
run := func(cmd *Command, args []string) {
|
run := func(cmd *Command, args []string) {
|
||||||
if cmd.Context() != context.Background() {
|
if cmd.Context() != context.Background() {
|
||||||
|
|
Loading…
Reference in a new issue