Skip to content

fix: interpolate ${env} in help text for positional arguments#595

Open
lawrence3699 wants to merge 1 commit intoalecthomas:masterfrom
lawrence3699:fix/positional-arg-env-interpolation
Open

fix: interpolate ${env} in help text for positional arguments#595
lawrence3699 wants to merge 1 commit intoalecthomas:masterfrom
lawrence3699:fix/positional-arg-env-interpolation

Conversation

@lawrence3699
Copy link
Copy Markdown

Fixes #556.

Problem: Using ${env} in the help text of a positional argument (arg:"") panics with "undefined variable ${env}", while it works fine for flags.

// panics
var cli struct {
    Foo string `arg:"" help:"Foo (${env})" env:"FOO"`
}

Cause: interpolateValue() only populated the env variable in updatedVars when value.Flag != nil. Positional arguments have value.Flag == nil, so env was never set.

Fix: Populate env from value.Tag.Envs for positional arguments. Also merge updatedVars into vars explicitly before interpolating help, since interpolate() skips the merge when values equal missing map keys (both "").

After: ${env} resolves to the first env var name for positional args (or "" if no env tag), matching flag behavior.

All existing tests pass; added regression tests for the three cases (env set, env unset, multiple envs).

Positional arguments with an env tag could not use ${env} in their help
text, causing a panic: "undefined variable ${env}". This happened because
the env variable was only populated for flags (value.Flag != nil), not
for positional arguments.

Populate the env variable from value.Tag.Envs for positional arguments
and merge updatedVars into vars explicitly to work around an optimization
in interpolate() that skips merging when values equal missing map keys.

Fixes alecthomas#556
Copilot AI review requested due to automatic review settings April 13, 2026 00:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a construction-time panic when ${env} is used in the help text for positional arguments by ensuring the env interpolation variable is populated for non-flag values and that updated interpolation variables are reliably visible during help interpolation.

Changes:

  • Populate updatedVars["env"] for positional arguments using value.Tag.Envs.
  • Explicitly merge updatedVars into vars before interpolating value.Help to avoid the “missing key + empty string” merge edge case.
  • Add regression tests covering positional args with env set, env unset, and multiple envs.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
kong.go Updates interpolation logic for positional-argument help to define ${env} and avoid merge-skipping edge cases.
issue556_test.go Adds regression tests ensuring ${env} in positional help interpolates correctly across key scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread kong.go
Comment on lines +285 to +289
} else {
updatedVars["env"] = ""
if len(value.Tag.Envs) != 0 {
updatedVars["env"] = value.Tag.Envs[0]
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

In the positional-argument branch, updatedVars["env"] is derived from value.Tag.Envs without interpolating the env tag values first. For flags, env tag values are interpolated (value.Flag.Envs[i] = interpolate(...)) and then copied into value.Tag.Envs, so env:"${someVar}" works there. For positional arguments, env:"${someVar}" would currently leave ${someVar} unexpanded (both for ${env} in help and for later env lookup in Value.Reset). Consider interpolating value.Tag.Envs in the value.Flag == nil branch (similar to the flag path) before selecting the first env name.

Copilot uses AI. Check for mistakes.
Comment thread kong.go
Comment on lines +291 to +295
// Merge updatedVars into vars explicitly because interpolate() skips
// the merge when all updatedVars values equal the zero value of missing
// map keys (e.g. env="").
vars = vars.CloneWith(updatedVars)
value.Help, err = interpolate(value.Help, vars, nil)
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This fix works around interpolate() skipping the updatedVars merge when keys are missing and the updated value is "" by explicitly cloning vars before interpolating help. However, the same interpolate() behavior can still affect other calls in this function that pass updatedVars directly (eg env name interpolation and placeholder interpolation) whenever any of the updated vars are "" and the corresponding key is absent from vars. A more robust fix would be to adjust interpolate() to merge when a key is missing (not only when vars[key] != val), which would remove the need for special-case merges here and prevent similar edge cases elsewhere.

Copilot uses AI. Check for mistakes.
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.

Panic with ${env} in help for positional arguments

2 participants