Skip to content

Commit 646e048

Browse files
committed
Run Before actions after setting up subcommand
This fixes an issue where the Before hook of a parent command would not see flag values set in the subcommand context.
1 parent 35945b7 commit 646e048

File tree

1 file changed

+36
-16
lines changed

1 file changed

+36
-16
lines changed

command.go

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"path/filepath"
1111
"reflect"
12+
"slices"
1213
"sort"
1314
"strings"
1415
"unicode"
@@ -561,23 +562,7 @@ func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) {
561562
}
562563
}
563564

564-
if cmd.Before != nil && !cmd.Root().shellCompletion {
565-
if bctx, err := cmd.Before(ctx, cmd); err != nil {
566-
deferErr = cmd.handleExitCoder(ctx, err)
567-
return deferErr
568-
} else if bctx != nil {
569-
ctx = bctx
570-
}
571-
}
572-
573-
tracef("running flag actions (cmd=%[1]q)", cmd.Name)
574-
575-
if err := cmd.runFlagActions(ctx); err != nil {
576-
return err
577-
}
578-
579565
var subCmd *Command
580-
581566
if args.Present() {
582567
tracef("checking positional args %[1]q (cmd=%[2]q)", args, cmd.Name)
583568

@@ -613,11 +598,46 @@ func (cmd *Command) Run(ctx context.Context, osArgs []string) (deferErr error) {
613598
}
614599
}
615600

601+
// If a subcommand has been resolved, let it handle the remaining execution.
616602
if subCmd != nil {
617603
tracef("running sub-command %[1]q with arguments %[2]q (cmd=%[3]q)", subCmd.Name, cmd.Args(), cmd.Name)
618604
return subCmd.Run(ctx, cmd.Args().Slice())
619605
}
620606

607+
// This code path is the innermost command execution. Here we actually
608+
// perform the command action.
609+
//
610+
// First, resolve the chain of nested commands up to the parent.
611+
var cmdChain []*Command
612+
for p := cmd; p != nil; p = p.parent {
613+
cmdChain = append(cmdChain, p)
614+
}
615+
slices.Reverse(cmdChain)
616+
617+
// Run Before actions in order.
618+
for _, cmd := range cmdChain {
619+
if cmd.Before == nil {
620+
continue
621+
}
622+
if bctx, err := cmd.Before(ctx, cmd); err != nil {
623+
deferErr = cmd.handleExitCoder(ctx, err)
624+
return deferErr
625+
} else if bctx != nil {
626+
ctx = bctx
627+
}
628+
}
629+
630+
// Run flag actions in order.
631+
// These take a context, so this has to happen after Before actions.
632+
for _, cmd := range cmdChain {
633+
tracef("running flag actions (cmd=%[1]q)", cmd.Name)
634+
if err := cmd.runFlagActions(ctx); err != nil {
635+
deferErr = cmd.handleExitCoder(ctx, err)
636+
return deferErr
637+
}
638+
}
639+
640+
// Run the command action.
621641
if cmd.Action == nil {
622642
cmd.Action = helpCommandAction
623643
} else {

0 commit comments

Comments
 (0)