Skip to content

Commit

Permalink
Merge pull request #24 from joobisb/issues#13
Browse files Browse the repository at this point in the history
feat: add a field on command to deprecate
  • Loading branch information
Emyrk authored Nov 18, 2024
2 parents 09f1207 + b6470ab commit 5f3d052
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 9 deletions.
12 changes: 12 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ type Command struct {
// Hidden determines whether the command should be hidden from help.
Hidden bool

// Deprecated indicates whether this command is deprecated.
// If empty, the command is not deprecated.
// If set, the value is used as the deprecation message.
Deprecated string `json:"deprecated,omitempty"`

// RawArgs determines whether the command should receive unparsed arguments.
// No flags are parsed when set, and the command is responsible for parsing
// its own flags.
Expand Down Expand Up @@ -316,6 +321,13 @@ func (inv *Invocation) CurWords() (prev string, cur string) {
// allArgs is wired through the stack so that global flags can be accepted
// anywhere in the command invocation.
func (inv *Invocation) run(state *runState) error {
if inv.Command.Deprecated != "" {
fmt.Fprintf(inv.Stderr, "%s %q is deprecated!. %s\n",
prettyHeader("warning"),
inv.Command.FullName(),
inv.Command.Deprecated,
)
}
err := inv.Command.Options.ParseEnv(inv.Environ)
if err != nil {
return xerrors.Errorf("parsing env: %w", err)
Expand Down
21 changes: 21 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,27 @@ func TestCommand(t *testing.T) {
err := i.Run()
require.NoError(t, err, fio.Stdout.String())
})

t.Run("DeprecatedCommand", func(t *testing.T) {
t.Parallel()

deprecatedCmd := &serpent.Command{
Use: "deprecated-cmd",
Deprecated: "This command is deprecated and will be removed in the future.",
Handler: func(i *serpent.Invocation) error {
_, _ = i.Stdout.Write([]byte("Running deprecated command"))
return nil
},
}

i := deprecatedCmd.Invoke()
io := fakeIO(i)
err := i.Run()
require.NoError(t, err)
expectedWarning := fmt.Sprintf("WARNING: %q is deprecated!. %s\n", deprecatedCmd.Use, deprecatedCmd.Deprecated)
require.Equal(t, io.Stderr.String(), expectedWarning)
require.Contains(t, io.Stdout.String(), "Running deprecated command")
})
}

func TestCommand_DeepNest(t *testing.T) {
Expand Down
20 changes: 11 additions & 9 deletions help.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,21 @@ func helpColor(s string) termenv.Color {
return helpColorProfile.Color(s)
}

// prettyHeader formats a header string with consistent styling.
// It uppercases the text, adds a colon, and applies the header color.
func prettyHeader(s string) string {
headerFg := pretty.FgColor(helpColor("#337CA0"))
s = strings.ToUpper(s)
txt := pretty.String(s, ":")
headerFg.Format(txt)
return txt.String()
}

var defaultHelpTemplate = func() *template.Template {
var (
optionFg = pretty.FgColor(
helpColor("#04A777"),
)
headerFg = pretty.FgColor(
helpColor("#337CA0"),
)
)
return template.Must(
template.New("usage").Funcs(
Expand All @@ -85,12 +92,7 @@ var defaultHelpTemplate = func() *template.Template {
optionFg.Format(txt)
return txt.String()
},
"prettyHeader": func(s string) string {
s = strings.ToUpper(s)
txt := pretty.String(s, ":")
headerFg.Format(txt)
return txt.String()
},
"prettyHeader": prettyHeader,
"typeHelper": func(opt *Option) string {
switch v := opt.Value.(type) {
case *Enum:
Expand Down
5 changes: 5 additions & 0 deletions help.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
{{"\n"}}
{{- end}}

{{- with .Deprecated }}
{{- indent (printf "DEPRECATED: %s" .) 2 | wrapTTY }}
{{"\n"}}
{{- end }}

{{ with .Aliases }}
{{" Aliases: "}} {{- joinStrings .}}
{{- end }}
Expand Down

0 comments on commit 5f3d052

Please # to comment.