Skip to content

Commit 9243240

Browse files
committed
cli-plugins/hooks: add commandInfo type for templating
Define a local type for methods to expose to the template, instead of passing the cobra.Cmd. This avoids templates depending on features exposed by Cobra that are not part of the contract, and slightly decouples the templat from the Cobra implementation. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 4a1b2ef commit 9243240

File tree

3 files changed

+47
-21
lines changed

3 files changed

+47
-21
lines changed

cli-plugins/hooks/hook_utils.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import (
66

77
const (
88
hookTemplateCommandName = `{{.Name}}`
9-
hookTemplateFlagValue = `{{flag . %q}}`
10-
hookTemplateArg = `{{arg . %d}}`
9+
hookTemplateFlagValue = `{{.FlagValue %q}}`
10+
hookTemplateArg = `{{.Arg %d}}`
1111
)
1212

1313
// TemplateReplaceSubcommandName returns a hook template string

cli-plugins/hooks/hooks_utils_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ func TestTemplateHelpers(t *testing.T) {
2222
got: func() string {
2323
return hooks.TemplateReplaceFlagValue("name")
2424
},
25-
want: `{{flag . "name"}}`,
25+
want: `{{.FlagValue "name"}}`,
2626
},
2727
{
2828
doc: "arg",
2929
got: func() string {
3030
return hooks.TemplateReplaceArg(0)
3131
},
32-
want: `{{arg . 0}}`,
32+
want: `{{.Arg 0}}`,
3333
},
3434
{
3535
doc: "arg",
3636
got: func() string {
3737
return hooks.TemplateReplaceArg(3)
3838
},
39-
want: `{{arg . 3}}`,
39+
want: `{{.Arg 3}}`,
4040
},
4141
}
4242

cli-plugins/hooks/template.go

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package hooks
33
import (
44
"bytes"
55
"errors"
6+
"fmt"
67
"strings"
78
"text/template"
89

@@ -13,13 +14,18 @@ func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
1314
out := hookTemplate
1415
if strings.Contains(hookTemplate, "{{") {
1516
// Message may be a template.
16-
tmpl := template.New("").Funcs(commandFunctions)
17-
tmpl, err := tmpl.Parse(hookTemplate)
17+
msgContext := commandInfo{cmd: cmd}
18+
19+
tmpl, err := template.New("").Funcs(template.FuncMap{
20+
// kept for backward-compatibility with old templates.
21+
"flag": func(_ any, flagName string) (string, error) { return msgContext.FlagValue(flagName) },
22+
"arg": func(_ any, i int) (string, error) { return msgContext.Arg(i) },
23+
}).Parse(hookTemplate)
1824
if err != nil {
1925
return nil, err
2026
}
2127
var b bytes.Buffer
22-
err = tmpl.Execute(&b, cmd)
28+
err = tmpl.Execute(&b, msgContext)
2329
if err != nil {
2430
return nil, err
2531
}
@@ -30,23 +36,43 @@ func ParseTemplate(hookTemplate string, cmd *cobra.Command) ([]string, error) {
3036

3137
var ErrHookTemplateParse = errors.New("failed to parse hook template")
3238

33-
var commandFunctions = template.FuncMap{
34-
"flag": getFlagValue,
35-
"arg": getArgValue,
39+
// commandInfo provides info about the command for which the hook was invoked.
40+
// It is used for templated hook-messages.
41+
type commandInfo struct {
42+
cmd *cobra.Command
43+
}
44+
45+
// Name returns the name of the (sub)command for which the hook was invoked.
46+
//
47+
// It's used for backward-compatibility with old templates.
48+
func (c commandInfo) Name() string {
49+
if c.cmd == nil {
50+
return ""
51+
}
52+
return c.cmd.Name()
3653
}
3754

38-
func getFlagValue(cmd *cobra.Command, flag string) (string, error) {
39-
cmdFlag := cmd.Flag(flag)
40-
if cmdFlag == nil {
41-
return "", ErrHookTemplateParse
55+
// FlagValue returns the value that was set for the given flag when the hook was invoked.
56+
func (c commandInfo) FlagValue(flagName string) (string, error) {
57+
if c.cmd == nil {
58+
return "", fmt.Errorf("%w: flagValue: cmd is nil", ErrHookTemplateParse)
59+
}
60+
f := c.cmd.Flag(flagName)
61+
if f == nil {
62+
return "", fmt.Errorf("%w: flagValue: no flags found", ErrHookTemplateParse)
4263
}
43-
return cmdFlag.Value.String(), nil
64+
return f.Value.String(), nil
4465
}
4566

46-
func getArgValue(cmd *cobra.Command, i int) (string, error) {
47-
flags := cmd.Flags()
48-
if flags == nil {
49-
return "", ErrHookTemplateParse
67+
// Arg returns the value of the nth argument.
68+
func (c commandInfo) Arg(n int) (string, error) {
69+
if c.cmd == nil {
70+
return "", fmt.Errorf("%w: arg: cmd is nil", ErrHookTemplateParse)
71+
}
72+
flags := c.cmd.Flags()
73+
v := flags.Arg(n)
74+
if v == "" && n >= flags.NArg() {
75+
return "", fmt.Errorf("%w: arg: %dth argument not set", ErrHookTemplateParse, n)
5076
}
51-
return flags.Arg(i), nil
77+
return v, nil
5278
}

0 commit comments

Comments
 (0)