Skip to content

Honor env sources on duplicated flags#2355

Merged
dearchap merged 1 commit into
urfave:mainfrom
ibobgunardi:bobi/duplicate-flag-env-sources
Jun 7, 2026
Merged

Honor env sources on duplicated flags#2355
dearchap merged 1 commit into
urfave:mainfrom
ibobgunardi:bobi/duplicate-flag-env-sources

Conversation

@ibobgunardi
Copy link
Copy Markdown

@ibobgunardi ibobgunardi commented Jun 7, 2026

What type of PR is this?

  • bug

What this PR does / why we need it:

  • Preserves env-source values when the same persistent flag instance is registered on an ancestor command and a subcommand.
  • Skips re-preparing a shared persistent flag instance on descendant commands so the value loaded during the parent parse is not reset.
  • Adds regression coverage for duplicated persistent flag env sources.

Which issue(s) this PR fixes:

Fixes #2217

Special notes for your reviewer:

The main behavior to review is the exact flag-instance check for inherited persistent flags.

Testing

  • go test ./... -run TestDuplicatePersistentFlagUsesEnvSource -count=1 -v
  • go test ./... -run "TestPersistentFlag|TestDuplicatePersistentFlagUsesEnvSource|TestRequiredPersistentFlag|TestCommand_IsSet_fromEnv|TestCheckRequiredFlags" -count=1 -v
  • go test ./... -count=1

Release Notes

Fixed env-source values being reset when the same persistent flag instance is registered on a parent command and subcommand.

@ibobgunardi ibobgunardi requested a review from a team as a code owner June 7, 2026 10:06
@dearchap
Copy link
Copy Markdown
Contributor

dearchap commented Jun 7, 2026

@ibobgunardi Can you follow the PR template when submitting a PR ? Thanks

dearchap
dearchap previously approved these changes Jun 7, 2026
Copy link
Copy Markdown
Contributor

@dearchap dearchap left a comment

Choose a reason for hiding this comment

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

Root Cause

When the same flag instance is registered on both a parent and subcommand, FlagBase.PreParse() re-initializes f.value to the default (f.Value) without checking f.applied. This overwrites the env-sourced value set by the parents PostParse()`.

Meanwhile, FlagBase.PostParse() guards with f.hasBeenSet, which is already true (set by the parent`s PostParse), so it skips re-reading the env var. End result: the subcommand gets the zero/default value instead of the env value.

Fix Validation

hasPersistentFlagOnAncestor() uses pointer equality to detect the shared instance, and the PreParse skip in command_run.go:144-146 correctly:

  1. Prevents the destructive re-initialization on the subcommand
  2. Preserves the env (or CLI-arg) value already set on the parent
  3. PostParse respects hasBeenSet and does not overwrite

Test Coverage

The test TestDuplicatePersistentFlagUsesEnvSource covers:

  • Env source read by the parentsBefore` handler ✓
  • Env source value propagated to the subcommands Action` ✓
  • IsSet() returning true on both parent and subcommand ✓

LGTM.

@ibobgunardi
Copy link
Copy Markdown
Author

Updated the description to follow the PR template. Thanks for the reminder.

@dearchap dearchap dismissed their stale review June 7, 2026 16:05

Undoing approval - user requested

Copy link
Copy Markdown
Contributor

@dearchap dearchap left a comment

Choose a reason for hiding this comment

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

Good question about f.applied in PreParse. I tested it — two regressions:

  1. TestSliceStringFlagParsing — PreParse re-creates f.value from scratch (via f.creator.Create). Without it, Set() appends to the existing slice, causing cross-sub-test value leakage. e.g. expected ["x", "y"], got ["x", "x", "y"].

  2. TestRequiredFlagDelayedapplied being true on a shared flag instance prevents PreParse from running on the leaf command, altering required-flag behavior that non-shared flags depend on.

applied serves dual roles (prevent recursion + track initialization), so adding it to PreParse is too broad. The pointer-equality/ancestor check is correctly scoped. LGTM.

@dearchap dearchap merged commit 700c663 into urfave:main Jun 7, 2026
9 checks passed
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.

Environment variables not read when flag is defined on both root and subcommand

2 participants