Skip to content

feat: support environment name abbreviations for --env flag - #11

Merged
andrest50 merged 3 commits into
mainfrom
feat/env-abbreviations
Sep 28, 2026
Merged

andrest50 merged 3 commits into
mainfrom
feat/env-abbreviations

Conversation

@andrest50

Copy link
Copy Markdown
Contributor

Summary

Adds support for abbreviated and alternate spellings of the --env flag value when running lfx auth login, so users can type shorter, more intuitive names without needing to remember the exact canonical string.

Accepted aliases

Canonical Also accepted
prod production
staging stage, stg
development develop, dev

Changes

  • internal/commands/environment.go — adds envAliases map and normalizeEnvironment() function; updates error message to list all accepted forms
  • internal/commands/auth.go — calls normalizeEnvironment() before resolving the environment; updates --env flag usage text
  • internal/commands/auth_test.go — adds TestNormalizeEnvironment, TestResolveEnvironmentAliases, and TestResolveEnvironmentUnknown
  • README.md — adds example lines showing alias usage

Testing

All existing tests pass; 3 new test functions covering every alias + the unknown-input error path.

=== RUN   TestNormalizeEnvironment      PASS
=== RUN   TestResolveEnvironmentAliases PASS
=== RUN   TestResolveEnvironmentUnknown PASS

Made with Cursor

@andrest50
andrest50 requested review from a team and emsearcy as code owners September 15, 2026 15:54
Copilot AI balanced review requested due to automatic review settings September 15, 2026 15:55
Add normalizeEnvironment() to map short-forms and alternate spellings to
the canonical authEnvironment constant before resolving IdP config:

  prod/production → prod
  staging/stage/stg → staging
  development/develop/dev → development

- environment.go: add envAliases map and normalizeEnvironment(); update
  resolveEnvironment error message to list all accepted forms
- auth.go: call normalizeEnvironment() in runAuthLogin; update --env flag
  Usage text to show alias groups
- auth_test.go: add TestNormalizeEnvironment, TestResolveEnvironmentAliases,
  and TestResolveEnvironmentUnknown covering every alias + unknown-input path
- README.md: add example lines showing alias usage

Signed-off-by: Andres Tobon <andrest2455@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@andrest50
andrest50 force-pushed the feat/env-abbreviations branch from 67a4d12 to c61eb14 Compare September 15, 2026 15:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@emsearcy

emsearcy commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Thanks for this — the alias mapping is correctly implemented and well-tested, but I'd like to push back on the overall approach before we merge.

Concern: multiple string values mapping to one canonical value

Having --env accept prod/production, staging/stage/stg, and development/develop/dev as synonyms for the same three canonical values adds a maintenance burden (the alias table, its tests, and the help/error text all need to stay in sync) without a proportional benefit. I'd prefer discrete values here rather than several spellings that all mean the same thing.

Alternative: discrete boolean flags per environment

Consider replacing the single --env <value> string flag with discrete flags instead, e.g. --dev, --staging, --prod (mutually exclusive, defaulting to --prod). A couple of reasons this is worth it long-term:

  1. urfave/cli/v3's built-in "did you mean" (Command.Suggest / SuggestDidYouMeanTemplate) actually applies here. That feature only corrects mistyped flag/command names, not flag values — so it doesn't help the current string-alias design at all. But if staging/dev/prod become flag names instead of flag values, a typo like --stagng would get a real "Did you mean --staging?" suggestion for free, which is a better fit for the SDK we're already on.
  2. It also composes more naturally with shell completion (already enabled via EnableShellCompletion: true — see #12 for a follow-up on documenting/packaging that): discrete flags show up directly in flag-name completion, whereas a single flag's valid values aren't completed out of the box.

Backward compatibility

This would be a breaking change for anyone already scripting --env staging/--env development/etc., so we'd need a deprecation path — e.g. keep --env accepting only the three canonical values (no aliases), mark it deprecated in Usage/README once the discrete flags land, and remove it in a later minor/major bump per our version-bump guidelines. Worth scoping as a separate follow-up rather than blocking this PR on a redesign.

Recommendation

I'd suggest holding off on merging the alias table as-is. Given the scope of a discrete-flag redesign (plus deprecation), it's worth a quick design discussion / follow-up issue rather than iterating further on this PR in place.

@andrest50

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review, @emsearcy — a couple of clarifications on the points raised:

On the breaking change: the concern in your comment is about your own proposed alternative (removing --env in favor of discrete flags like --dev/--staging/--prod), not about this PR. This PR only adds accepted aliases to the existing --env string flag — every existing invocation (--env prod, --env staging, --env development) continues to work identically. There is nothing to deprecate here.

On discrete flags: the alternative you describe would mean passing --dev or --staging as flag names, not --env=dev. That is a different interface shape from what the PR does, and from what the gh CLI precedent (--hostname <value>) suggests. I would also argue it makes scripting less readable — lfx auth login --env staging is more self-documenting than lfx auth login --staging.

On did-you-mean and shell completion: both are fair observations. Command.Suggest genuinely only applies to flag/command names, so it would not help a user who types --env devlopment. And flag-value completion is not wired up out of the box. These are real limitations of the string-flag approach. That said, aliases solve a different problem — reducing the cognitive load of memorizing development vs dev — and the two goals are not in conflict. The discrete-flag direction could still be explored as a follow-up without blocking or undoing what is here.

On maintenance burden: the alias map is 4 entries. The error message is one format string. The table-driven tests cover every alias in ~20 lines. I do not think this rises to the level of a meaningful ongoing cost.

Happy to discuss further, but I do not think there is a correctness or compatibility issue that warrants holding the PR. If the design preference for discrete flags is strong, I would suggest we track that as a separate issue rather than blocking this additive change.

Copilot AI review requested due to automatic review settings September 23, 2026 22:30
emsearcy
emsearcy previously approved these changes Sep 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Changing the persisted production identifier breaks existing authenticated sessions after upgrade.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity

Open (1)

Comment thread internal/commands/environment.go
Rename the canonical prod environment name to production (matching
staging and development already being full words). --env's usage text
and invalid-environment errors now mention only the three canonical
names instead of enumerating every accepted alias.

Add `lfx auth environments`, which lists each canonical name with its
aliases and default API audience, so that detail stays discoverable
without cluttering --env's own usage text.

Every place that reads a previously persisted
credstore.DeviceState.Environment (loadDeviceStateForBackend,
resolveAccessToken, and the `auth status` display) now runs it through
normalizeEnvironment, so state.json files written before the prod ->
production rename keep resolving correctly (via the existing "prod"
alias) without requiring a fresh `lfx auth login`.

Also drop backticks from flag Usage strings (--backend, --env,
--audience, --hostname): urfave/cli's help renderer treats the first
backtick-quoted substring in a flag's Usage as its value placeholder
(replacing the normal "string" type hint), so any backtick-quoted
command name there hijacked that column instead of rendering as
intended. Single quotes read the same without triggering it, in both
the terminal help and generated Markdown docs.

Also run go get -u ./... && go mod tidy, pinning golang.org/x/oauth2,
golang.org/x/sys, and golang.org/x/term just below their latest
patches (which now require go1.26) to keep go.mod's go directive at
1.25.14, matching this repo's toolchain policy of staying one minor
version behind MegaLinter's bundled Go (1.26.x).

Assisted-by: github-copilot:claude-sonnet-5
Signed-off-by: Eric Searcy <eric@linuxfoundation.org>
Copilot AI review requested due to automatic review settings September 23, 2026 22:37
@emsearcy
emsearcy force-pushed the feat/env-abbreviations branch from 2a56b5e to 0229040 Compare September 23, 2026 22:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Changing production’s canonical persisted value breaks rollback compatibility and contradicts the documented alias contract.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Resolved since last review (1)

Comment thread internal/commands/auth.go
emsearcy
emsearcy previously approved these changes Sep 23, 2026
@emsearcy
emsearcy dismissed their stale review September 25, 2026 18:47

dismissing so it's clear this is still waiting on a review

@dealako

dealako commented Sep 28, 2026 •

Copy link
Copy Markdown

@andrest50 I'm starting review 1 of this pull request now (started 2026-09-28 16:09 UTC). This usually takes a few minutes — I'll update this comment with the summary when I'm done.


@andrest50 thanks for the alias work — and thanks @emsearcy for the follow-up that renamed the canonical production value, added lfx auth environments, and fixed the upgrade path for persisted "prod". The mapping itself is small, consistent, and the helper tests plus TestLoadDeviceStateForBackendLegacyProdEnvironment cover the important read-side cases. Nothing here is merge-blocking.

  • 🔴 Blocking: 0 issues
  • 🟡 Minor: 1 issue: alias handling is only unit-tested on helpers, not through lfx auth login
  • ⚪ Nit: 2 issues: README leads the development example with dev; environments command Usage still uses backticks
  • ❔ Question: 1 item: new logins persist "production", which v1.0.x binaries reject

Prior round: Copilot's upgrade-path break (discussion) is resolved in 0229040. Copilot's still-open request for a command-level auth environments test (discussion) stands — I agree and am not duplicating it.

✅ Approved with minor comments

@dealako dealako left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@andrest50 alias mapping, the production rename, and the persisted-prod upgrade path look solid. One test-gap minor, a couple of nits, and a downgrade-compat question — none of them block merge.

  • 🔴 Blocking: 0
  • 🟡 Minor: 1 — lfx auth login never exercises aliases end-to-end
  • ⚪ Nit: 2 — README leads with dev; environments Usage still uses backticks
  • ❔ Question: 1 — new logins persist production, which v1.0.x rejects

Agree with Copilot on the still-open auth environments command test (#11 (comment)); not repeating it here. Copilot's original prod→production upgrade break is fixed in 0229040.

✅ Approved with minor comments

Comment thread internal/commands/auth.go
Usage: "Target environment: prod, staging, or development",
Value: string(envProd),
Usage: "Target environment; see 'lfx auth environments' for accepted values",
Value: string(envProduction),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[question] New logins persist "production", which released v1.0.x binaries reject

Issue: The renamed constant is also the value saved to DeviceState.Environment. A default lfx auth login (and --env=prod, after normalize) now writes "environment": "production" to state.json. Read-side normalize fixes the upgrade path; it does not help an older binary reading the new file.

Proof: --env defaults to string(envProduction) here. runAuthLogin normalizes to envProduction, then loginWithToken / loginWithDeviceCode persist Environment: string(env) (auth.go:179, auth.go:282). v1.0.1 (envProd = "prod", Latest) keys authDomains by "prod" and calls resolveEnvironment(authEnvironment(state.Environment)) with no alias step, so it errors invalid environment: "production".

Why it matters: Downgrading, or running a v1.0.x binary alongside this build against the same state dir, breaks lfx auth token / lfx api until the user logs in again with the older binary. Credentials stay in the keyring; only state.json becomes unreadable to v1.0.x.

Fix: If downgrade compatibility matters, keep writing the legacy production value ("prod") while still displaying production — normalizeEnvironment already reads both. If it does not, call that out in the release notes (going back to v1.0.x requires lfx auth login again).

Comment thread internal/commands/auth.go
}

env := authEnvironment(cmd.String(envFlagName))
env := normalizeEnvironment(cmd.String(envFlagName))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[minor] No test exercises alias handling through lfx auth login

Issue: This is the only place aliases are applied to user input. The new tests cover normalizeEnvironment / resolveEnvironment in isolation. Dropping this call, or passing the raw flag into defaultAudienceForEnvironment, would break lfx auth login --env=dev while every test still passed.

Proof: No *_test.go references runAuthLogin or loginWithToken. The --with-token path does not hit the network: it reads stdin and saves through credStoreFromCommand. --insecure-storage plus t.Setenv("XDG_STATE_HOME", t.TempDir()) is already a tested seam elsewhere (api_test.go swaps stdin).

Why it matters: Accepting aliases in lfx auth login is the user-facing feature. Helper tests can stay green while the command itself is unwired.

Fix: Table-test a root command (Flags: CredentialStoreFlags, Commands: NewAuthCommand()) with --insecure-storage auth login --with-token --env=<alias> for prod / stg / dev, piping a dummy refresh token on stdin. Assert the saved DeviceState has the canonical Environment, matching IDPDomain, and that environment's default audience.

Comment thread README.md

# Log in against a non-production environment (aliases accepted).
lfx auth login --env staging # also: stage, stg
lfx auth login --env dev # also: develop, development

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[nit] Show canonical --env names in the README and point to lfx auth environments

Issue: The staging example leads with the canonical name; the development example leads with the alias dev and lists development under "also". The README also never mentions the new lfx auth environments command, even though --backend already points at lfx auth backends.

Proof: Canonical names are production / staging / development (environment.go:21-25). After lfx auth login --env dev, auth status prints Environment: development because login persists the normalized value. AGENTS.md asks to update the README for user-facing changes.

Why it matters: The README teaches an alias as the primary spelling, which fights this PR's move to full-word canonical names and what auth status / auth environments print.

Fix: Lead with the canonical names and point at the new command, e.g.

# Aliases are accepted; run `lfx auth environments` for the full list.
lfx auth login --env staging       # aliases: stage, stg
lfx auth login --env development   # aliases: dev, develop

Comment thread internal/commands/auth.go
func newAuthEnvironmentsCommand() *cli.Command {
return &cli.Command{
Name: "environments",
Usage: "List --env values accepted by `lfx auth login`, including aliases and default audiences",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[nit] Use single quotes in the environments command Usage, like the rest of the help text

Issue: This PR switched flag Usage that names a command to single quotes ('lfx auth backends', 'lfx auth environments'). This new command Usage still wraps lfx auth login in backticks — it is now the only Usage string in internal/commands that still has them.

Proof: Flag Usage runs through urfave/cli's unquoteUsage (the original reason backticks were removed). Command Usage is printed as-is, so these backticks show up literally next to sibling commands that use no quoting, and next to --env's single-quoted 'lfx auth environments'.

Why it matters: Help output mixes quoting styles for the same kind of command reference. No behavioral break; consistency only.

Fix: Usage: "List --env values accepted by 'lfx auth login', including aliases and default audiences"

@andrest50
andrest50 merged commit 8e0e207 into main Sep 28, 2026
9 checks passed
@andrest50
andrest50 deleted the feat/env-abbreviations branch September 28, 2026 16:39
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.

4 participants