You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Cancel a running or queued build by ID. The command fetches the build, sets its status to "Cancelling", and posts the update via the Build REST 7.1 endpoint. The returned Build reflects the post-update state (typically status: cancelling).
The request body is a Build resource whose only mutated field is status: "Cancelling".
Note:az pipelines build cancel accepts a numeric build ID; it has no name resolution path (builds are immutable records and have no displayable name in the same way definitions do). The BUILD positional segment must parse as a positive integer; non-numeric values are rejected with util.FlagErrorf.
Locked Decisions (do not re-derive)
#
Decision
Rationale
1
Use the vendored SDK build.Client.UpdateBuild (not raw HTTP). Mock already generated at internal/mocks/build_client_mock.go:1286.
Consistent with build list (#211) and build show (#241).
2
The build is identified by a positional BUILD argument ([ORGANIZATION/]PROJECT/BUILD). The BUILD segment must parse as a positive integer (no name resolution — builds are numeric). Folds the previous --id flag into the positional.
Mirrors az pipelines build cancel ergonomics.
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.
util.ExactArgs(1, "build target is required"). The Target field is parsed as int; non-numeric / zero / negative values rejected with util.FlagErrorf before the SDK call.
Cheap pre-flight validation; REST 4xx is unhelpful.
4
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.
The command issues a destructive mutation; require a confirmation prompt unless --yes is supplied. On cancel return util.ErrCancel.
AGENTS.md: Confirmation for Destructive Operations.
6
No --open flag. The Python extension supports --open; the azdo CLI renders a Go-formatted result instead and the user is unlikely to need a browser redirect mid-cancel.
Keep the surface minimal.
7
No new SDK client, no new helper, no new package beyond internal/cmd/pipelines/build/cancel.
Mandate: minimal code.
8
Mock for UpdateBuild is already generated at internal/mocks/build_client_mock.go:1286. Do not regenerate.
internal/cmd/pipelines/variablegroup/delete/delete.go — primary target-resolution precedent (Decision 2 / 2.5): uses Use: "delete [ORGANIZATION/]PROJECT/GROUP", util.ExactArgs(1, "..."), util.ParseProjectTargetWithDefaultOrganization, and a shared.ResolveVariableGroup helper. Our cancel differs only in (a) target is always a numeric build ID, no name lookup; (b) the destructive confirmation prompt uses "Are you sure you want to cancel this build?".
internal/cmd/pipelines/build/list/list.go (feat: Implement azdo pipelines build list command #211) — primary list reference for the modern list pattern, JSON view struct, table printer, and --max-items cap. cancel does not use --max-items; the table emits exactly one row.
Sub-issue of #213. Hardened spec — do not re-derive decisions. Mirrors
az pipelines build cancelfrom the Azure CLI and the Python implementation atazure-devops/azext_devops/dev/pipelines/build.py#L106.Command Description
Cancel a running or queued build by ID. The command fetches the build, sets its status to
"Cancelling", and posts the update via the Build REST 7.1 endpoint. The returnedBuildreflects the post-update state (typicallystatus: cancelling).The request body is a
Buildresource whose only mutated field isstatus: "Cancelling".Locked Decisions (do not re-derive)
build.Client.UpdateBuild(not raw HTTP). Mock already generated atinternal/mocks/build_client_mock.go:1286.build list(#211) andbuild show(#241).BUILDargument ([ORGANIZATION/]PROJECT/BUILD). TheBUILDsegment must parse as a positive integer (no name resolution — builds are numeric). Folds the previous--idflag into the positional.az pipelines build cancelergonomics.util.ParseProjectTargetWithDefaultOrganizationfrominternal/cmd/util/scope.go:183. The function returns a*TargetwithOrganization,Project,Targetfields, accepting 2- or 3-segment inputs.internal/cmd/pipelines/variablegroup/{create,delete,show,update}/precedent.util.ExactArgs(1, "build target is required"). TheTargetfield is parsed asint; non-numeric / zero / negative values rejected withutil.FlagErrorfbefore the SDK call.--jsonpasses a dedicated view structbuildJSON(the same shape asbuild show(#241) uses) toopts.exporter.Write.internal/cmd/pipelines/build/list/list.go(#211).--yesis supplied. On cancel returnutil.ErrCancel.--openflag. The Python extension supports--open; theazdoCLI renders a Go-formatted result instead and the user is unlikely to need a browser redirect mid-cancel.internal/cmd/pipelines/build/cancel.UpdateBuildis already generated atinternal/mocks/build_client_mock.go:1286. Do not regenerate.Command Signature
cobra.ExactArgs(1)—args[0]→ target (viautil.ParseProjectTargetWithDefaultOrganization).Targetfield is parsed asint; non-numeric / zero / negative values rejected withutil.FlagErrorf.Flags
--yes(bool)--json/--jq/--templateutil.AddJSONFlagsJSON Output Contract
The JSON view struct mirrors
build show(#241). Fields (matching SDK struct JSON tags):Table Output Contract
Default columns:
ID, NUMBER, STATUS, RESULT, DEFINITION ID, DEFINITION NAME, SOURCE BRANCH, QUEUED TIME, REASON(mirrorstransform_build_table_outputfrom_format.py).Command Wiring
internal/cmd/pipelines/build/cancelcancel.go—NewCmd(ctx util.CmdContext) *cobra.Command+cancelOptions+runCancelcancel_test.go— table-driven gomock testsinternal/cmd/pipelines/build/build.goto addcancel.NewCmd(ctx)tocmd.AddCommand(...). Update theExampleblock.pipelines→build→cancel.API Surface
Reuse the already-vendored client. No new SDK clients or mocks required.
build.Client.UpdateBuild→ Builds - Update (REST 7.1)build.UpdateBuildArgsstruct:{Build *Build, Project *string, BuildId *int}.Build{Status: types.ToPtr("Cancelling")}and posts it toUpdateBuild.Mock for
UpdateBuildis already generated atinternal/mocks/build_client_mock.go:1286. No mock regeneration needed.Reference Existing Patterns
azure-dev-ops-cli-extension/azure-dev-ops/azuredevops/azext_devops/dev/pipelines/build.py#L106-L120—build_cancelPython implementation.azure-dev-ops-cli-extension/azure-dev-ops/azuredevops/azext_devops/dev/pipelines/commands.py#L92—g.command('cancel', 'build_cancel', table_transformer=transform_build_table_output).azure-dev-ops-cli-extension/azure-dev-ops/azuredevops/azext_devops/dev/pipelines/_format.py—transform_build_table_output(single-row) and_transform_build_row(row builder).internal/cmd/pipelines/variablegroup/delete/delete.go— primary target-resolution precedent (Decision 2 / 2.5): usesUse: "delete [ORGANIZATION/]PROJECT/GROUP",util.ExactArgs(1, "..."),util.ParseProjectTargetWithDefaultOrganization, and ashared.ResolveVariableGrouphelper. Ourcanceldiffers only in (a) target is always a numeric build ID, no name lookup; (b) the destructive confirmation prompt uses "Are you sure you want to cancel this build?".internal/cmd/pipelines/build/list/list.go(feat: Implementazdo pipelines build listcommand #211) — primary list reference for the modern list pattern, JSON view struct, table printer, and--max-itemscap.canceldoes not use--max-items; the table emits exactly one row.internal/cmd/pipelines/build/show/show.go(feat: Implementazdo pipelines build showcommand #241) — primary show sibling; reuse the samebuildJSONview struct.internal/cmd/boards/workitem/list/list_test.go:765-844—setupFakeDeps/stub*fixture.internal/mocks/build_client_mock.go:1286— mock forUpdateBuild(already generated).internal/azdo/factory.go:61—ClientFactory().Build(...)accessor (reuse).internal/cmd/util/scope.go:183—util.ParseProjectTargetWithDefaultOrganization(project-scoped parser).References
azext_devops/dev/pipelines/build.pyazext_devops/dev/pipelines/commands.pyazext_devops/dev/pipelines/_format.py