Skip to content

feat: Implement azdo pipelines variable update command #129

@tmeckel

Description

@tmeckel

This issue tracks the implementation of the azdo pipelines variable update command.

Command Description

Update a pipeline variable’s name, value, secret flag, or allow-override flag on a classic build definition. The command must GET the definition, mutate the variables map, and PUT the full definition back (respecting revision). Secret values are never returned by the API; do not attempt to read or print them.

azdo Command Signature

azdo pipelines variable update [ORGANIZATION/]PROJECT/PIPELINE_ID_OR_NAME --name VARIABLE_NAME [flags]

Flags:

  • --new-name: Rename the variable.
  • --value: Replace the stored value.
  • --secret: Toggle secret flag (tri-state; only apply when flag is set).
  • --allow-override: Toggle queue-time override flag (tri-state; only apply when flag is set).
  • --prompt-value: For updating a secret without --value; prompt securely (or use AZDO_PIPELINES_VAR_<NAME> env).
  • JSON export flags (see JSON contract below).

At least one of --new-name, --value, --secret, --allow-override, or --prompt-value must be provided.

Behavior

  • Parse [ORGANIZATION/]PROJECT/PIPELINE_ID_OR_NAME via util.ParseProjectTargetWithDefaultOrganization; wrap errors with util.FlagErrorWrap.
  • Resolve pipeline:
    • If target is numeric, treat as definitionId.
    • Otherwise, resolve by name via Build Definitions - List, handling continuation tokens and returning an error on collisions (multiple matches).
  • GET the definition via Build GetDefinition.
  • Locate the variable by case-insensitive key; enforce rename uniqueness (case-insensitive).
  • Tri-state booleans: use Flags().Changed("secret") / Flags().Changed("allow-override") to distinguish “not specified” from “set to false.”
  • Secret handling:
    • Never log or print secret values.
    • Do not attempt to preserve an existing secret value by reading it (not available). Only change the secret value if --value or --prompt-value is provided.
  • Apply requested changes (name/value/secret/allowOverride), mutate the variables map, and PUT via UpdateDefinition, preserving unrelated definition fields and ensuring revision matches the GET result.
  • Stop progress before emitting results.
  • Output:
    • Single-object Go text template (not a list). Show name, secret, allowOverride, and value masked (***) when secret; otherwise show value.
  • JSON output:
    • Emit an augmented struct that adds name and embeds the SDK variable model; register fields with util.AddJSONFlags (e.g., name, value, isSecret, allowOverride, isReadOnly).
    • Secret values must be redacted/omitted (value nil for secret).

Implementation Notes (filled checklist)

  • Implement command: internal/cmd/pipelines/variable/update/update.go (type opts struct, NewCmd(ctx), run(ctx, opts)).
  • Wire command: internal/cmd/pipelines/variable/variable.go must AddCommand(update.NewCmd(ctx)) and be reachable from azdo pipelines.
  • Parse scope: util.ParseProjectTargetWithDefaultOrganization(ctx, targetArg); wrap parse errors with util.FlagErrorWrap.
  • Client: Build via ctx.ClientFactory().Build(ctx.Context(), scope.Organization).
  • Resolve pipeline: numeric ID or name via Definitions - List (with continuation and collision handling).
  • Update algorithm: GET definition → locate variable (case-insensitive) → enforce rename uniqueness → apply requested changes → PUT definition with matching revision.
  • Secret handling: never read/print existing secret values; only set a new secret when --value or --prompt-value is provided.
  • Output:
    • Template: single-object template for the updated variable; mask value as *** when secret.
    • JSON: augmented struct with name + embedded SDK variable fields; util.AddJSONFlags fields name, value, isSecret, allowOverride, isReadOnly; redact/omit secret value.
  • Tests:
    • Add internal/cmd/pipelines/variable/update/update_test.go.
    • Hermetic mocks: Build client + prompter (for prompt path).
    • Cases: rename collision, prompt-value path, missing flags validation, secret redaction, name resolution collisions, numeric ID path.

SDK / Client Requirements

  • Requires the Build client (ClientFactory().Build(...)) to fetch and update pipeline definitions. If missing, follow “Handling Missing Azure DevOps SDK Clients” in AGENTS.md.

References

  • Azure CLI implementation: pipeline_variable_update
  • REST: Definitions - List for name resolution; Definitions - Get/Update for variables (classic build definitions).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions