fix: variable update in non-interactive mode clears all existing variables#196
Conversation
…ables `variable update -i=false -k "NEW=val"` silently deletes all existing variables because: 1. `runUpdateVariable` unconditionally resets `opts.keys` with `make(map[string]string)`, wiping the CLI-parsed `--key` values 2. `runUpdateVariableNonInteractive` passes this empty/partial map directly to `UpdateVariables`, which is a full-replace API The fix follows the same fetch-and-merge pattern already used by `variable create` (create.go:115-127) and `variable delete` (delete.go:138-145): - Move `make(map[string]string)` into the interactive branch only - Fetch existing variables before calling UpdateVariables - Merge user-provided keys on top of existing ones - Start the spinner (was missing `s.Start()`) Also fixes: - `variable create` interactive: `strings.Split` → `strings.SplitN` to handle values containing `=` (e.g. DATABASE_URL=postgres://...?ssl=require) - Typo: `varableDeleteCmd` → `variableDeleteCmd` in variable.go Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WalkthroughThree changes to the variable command handling: the create command now accepts values containing Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
internal/cmd/variable/update/update.go (1)
107-118: Consider adding validation for empty keys in non-interactive mode.When
--keyis not provided,opts.keyswill benil, and the update becomes a no-op (existing vars are fetched, nothing is merged, and the same vars are written back). This is safe but potentially confusing for users.💡 Optional: Add early validation
func runUpdateVariableNonInteractive(f *cmdutil.Factory, opts *Options) error { + if len(opts.keys) == 0 { + return fmt.Errorf("--key is required in non-interactive mode") + } + if opts.id == "" && opts.name != "" {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/cmd/variable/update/update.go` around lines 107 - 118, Add an early validation in runUpdateVariableNonInteractive to error when no keys are provided in non-interactive mode: check opts.keys (or the single-key flag if applicable) after resolving opts.id and if it is nil/empty return a clear error like "--key is required when not running interactively". Update the function runUpdateVariableNonInteractive to perform this check before fetching/merging variables so the command fails fast and avoids a no-op update.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@internal/cmd/variable/update/update.go`:
- Around line 107-118: Add an early validation in
runUpdateVariableNonInteractive to error when no keys are provided in
non-interactive mode: check opts.keys (or the single-key flag if applicable)
after resolving opts.id and if it is nil/empty return a clear error like "--key
is required when not running interactively". Update the function
runUpdateVariableNonInteractive to perform this check before fetching/merging
variables so the command fails fast and avoids a no-op update.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 98ecaf3c-dc9b-4d6c-a992-ba55a39dead5
📒 Files selected for processing (3)
internal/cmd/variable/create/create.gointernal/cmd/variable/update/update.gointernal/cmd/variable/variable.go
The warning that `variable update` clears all vars was a known CLI bug (zeabur/cli#196) that has been fixed. The `zeabur-variables` skill already correctly documents that `variable update` only updates specified keys, but this skill still had the outdated caveat causing contradiction. Also split the workflow example into separate create/update steps to clarify when to use each subcommand. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The warning that `variable update` clears all vars was a known CLI bug (zeabur/cli#196) that has been fixed. The `zeabur-variables` skill already correctly documents that `variable update` only updates specified keys, but this skill still had the outdated caveat causing contradiction. Also split the workflow example into separate create/update steps to clarify when to use each subcommand. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
variable update -i=false -k "NEW=val"silently deletes all existing variables. This is a data-loss bug.Root cause
Two issues combine to cause this:
runUpdateVariable()(update.go:44) unconditionally resetsopts.keyswithmake(map[string]string), wiping the CLI-parsed--keyvalues before they reach the handlerrunUpdateVariableNonInteractive()passes this empty/partial map directly toUpdateVariables(), which is a full-replace API — unmentioned variables get deletedInteractive mode is unaffected because
runUpdateVariableInteractivefetches all existing variables and rebuilds the map before calling the non-interactive handler.Fix
Follow the same fetch-and-merge pattern already used by
variable create(create.go:115-127) andvariable delete(delete.go:138-145):make(map[string]string)into the interactive branch only (don't wipe CLI args)UpdateVariabless.Start())Additional fixes in this PR
variable createinteractive:strings.Split(input, "=")→strings.SplitN(input, "=", 2)— values containing=(e.g.,DATABASE_URL=postgres://host/db?sslmode=require) were rejected as invalid inputvarableDeleteCmd→variableDeleteCmdin variable.goTest plan
zeabur variable update -i=false --id <svc> -k "NEW_VAR=hello"should addNEW_VARwithout affecting existing variableszeabur variable update -i=false --id <svc> -k "EXISTING=new_value"should update only that keyvariable updateshould still work as beforezeabur variable createinteractive withDATABASE_URL=postgres://host?ssl=requireshould succeed🤖 Generated with Claude Code
Summary by CodeRabbit
=characters.