Skip to content

feat: Implement azdo pipelines build queue command #253

Description

@tmeckel

Sub-issue of #213. Hardened spec — do not re-derive decisions. Mirrors az pipelines build queue from the Azure CLI and the Python implementation at azure-dev-ops-cli-extension/azure-devops/azext_devops/dev/pipelines/build.py#L26-L75.

Command Description

Request (queue) a new build from a build definition identified by either ID or name. The command resolves the definition (a positive integer is used directly; a string is resolved via GetDefinitions), constructs a Build with the requested branch, commit, and (optional) variables, and posts it to the Build REST 7.1 endpoint. The returned Build is the queued build (including its new id, buildNumber, and status: notStarted | queued).

POST https://dev.azure.com/{organization}/{project}/_apis/build/builds?api-version=7.1

Locked Decisions (do not re-derive)

# Decision Rationale
1 Use the vendored SDK build.Client.QueueBuild (not raw HTTP). Mock already generated at internal/mocks/build_client_mock.go:1227. Consistent with build list (#211) and build show (#241).
2 The definition is identified by a positional DEFINITION argument ([ORGANIZATION/]PROJECT/DEFINITION). The target segment is resolved via a new shared.ResolvePipelineDefinition helper at internal/cmd/pipelines/build/queue/shared/resolve.go that mirrors Python's get_definition_id_from_name: if it parses as a positive integer, use it directly; otherwise call build.Client.GetDefinitions(name=...) and pick the first match. Folds the previous --definition-id and --definition-name flags into a single positional. Mirrors az pipelines build queue ergonomics with one positional for either ID or name.
2.5 Parse the positional using util.ParseProjectTargetWithDefaultOrganization from internal/cmd/util/scope.go:183. The function returns a *Target with Organization, Project, Target fields, accepting 2- or 3-segment inputs. Mirrors internal/cmd/pipelines/variablegroup/{create,delete,show,update}/ precedent.
3 util.ExactArgs(1, "definition target is required"). Standard cobra pattern; the 1st positional is the full target.
4 Variables are accepted via repeatable --variable flag (each name=value). Internally accumulated into a map[string]string and serialized into the Build.Parameters JSON map. Mirrors Azure CLI ergonomics; replaces Python's space-separated list.
5 Optional flags: --branch (string, accepts main, refs/heads/main, or refs/pull/1/merge — the SDK normalizes), --commit-id (string), --queue-id (int), --open (bool) — opens the build results page in the user's default browser. Mirrors Python build_queue parameters.
6 Default output is a table. JSON output via --json passes a dedicated view struct buildJSON (the same shape as build show (#241) uses) to opts.exporter.Write. Mirrors internal/cmd/pipelines/build/list/list.go (#211).
7 No confirmation prompt. Queueing is non-destructive. Queueing is reversible (cancel via #TBD).
8 No new SDK client, no new helper beyond shared.ResolvePipelineDefinition, no new package beyond internal/cmd/pipelines/build/queue. Mandate: minimal code.
9 Mocks for QueueBuild and GetDefinitions are already generated. Do not regenerate. Verified at internal/mocks/build_client_mock.go:1227 and :837.

Command Signature

azdo pipelines build queue [ORGANIZATION/]PROJECT/DEFINITION
  [--branch BRANCH]
  [--commit-id COMMIT_ID]
  [--variable NAME=VALUE]         (repeatable)
  [--queue-id QUEUE_ID]           (int)
  [--open]
  [--json ...]
  • cobra.ExactArgs(1)args[0] → target (via util.ParseProjectTargetWithDefaultOrganization).
  • The Target field of the parsed *Target is resolved via shared.ResolvePipelineDefinition(ctx, clientFact, args[0]).

Flags

Flag Maps to Notes
--branch (str) Build.SourceBranch Auto-prefixes refs/heads/ if absent
--commit-id (str) Build.SourceVersion Specific commit SHA
--variable (str, repeatable) Build.Parameters (JSON map) name=value per occurrence
--queue-id (int) Build.Queue.Id Override the default queue
--open (bool) post-action Opens the build results page in the user's default browser
--json / --jq / --template util.AddJSONFlags JSON export

JSON Output Contract

The JSON view struct mirrors build show (#241). Fields (matching SDK struct JSON tags):

type buildJSON struct {
    ID          *int    `json:"id,omitempty"`
    Number      *string `json:"buildNumber,omitempty"`
    Status      *string `json:"status,omitempty"`
    Result      *string `json:"result,omitempty"`
    DefinitionID   *int    `json:"definitionId,omitempty"`
    DefinitionName *string `json:"definitionName,omitempty"`
    SourceBranch   *string `json:"sourceBranch,omitempty"`
    QueueTime      *string `json:"queueTime,omitempty"`
    Reason         *string `json:"reason,omitempty"`
    RequestedBy    *string `json:"requestedFor,omitempty"`
}

Table Output Contract

Default columns: ID, NUMBER, STATUS, RESULT, DEFINITION ID, DEFINITION NAME, SOURCE BRANCH, QUEUED TIME, REASON (mirrors transform_build_table_output from _format.py).

Command Wiring

  • Package path: internal/cmd/pipelines/build/queue
  • Files:
    • queue.goNewCmd(ctx util.CmdContext) *cobra.Command + queueOptions + runQueue
    • shared/resolve.goResolvePipelineDefinition(ctx, clientFact, raw) (int, error) (positive-int fast path + GetDefinitions first-match lookup)
    • queue_test.go — table-driven gomock tests
  • Update internal/cmd/pipelines/build/build.go to add queue.NewCmd(ctx) to cmd.AddCommand(...). Update the Example block.
  • Higher-level parents must already remain wired: pipelinesbuildqueue.

API Surface

Reuse the already-vendored client. No new SDK clients or mocks required.

  • build.Client.GetDefinitionsDefinitions - List (REST 7.1) — for name → ID resolution.
  • build.Client.QueueBuildBuilds - Queue (REST 7.1)
  • build.QueueBuildArgs struct: {Build *Build, Project *string}.
  • build.GetDefinitionsArgs struct: {Project *string, Name *string, Path *string}.
  • The implementation constructs a Build populated with Definition.Id, SourceBranch, SourceVersion, Parameters (from --variable), and Queue.Id (from --queue-id).

Mocks for QueueBuild (:1227) and GetDefinitions (:837) are already generated. No mock regeneration needed.

Reference Existing Patterns

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions