ποΈ Resolve WS_* env defaults from env.reference.yaml#12
Merged
Conversation
Adds `IsWorkspace()` and `RequireWorkspace()` to `internals/config` using the image-baked manifest as the detection signal, then wires a single `PersistentPreRunE` on the root command so every subcommand exits 1 with a styled error when run outside the workspace.
Single source of truth for every `WS_*` var moves to
`env.reference.yaml`. New `internals/config/{envref,resolve,format}.go`
parses the YAML once per process (path-keyed cache), exposes
`Resolve(group, prop)` for internal callers and `ResolveKey(runtimeKey)`
for the CLI surface, with typed sugars for bool/int/list. Deprecation
chains collapse transitively to the canonical target; cycles are
rejected. New `ws-cli show env <KEY>` subcommand under the existing
`show` family resolves env values for shell consumption with
`--raw|--list|--bool|--int|--check` flags. Existing const-driven
callsites in `cmd/feature`, `cmd/show/path`, `internals/{logger,
metrics,secrets}` swept onto the resolver. `WS__INTERNAL_*` namespace
stays out of scope as ws-cli's internal wiring layer.
`(*EnvReference).Resolve` returns just `string` (it never errored). Drop the local `defaultEnvReferencePath` const β moved into `internals/config/defaults.go` alongside the other path constants. Reuse `env.String` for env lookups in the resolver chain and `Check`. Collapse the four nested `yaml*` intermediate types into one anonymous struct in `parseEnvReference`. Switch-based `ParseBool` replaces the two package-level truthy/falsy maps.
`MustResolve(group, prop)` panics on YAML-load failure. Use it in
callers without fallback semantics β `cmd/show/path.go`,
`internals/logger/logger.go`, `internals/metrics/system.go` β
where missing YAML means the workspace is fundamentally broken
anyway. Multi-branch fallback paths in `internals/secrets/{key,
vault}.go` keep the error-returning `Resolve` form.
`cmd/root.go`'s `PersistentPreRunE` eager-loads the YAML alongside
`RequireWorkspace()` so YAML failure surfaces once at startup
through cobra's error path, not deep inside random commands.
`ResolveKey` short-circuits when the env var is set explicitly β
avoids loading the YAML when callers don't actually need the
default lookup. Lets tests that set every env var run without
installing a YAML fixture.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
internals/config/{envref,resolve,format}.goparsesenv.reference.yamlonce per process (path-keyed cache, auto-invalidates onWS__INTERNAL_ENV_REFERENCEoverride). ExposesResolve(group, prop)for internal callers andResolveKey(runtimeKey)for the CLI surface, with typed sugars for bool/int/list. Deprecation chains collapse transitively to the canonical target; cycles rejected.ws-cli show env <KEY>subcommand under the existingshowfamily β flags--raw|--list|--bool|--int|--check. Stderr deprecation lines match the retired Pythonentrypoint/check-deprecated-envbyte-for-byte so bash callers grepping the existing strings keep working. Exit codes for--check:0preferred set /1deprecated only or unset /2both set.cmd/feature,cmd/show/path,internals/{logger,metrics,secrets}swept onto the resolver. The user-facingEnv*/Default*env-default consts ininternals/config/defaults.goare deleted;WS__INTERNAL_*namespace stays out of scope as ws-cli's wiring layer.Why
Today every
WS_*default exists in two places:env.reference.yaml(the canonical schema) andinternals/config/defaults.goas Go consts. Drift is a question of when, not if. This PR moves ws-cli to read defaults at runtime from the YAML, which becomes the single source of truth.This is phase 1 of a two-phase rollout (
lockstep-ws-cli):show envsubcommand + tagged release.workspace):env.reference.yamlschema gainsdelimiter:field;common.sh:check_env_setrewires to delegate tows-cli show env --check; Pythonentrypoint/check-deprecated-envretires.Test plan
go test ./...β all packages green (full Vera matrix ininternals/config/resolve_test.go: bool truthy/falsy variants, int boundaries + overflow, list whitespace + unicode + delimiter overrides, deprecation chain collapse + cycle rejection, warn-once + byte-for-byte stderr).cmd/show/show_test.goextended forshow envflag dispatch, exit codes, mutually-exclusive flags, fixture-driven YAML loading viat.Setenv+t.TempDir()(path-keyed cache invalidates without test-only reset hooks).go vet ./...clean.pre-commit run --all-filesclean.ws-cli show env WS_SERVER_ROOT --rawagainst a running workspace once merged + tagged.Out of scope (deferred to phase 2)
env.reference.yamldelimiter:schema field +WS__INTERNAL_ENV_REFERENCEdeclaration.workspace/src/build/dependencies/dependencies.yamlws-cliversion:bump (Renovate will open it oncev0.0.51is tagged).common.sh:check_env_setrewire.entrypoint/check-deprecated-envretirement.AC 5 audit (non-test)
rg '"WS_[A-Z_]+"' ws-cli/{cmd,internals}excluding*_test.go: 4 documented exceptions βinternals/config/defaults.goβEnvIPCSocket(transitional;_internal:namespace stays as Go const).internals/config/envref.goβos.Getenv("WS__INTERNAL_ENV_REFERENCE")loader bootstrap.internals/secrets/{key.go, vault.go}β twoos.LookupEnvcalls preserving "user-misconfig produces specific error" / "env-set bypasses default file-existence check" semantics from the original code.