Skip to content

Add urfave_cli_no_template build tag - #2441

Merged
Juneezee merged 4 commits into
urfave:mainfrom
kolyshkin:no-template-tag
Oct 1, 2026
Merged

Juneezee merged 4 commits into
urfave:mainfrom
kolyshkin:no-template-tag

Conversation

@kolyshkin

@kolyshkin kolyshkin commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Using text/template disables linker dead code elimination of exported methods for the whole program (golang/go#72895), which can noticeably increase the binary size.

This adds urfave_cli_no_template build tag, which renders the default help and fish completion without text/template, producing the same output.

Custom templates are not supported in this mode:

  • RootCommandHelpTemplate, CommandHelpTemplate, SubcommandHelpTemplate and FishCompletionTemplate are short string constants, only used to tell which help is requested, so modifying them is a compile error;
  • if the default help printer is used with a custom template (such as CustomRootCommandHelpTemplate or CustomHelpTemplate), it panics. A custom template handled by a custom HelpPrinter is fine.

With this tag, examples/example-cli is 3.2 MB instead of 5.1 MB, and runc is 10.5 MB instead of 12.4 MB (with opencontainers/runc#5486 applied, which fixes the only other reason DCE is disabled in runc); all 19 help pages of runc are byte-for-byte identical.

Testing:

  • the existing test suite is run with this tag in CI (skipping custom template tests);
  • a new golden test (TestHelpOutput) renders various help pages and fish completion, making sure both modes produce the exact same output;
  • TestNoTemplateTagDCE makes sure there are no <ReflectMethod> symbols (which disable DCE) in examples/example-cli built with this tag;
  • make check-binary-size now also shows the size with this tag.

Closes #2277.

An alternative, in which the template-less rendering code is generated from the templates, was proposed in #2442 (now closed).

@kolyshkin

Copy link
Copy Markdown
Contributor Author

Added the forth commit to modify check-binary-size CI job to show size with the new tag; here's the output:

2.2MB is the current binary size
0.7MB is the current binary size with urfave_cli_no_template build tag
  ✅ 1.5MB is the target min size
  ✅ 2.2MB is the target max size

@kolyshkin

Copy link
Copy Markdown
Contributor Author

@ldez @seanamos @abitrolly PTAL

@ldez

ldez commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

I wanted to create a PR based on the issue but I was waiting for feedback from urfave/cli maintainers before opening it because this is significant change.

I will review and test the 2 PRs as soon as possible.

@Juneezee Juneezee linked an issue Sep 24, 2026 that may be closed by this pull request
@kolyshkin

Copy link
Copy Markdown
Contributor Author

@dearchap @Juneezee PTAL

@Juneezee Juneezee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for writing both versions, it makes the trade-off easy to see.

I checked both branches locally with Go 1.27.1:

  • Tests pass with and without the tag.
  • examples/example-cli: 5.58 MB -> 3.28 MB (#2441) and 3.30 MB (#2442).
  • With the tag, go build -ldflags=-dumpdep ./examples/example-cli shows no <ReflectMethod> symbols (27 without the tag), so DCE is back.
  • Help output was byte-for-byte identical in both modes for extra commands outside the golden test (wrap widths, flag categories, persistent flags, subcommand UsageText/Category, pointer and value authors).

Which approach

I prefer #2441. The default templates change a few times a year (9 commits to template.go since 2024). The golden test covers almost all of the hand-written renderer, and the tagged CI run catches drift. Both need a second step when a template changes (go generate vs. a hand edit), so the real difference is the generator itself. It is nicely done, but it adds a 576-line template compiler (internal/genhelp/main.go) and 352 generated lines (help_notemplate_gen.go), where #2441 has one 341-line file of plain Go (help_notemplate.go).

Side note: the two descriptions disagree. #2441 says "I prefer this PR" and #2442 says "my preference is this one". Could you update whichever is stale?

Custom templates fail silently (both PRs)

With the tag, a custom or modified template prints no help, Run returns nil, and nothing is logged unless CLI_TEMPLATE_ERROR_DEBUG is set:

cli/help_notemplate.go

Lines 63 to 73 in 628df91

switch templ {
case defaultRootCommandHelpTemplate:
h.root()
case defaultCommandHelpTemplate:
h.command()
case defaultSubcommandHelpTemplate:
h.subcommand()
default:
handleTemplateError(errNoTemplate)
return
}

cli/help.go

Lines 361 to 371 in d1d8108

func handleTemplateError(err error) {
if err != nil {
tracef("error encountered during template parse: %[1]v", err)
// If the writer is closed, t.Execute will fail, and there's nothing
// we can do to recover.
if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
_, _ = fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
}
return
}
}

Example:

package main

import (
	"context"

	"github.com/urfave/cli/v3"
)

func main() {
	cmd := &cli.Command{Name: "app", CustomRootCommandHelpTemplate: "NAME: {{.Name}}\n"}
	_ = cmd.Run(context.Background(), []string{"app", "--help"})
}

go run . prints NAME: app. go run -tags urfave_cli_no_template . prints nothing. The same happens with cli.RootCommandHelpTemplate += "...".

This can bite a binary author who adds the tag without knowing that a dependency customizes the templates. ToFishCompletion already returns errNoTemplate, so help could report it too. Replacing both handleTemplateError(errNoTemplate) calls in DefaultPrintHelpCustom with

_, _ = fmt.Fprintln(ErrWriter, errNoTemplate)

works, and both test suites pass on both PRs after skipping TestPrintHelpCustomTemplateError with the tag. That test is about template parse errors. With the tag it only passes because data is not a *Command, so it hits the errNoTemplate path:

cli/help_test.go

Lines 2314 to 2328 in d1d8108

t.Setenv("CLI_TEMPLATE_ERROR_DEBUG", "true")
for _, tmpl := range tmpls {
oldtmpl := *tmpl
// safety mechanism in case something fails
defer func(stmpl *string) { *stmpl = oldtmpl }(tmpl)
errBuf := &bytes.Buffer{}
ErrWriter = errBuf
buf := &bytes.Buffer{}
*tmpl = "{{junk"
DefaultPrintHelpCustom(buf, "", "", nil)
assert.Contains(t, errBuf.String(), "CLI TEMPLATE ERROR")

TestNoTemplate_CustomHelpTemplate could then also check the error output.

Nits

TestNoTemplateTagDeps only looks for text/template. Checking the go build -ldflags=-dumpdep ./examples/example-cli output for <ReflectMethod> would also catch other packages that turn DCE off (html/template, a direct MethodByName call). It is cheap, about 0.4s here with a warm cache.

cli/dce_test.go

Lines 12 to 20 in 628df91

// Using text/template disables linker's dead code elimination of exported
// methods, so make sure it is not linked in with urfave_cli_no_template tag.
func TestNoTemplateTagDeps(t *testing.T) {
out, err := exec.Command("go", "list", "-deps", "-tags", "urfave_cli_no_template", ".").Output()
require.NoError(t, err)
deps := strings.Fields(string(out))
require.NotEmpty(t, deps)
require.False(t, slices.Contains(deps, "text/template"), "text/template is linked in with urfave_cli_no_template tag")
}

(#2441 only) The golden test has no subcommand with UsageText, so this branch is never compared against the template:

cli/help_notemplate.go

Lines 142 to 144 in 628df91

if c.UsageText != "" {
h.WriteString(h.wrap(c.UsageText, 3))
} else {

Looking for more input from other users and reviewers.

Comment thread docs/v3/binary-size.md Outdated
@kolyshkin

Copy link
Copy Markdown
Contributor Author

@Juneezee thanks for the thorough review! Addressed everything (rebased on top of main, too):

  • Custom (or modified) templates are no longer silently ignored: an error is printed to the root command's ErrWriter (or global ErrWriter if data is not a *Command) instead of help. TestNoTemplate_CustomHelpTemplate now checks this, and I've added tests for a modified RootCommandHelpTemplate and non-*Command data. TestPrintHelpCustomTemplateError is skipped with the tag. Docs updated accordingly.
  • TestNoTemplateTagDeps is replaced by TestNoTemplateTagDCE, which builds examples/example-cli with -ldflags=-dumpdep and checks there are no <ReflectMethod> symbols with the tag (and, as a sanity check, that there are some without it).
  • The golden test now has a subcommand with UsageText and Category.
  • Added a link to proposal: text/template,html/template: Template.ExecuteLite skip resolution to methods to allow DCE golang/go#72895 to the docs.
  • Closed Add urfave_cli_no_template build tag (generated code) #2442 and updated the description.

@kolyshkin
kolyshkin requested a review from Juneezee September 26, 2026 07:22
@Juneezee

Copy link
Copy Markdown
Member

@kolyshkin Thanks for the quick update. Everything from the first review is addressed. Verified locally at commit a6313e2:

  • Tests pass with and without the tag, also when merged into current main.
  • A custom template now prints the error to ErrWriter, and TestNoTemplateTagDCE checks <ReflectMethod> directly.
  • The golden test now covers the subcommand UsageText branch.

The fail-early idea in commit a6313e2 is useful, but the current implementation has two drawbacks.

1. Run fails even when a custom printer handles the template

checkNoCustomTemplates rejects any CustomRootCommandHelpTemplate or CustomHelpTemplate in the command tree before the action or help runs:

cli/command_run.go

Lines 113 to 116 in a6313e2

if cmd.parent == nil {
if err := checkNoCustomTemplates(cmd); err != nil {
return ctx, err
}

This breaks programs that render help themselves. The docs describe that as a full override via cli.HelpPrinter:

All of the help text generation may be customized, and at multiple levels. The templates
are exposed as variables `RootCommandHelpTemplate`, `CommandHelpTemplate`, and
`SubcommandHelpTemplate` which may be reassigned or augmented, and full override is
possible by assigning a compatible func to the `cli.HelpPrinter` variable, e.g.:

Example:

package main

import (
	"context"
	"fmt"
	"io"
	"os"

	"github.com/urfave/cli/v3"
)

func main() {
	// A help printer that does not use text/template.
	cli.HelpPrinter = func(w io.Writer, templ string, data any) {
		fmt.Fprintf(w, "custom help for %s\n", data.(*cli.Command).Name)
	}
	cmd := &cli.Command{
		Name:                          "app",
		CustomRootCommandHelpTemplate: "rendered by the custom printer",
		Action: func(context.Context, *cli.Command) error {
			fmt.Println("action ran")
			return nil
		},
	}
	if err := cmd.Run(context.Background(), os.Args); err != nil {
		fmt.Println("error:", err)
	}
}

With -tags urfave_cli_no_template, at 6d1b921 app prints action ran and app --help prints custom help for app. At a6313e2 both print:

error: command "app": custom templates are not supported when built with urfave_cli_no_template tag

It also fails programs that set a custom template but never show it. ExampleCommand_Suggest_command passed with the tag before this commit, and had to move to examples_template_test.go.

For comparison, the ErrWriter message from the earlier commit only fires when the default printer actually receives a custom template, so it does not affect these cases.

2. The default template text is gone from the API docs

The templates are now unexported constants, and the exported variables are initialized from them:

cli/help_template.go

Lines 15 to 18 in a6313e2

// RootCommandHelpTemplate is the text template for the Default help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var RootCommandHelpTemplate = rootCommandHelpTemplate

As a result, the API docs no longer show the default template text, for every user and not only those using the tag. From the repository root, go doc RootCommandHelpTemplate on main (58ec406) prints the full template (30 lines, truncated here):

var RootCommandHelpTemplate = `NAME:
   {{template "helpNameTemplate" .}}

USAGE:
...

At a6313e2 it prints only:

var RootCommandHelpTemplate = rootCommandHelpTemplate
    RootCommandHelpTemplate is the text template for the Default help topic.
    cli.go uses text/template to render templates. You can render custom help
    text by setting this variable.

CommandHelpTemplate, SubcommandHelpTemplate and FishCompletionTemplate change the same way, as the godoc-current.txt diff in this commit shows. The docs/v3/examples/help/generated-help-text.md docs linked above tell users to reassign or augment these variables, so the default text is what they start from.

Summary

Failing early has real value, for example the compile error for cli.RootCommandHelpTemplate += "..." with the tag. It is worth weighing whether that justifies the drawbacks above, or whether a different implementation could avoid them.

Looking for more input from other users and reviewers.

@kolyshkin

kolyshkin commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor Author

@Juneezee thanks again!

  1. You're right, the check in Run is wrong: there are too many ways to customize help (HelpPrinter, HelpPrinterCustom, ShowRootCommandHelp, ShowCommandHelp) to reliably tell whether a custom template will end up in the default printer.

    I've dropped it, so the last commit (now 0443c43) only makes the default templates constants with the tag. A custom template set via Custom*Template is handled as before (an error is printed to ErrWriter if it reaches the default printer), ExampleCommand_Suggest_command is back in examples_test.go, and I've added TestNoTemplate_CustomHelpPrinter based on your example.

  2. I don't think this is an issue. The template text is still one click away in the source, and it's not shown on pkg.go.dev anyway:

    var RootCommandHelpTemplate = `` /* 873-byte string literal not displayed */

@kolyshkin

Copy link
Copy Markdown
Contributor Author

Update: the template constants with the tag are now just short strings ("root", "command", etc.), since templates are not used in this mode anyway. As a result, the template variables (without the tag) are back to how they were, and the API docs are unchanged from main.

@kolyshkin
kolyshkin force-pushed the no-template-tag branch 6 times, most recently from 1d73ed8 to 04c7fd4 Compare September 26, 2026 20:07
@kolyshkin

Copy link
Copy Markdown
Contributor Author

Reworked the patchset (and rebased on top of main). Changes since my last comment:

  • The series is now 4 commits, with no back-and-forth: the first commit moves everything that only makes sense with text/template (including RootCommandHelpTemplate etc.) to help_template.go, and the second one adds the tag in its final form.
  • With the tag, using a custom template with the default help printer now panics instead of printing an error to ErrWriter, same as a broken custom template already does without the tag (via template.Must). A custom HelpPrinter still works fine.
  • Removed the test checking that modifying the template constants is a compile error, since it only tests the Go language.
  • Docs: the tag and its limitations are now described in README (as build tags used to be), binary-size.md only covers the dead code elimination aspect and links to README, and the v2-to-v3 migration guide mentions the new tag.
  • Updated the PR description. Note that for runc, the binary size gain also needs libct: don't use reflect to log CRIU options opencontainers/runc#5486.

@Juneezee Juneezee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kolyshkin LGTM, thanks! Verified locally at 04c7fd4: tests pass with and without the tag, and with the tag examples/example-cli has no <ReflectMethod> symbols.

Two optional follow-ups, not blocking:

  1. With the tag, a custom HelpPrinter receives "root", "command" or "subcommand" as templ instead of the template text:

cli/help_notemplate.go

Lines 17 to 28 in 04c7fd4

// With urfave_cli_no_template tag, templates are not used, and these are
// only used to tell which help is requested.
const (
// RootCommandHelpTemplate identifies the help for the root command.
RootCommandHelpTemplate = "root"
// CommandHelpTemplate identifies the help for a command.
CommandHelpTemplate = "command"
// SubcommandHelpTemplate identifies the help for a command with subcommands.
SubcommandHelpTemplate = "subcommand"
// FishCompletionTemplate is not used.
FishCompletionTemplate = "fish"
)

The README line "Replacing cli.HelpPrinter works as usual" could mention that:

cli/README.md

Lines 42 to 48 in 04c7fd4

- `RootCommandHelpTemplate`, `CommandHelpTemplate`, `SubcommandHelpTemplate`
and `FishCompletionTemplate` are constants;
- if the default help printer is used with a custom template (such as
`CustomRootCommandHelpTemplate` or `CustomHelpTemplate`), it panics;
- custom template functions other than `wrap` and `wrapAt` are ignored.
Replacing `cli.HelpPrinter` works as usual.

  1. The errNoTemplate panic could include the command name, to make it easier to find which command has the custom template:

cli/help_notemplate.go

Lines 65 to 74 in 04c7fd4

switch templ {
case RootCommandHelpTemplate:
h.root()
case CommandHelpTemplate:
h.command()
case SubcommandHelpTemplate:
h.subcommand()
default:
panic(errNoTemplate)
}

@ldez since the build tag approach was your idea in #2277 (comment), it would be great to hear your thoughts before this is merged.

@kolyshkin

Copy link
Copy Markdown
Contributor Author

@Juneezee thanks! Addressed both:

  1. README now says that a custom HelpPrinter receives "root", "command" or "subcommand" as templ with the tag.
  2. The panic now includes the command name, e.g. command "foo bar": custom templates are not supported when built with urfave_cli_no_template tag.

@kolyshkin

Copy link
Copy Markdown
Contributor Author

@ldez ptal 🙏🏻

@ldez

ldez commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

The implementation seem right, I tested it and it works as expected.

My only concern is about customization.

Replacing cli.HelpPrinter works as usual, except it receives "root",
"command" or "subcommand" as templ instead of the template text.

This doesn't allow the hack around cli.HelpPrinter to provide a custom help because the name of a subcommand can be identical for several commands.

But this is a detail, we can ignore it for now, at least, I think we cannot provide a better solution without breaking changes.


Off topic: I don't think GitHub is able to close automatically and issue when using the word Addresses inside the issue description, you should uses fixes or closes or resolves.

https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword

Move DefaultPrintHelpCustom, the fish completion template rendering,
and the exported templates (RootCommandHelpTemplate etc.) to
help_template.go, so that everything which only makes sense with
text/template is in one file.

No functional change; this is a preparation for the next commit.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin

Copy link
Copy Markdown
Contributor Author

The implementation seem right, I tested it and it works as expected.

My only concern is about customization.

Replacing cli.HelpPrinter works as usual, except it receives "root",
"command" or "subcommand" as templ instead of the template text.

This doesn't allow the hack around cli.HelpPrinter to provide a custom help because the name of a subcommand can be identical for several commands.

I think you are mixing things up here. The command (*Command) is still passed on in data, what we do not pass when the new build tag is set is the full template itself (instead of templates for root, command, subcommand we pass a simple string).

There is even a (weak) test, added by this PR, TestNoTemplate_CustomHelpPrinter, which checks data.(*Command).Name is as expected (for command only).

I have now added another test, TestNoTemplate_CustomHelpPrinterTempl, which checks the command name is actually passed (and also that root/command/subcommand works as documented).

Off topic: I don't think GitHub is able to close automatically and issue when using the word Addresses inside the issue description, you should uses fixes or closes or resolves.

Thanks, fixed (although I think @Juneezee manually linked the issue to this PR).

Using text/template makes the Go linker disable dead code elimination
of exported methods for the whole program, since templates can call
arbitrary methods by name (see golang/go#72895). For large programs,
this results in a noticeably bigger binary.

Add urfave_cli_no_template build tag, which renders the default help
and fish completion directly, producing the same output, but without
using text/template.

Custom templates are not supported in this mode. RootCommandHelpTemplate,
CommandHelpTemplate, SubcommandHelpTemplate and FishCompletionTemplate
are short string constants, only used to tell which help is requested,
so an attempt to modify them is a compile error. If the default help
printer is used with a custom template, it panics.

With this tag, examples/example-cli binary is 3.2 MB instead of 5.1 MB,
and runc binary (with opencontainers/runc#5486 applied) is 10.5 MB
instead of 12.4 MB.

Run tests with this tag in CI, skipping those that use custom templates,
and add a test to ensure linker's dead code elimination is not disabled
with this tag.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Add a test which renders various help pages and fish completion for
a few commands exercising most of the template features, and compares
the result with a golden file.

Since CI runs tests both with and without urfave_cli_no_template tag,
this ensures both implementations produce the exact same output.

To regenerate the golden file, run the test with UPDATE_GOLDEN=1.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
In check-binary-size, also show how much the package contributes to the
binary size when built with urfave_cli_no_template tag. This is for
informational purposes only; the limits are checked for the default
build.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@ldez

ldez commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

I think you are mixing things up here.

I missed that a command has a Root() method, so we can have the parent of the subcommand.

Not easy to use but it can work.

@Juneezee
Juneezee merged commit f6f38ed into urfave:main Oct 1, 2026
9 checks passed
@Juneezee Juneezee linked an issue Oct 9, 2026 that may be closed by this pull request
Maks1mS pushed a commit to stplr-dev/stplr that referenced this pull request Oct 24, 2026
This PR contains the following updates:

| Package | Type | Update | Change | OpenSSF |
|---|---|---|---|---|
| [github.com/urfave/cli/v3](https://github.com/urfave/cli) | require | minor | `v3.10.1` → `v3.14.0` | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/urfave/cli/badge)](https://securityscorecards.dev/viewer/?uri=github.com/urfave/cli) |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/23) for more information.

---

### Release Notes

<details>
<summary>urfave/cli (github.com/urfave/cli/v3)</summary>

### [`v3.14.0`](https://github.com/urfave/cli/releases/tag/v3.14.0)

[Compare Source](urfave/cli@v3.13.0...v3.14.0)

#### What's Changed

- chore(deps): bump mkdocs-git-revision-date-localized-plugin from 1.5.4 to 1.6.0 in the python-packages group by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2436](urfave/cli#2436)
- fix: set BoolWithInverseFlag in a short option group by [@&#8203;lazerg](https://github.com/lazerg) in [#&#8203;2440](urfave/cli#2440)
- Keep arguments after a bare dash by [@&#8203;official-burak](https://github.com/official-burak) in [#&#8203;2419](urfave/cli#2419)
- fix: handle a multi-byte flag at the end of a short option group by [@&#8203;SulimanAbdulrazzaq](https://github.com/SulimanAbdulrazzaq) in [#&#8203;2438](urfave/cli#2438)
- fix: complete persistent flags in shell completion by [@&#8203;sb123sb123](https://github.com/sb123sb123) in [#&#8203;2437](urfave/cli#2437)
- fix: restore Unwrap on the error returned by Exit by [@&#8203;fadiroot](https://github.com/fadiroot) in [#&#8203;2444](urfave/cli#2444)
- fix: reject a parent's Local flag inside a short option group by [@&#8203;fadiroot](https://github.com/fadiroot) in [#&#8203;2445](urfave/cli#2445)
- fix: report a flag that needs an argument but is not last in a short group by [@&#8203;yu2971512385-ui](https://github.com/yu2971512385-ui) in [#&#8203;2443](urfave/cli#2443)
- Use prefixFor so flag suggestions agree with help on rune count by [@&#8203;januththedev](https://github.com/januththedev) in [#&#8203;2448](urfave/cli#2448)
- fix: reject duplicate flag names by [@&#8203;deepakganesh78](https://github.com/deepakganesh78) in [#&#8203;2396](urfave/cli#2396)
- fix: date a time-only timestamp today when Timezone is not UTC by [@&#8203;breken-ai](https://github.com/breken-ai) in [#&#8203;2450](urfave/cli#2450)
- fix: let a subcommand's command-line value replace a persistent flag's env/file value by [@&#8203;breken-ai](https://github.com/breken-ai) in [#&#8203;2449](urfave/cli#2449)
- Add urfave_cli_no_template build tag by [@&#8203;kolyshkin](https://github.com/kolyshkin) in [#&#8203;2441](urfave/cli#2441)
- fix: skip empty source values for flags that cannot parse them by [@&#8203;abo3losh1](https://github.com/abo3losh1) in [#&#8203;2451](urfave/cli#2451)

#### New Contributors

- [@&#8203;lazerg](https://github.com/lazerg) made their first contribution in [#&#8203;2440](urfave/cli#2440)
- [@&#8203;official-burak](https://github.com/official-burak) made their first contribution in [#&#8203;2419](urfave/cli#2419)
- [@&#8203;SulimanAbdulrazzaq](https://github.com/SulimanAbdulrazzaq) made their first contribution in [#&#8203;2438](urfave/cli#2438)
- [@&#8203;sb123sb123](https://github.com/sb123sb123) made their first contribution in [#&#8203;2437](urfave/cli#2437)
- [@&#8203;fadiroot](https://github.com/fadiroot) made their first contribution in [#&#8203;2444](urfave/cli#2444)
- [@&#8203;yu2971512385-ui](https://github.com/yu2971512385-ui) made their first contribution in [#&#8203;2443](urfave/cli#2443)
- [@&#8203;januththedev](https://github.com/januththedev) made their first contribution in [#&#8203;2448](urfave/cli#2448)
- [@&#8203;deepakganesh78](https://github.com/deepakganesh78) made their first contribution in [#&#8203;2396](urfave/cli#2396)
- [@&#8203;breken-ai](https://github.com/breken-ai) made their first contribution in [#&#8203;2450](urfave/cli#2450)
- [@&#8203;abo3losh1](https://github.com/abo3losh1) made their first contribution in [#&#8203;2451](urfave/cli#2451)

**Full Changelog**: <urfave/cli@v3.13.0...v3.14.0>

### [`v3.13.0`](https://github.com/urfave/cli/releases/tag/v3.13.0)

[Compare Source](urfave/cli@v3.12.0...v3.13.0)

#### What's Changed

- Trim the key of a map flag when TrimSpace is set by [@&#8203;youdie006](https://github.com/youdie006) in [#&#8203;2431](urfave/cli#2431)
- Fix inverse bool flag counting with an external counter by [@&#8203;jakezwang](https://github.com/jakezwang) in [#&#8203;2432](urfave/cli#2432)
- feat: add Deprecated field to flags and commands by [@&#8203;anandghegde](https://github.com/anandghegde) in [#&#8203;2429](urfave/cli#2429)
- fix: parse single-rune Unicode flags by [@&#8203;znnnnnnn-wil](https://github.com/znnnnnnn-wil) in [#&#8203;2434](urfave/cli#2434)

#### New Contributors

- [@&#8203;jakezwang](https://github.com/jakezwang) made their first contribution in [#&#8203;2432](urfave/cli#2432)
- [@&#8203;anandghegde](https://github.com/anandghegde) made their first contribution in [#&#8203;2429](urfave/cli#2429)
- [@&#8203;znnnnnnn-wil](https://github.com/znnnnnnn-wil) made their first contribution in [#&#8203;2434](urfave/cli#2434)

**Full Changelog**: <urfave/cli@v3.12.0...v3.13.0>

### [`v3.12.0`](https://github.com/urfave/cli/releases/tag/v3.12.0)

[Compare Source](urfave/cli@v3.11.0...v3.12.0)

#### What's Changed

- feat: add Command.ArgValidator for tree-wide argument validation by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2377](urfave/cli#2377)
- Single-value arguments can be marked as required by [@&#8203;idelchi](https://github.com/idelchi) in [#&#8203;2393](urfave/cli#2393)
- docs: clarify that named Arguments are excluded from cmd.Args() by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2411](urfave/cli#2411)
- fix: never run command action on shell completion past a double dash by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2412](urfave/cli#2412)
- chore(deps): bump github.com/stretchr/testify from 1.11.1 to 1.12.0 by [@&#8203;app/dependabot](https://github.com/app/dependabot) in [#&#8203;2413](urfave/cli#2413)
- Support custom FlagStringer for MutuallyExclusiveFlags by [@&#8203;SHIVANSHGARG07](https://github.com/SHIVANSHGARG07) in [#&#8203;2414](urfave/cli#2414)
- Add TextFlag for encoding.TextMarshaler/TextUnmarshaler values by [@&#8203;ChrisJr404](https://github.com/ChrisJr404) in [#&#8203;2415](urfave/cli#2415)
- chore(deps): bump github.com/stretchr/testify from 1.12.0 to 1.12.1 by [@&#8203;app/dependabot](https://github.com/app/dependabot) in [#&#8203;2416](urfave/cli#2416)
- chore(deps): bump the python-packages group with 2 updates by [@&#8203;app/dependabot](https://github.com/app/dependabot) in [#&#8203;2417](urfave/cli#2417)
- Show inherited persistent flags in child help by [@&#8203;justadityaraj](https://github.com/justadityaraj) in [#&#8203;2421](urfave/cli#2421)
- fix: preserve whitespace in positional arguments by [@&#8203;lenamonj](https://github.com/lenamonj) in [#&#8203;2423](urfave/cli#2423)
- fix: preserve whitespace in equals-form flag values by [@&#8203;BenYang12](https://github.com/BenYang12) in [#&#8203;2425](urfave/cli#2425)
- fix: complete subcommand flags after positional arguments by [@&#8203;fzlzjerry](https://github.com/fzlzjerry) in [#&#8203;2426](urfave/cli#2426)
- Fix a year-less timestamp layout losing January 1 by [@&#8203;youdie006](https://github.com/youdie006) in [#&#8203;2427](urfave/cli#2427)
- docs: add go-size-analyzer, module version, and reflection by [@&#8203;imsumedhaa](https://github.com/imsumedhaa) in [#&#8203;2428](urfave/cli#2428)

#### New Contributors

- [@&#8203;idelchi](https://github.com/idelchi) made their first contribution in [#&#8203;2393](urfave/cli#2393)
- [@&#8203;SHIVANSHGARG07](https://github.com/SHIVANSHGARG07) made their first contribution in [#&#8203;2414](urfave/cli#2414)
- [@&#8203;ChrisJr404](https://github.com/ChrisJr404) made their first contribution in [#&#8203;2415](urfave/cli#2415)
- [@&#8203;justadityaraj](https://github.com/justadityaraj) made their first contribution in [#&#8203;2421](urfave/cli#2421)
- [@&#8203;lenamonj](https://github.com/lenamonj) made their first contribution in [#&#8203;2423](urfave/cli#2423)
- [@&#8203;BenYang12](https://github.com/BenYang12) made their first contribution in [#&#8203;2425](urfave/cli#2425)
- [@&#8203;youdie006](https://github.com/youdie006) made their first contribution in [#&#8203;2427](urfave/cli#2427)
- [@&#8203;imsumedhaa](https://github.com/imsumedhaa) made their first contribution in [#&#8203;2428](urfave/cli#2428)

**Full Changelog**: <urfave/cli@v3.11.0...v3.12.0>

### [`v3.11.0`](https://github.com/urfave/cli/releases/tag/v3.11.0)

[Compare Source](urfave/cli@v3.10.1...v3.11.0)

#### What's Changed

- fix: correct a typo in the help message for the powershell autocompletion by [@&#8203;suzuki-shunsuke](https://github.com/suzuki-shunsuke) in [#&#8203;2383](urfave/cli#2383)
- Escape backslashes in fish completion descriptions by [@&#8203;mahirhir](https://github.com/mahirhir) in [#&#8203;2378](urfave/cli#2378)
- chore(deps): bump actions/setup-go from 6 to 7 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2389](urfave/cli#2389)
- chore(deps): bump mkdocs-material from 9.7.6 to 9.7.7 in the python-packages group by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2391](urfave/cli#2391)
- chore(deps): bump actions/setup-python from 6 to 7 by [@&#8203;dependabot](https://github.com/dependabot)\[bot] in [#&#8203;2390](urfave/cli#2390)
- fix: skip all hidden flags in shell completion, not just bool flags by [@&#8203;vidigoat](https://github.com/vidigoat) in [#&#8203;2388](urfave/cli#2388)
- Fix nil pointer dereference for interface-typed flag values by [@&#8203;mrueg](https://github.com/mrueg) in [#&#8203;2400](urfave/cli#2400)
- Fix index out of range panic when Run is given no arguments by [@&#8203;mrueg](https://github.com/mrueg) in [#&#8203;2401](urfave/cli#2401)
- fix: honor BoolWithInverseFlag DefaultText by [@&#8203;fzlzjerry](https://github.com/fzlzjerry) in [#&#8203;2403](urfave/cli#2403)
- Fix Issue [#&#8203;2385](urfave/cli#2385) by [@&#8203;BrandonIrizarry](https://github.com/BrandonIrizarry) in [#&#8203;2386](urfave/cli#2386)
- fix: inherit HideHelpCommand in subcommands by [@&#8203;utkarshalpha](https://github.com/utkarshalpha) in [#&#8203;2395](urfave/cli#2395)
- test: cover Run-with-no-arguments paths ([#&#8203;2406](urfave/cli#2406)) by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2407](urfave/cli#2407)
- test: add shell-completion case for hidden BoolWithInverseFlag by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2408](urfave/cli#2408)
- test: fix ineffective mutex error-string assertion and add mirror cases by [@&#8203;dearchap](https://github.com/dearchap) in [#&#8203;2410](urfave/cli#2410)

#### New Contributors

- [@&#8203;mahirhir](https://github.com/mahirhir) made their first contribution in [#&#8203;2378](urfave/cli#2378)
- [@&#8203;vidigoat](https://github.com/vidigoat) made their first contribution in [#&#8203;2388](urfave/cli#2388)
- [@&#8203;fzlzjerry](https://github.com/fzlzjerry) made their first contribution in [#&#8203;2403](urfave/cli#2403)
- [@&#8203;BrandonIrizarry](https://github.com/BrandonIrizarry) made their first contribution in [#&#8203;2386](urfave/cli#2386)
- [@&#8203;utkarshalpha](https://github.com/utkarshalpha) made their first contribution in [#&#8203;2395](urfave/cli#2395)

**Full Changelog**: <urfave/cli@v3.10.1...v3.11.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At 12:00 AM through 04:59 AM and 10:00 PM through 11:59 PM, Monday through Friday (`* 0-4,22-23 * * 1-5`)
  - Only on Sunday and Saturday (`* * * * 0,6`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNTEuMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE1MS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJLaW5kL0RlcGVuZGVuY2llcyJdfQ==-->

Reviewed-on: https://altlinux.space/stapler/stplr/pulls/503
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Documentation on optimizing binary size Dead code elimination partially disabled

3 participants