Skip to content

feat: Implement azdo pipelines delete command #255

@tmeckel

Description

@tmeckel

Sub-issue of #116. Hardened spec — do not re-derive decisions. Mirrors az pipelines delete from the Azure CLI and the Python implementation at azure-dev-ops-cli-extension/azure-dev-ops/azuredevops/azext_devops/dev/pipelines/pipeline.py#L141-L154.

Command Description

Delete a pipeline (build definition) by ID or name. The command resolves the target (a positive integer is used directly; a string is resolved via GetDefinitions), issues a destructive DELETE against the Definitions REST 7.1 endpoint, and prints a success message on completion.

DELETE https://dev.azure.com/{organization}/{project}/_apis/build/definitions/{definitionId}?api-version=7.1

Note: The azdo CLI's pipelines delete operates on modern Pipelines / build definitions (i.e., it calls DeleteDefinition, not DeleteBuild). The legacy az pipelines build delete (which would call DeleteBuild on the Build resource) is not part of this issue — that is a separate concern tracked elsewhere (if needed).

Locked Decisions (do not re-derive)

# Decision Rationale
1 Use the vendored SDK build.Client.DeleteDefinition (not raw HTTP). Mock already generated at internal/mocks/build_client_mock.go:226. Consistent with the broader pipelines group.
2 The pipeline is identified by a positional PIPELINE argument ([ORGANIZATION/]PROJECT/PIPELINE). The target segment is resolved via a new shared.ResolvePipelineDefinition helper at internal/cmd/pipelines/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 and pick the first match. Folds the previous --id flag into the positional. Mirrors sibling leaves (#243, #257, #258). 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, "pipeline target is required"). Standard cobra pattern; the 1st positional is the full target.
4 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. The Python extension uses Knack's built-in confirmation with the message "Are you sure you want to delete this pipeline?" — replicate the same prompt text.
5 Output: a one-line success message Pipeline {id} was deleted successfully. written to stdout (mirrors the Python pipeline_delete). JSON output is not applicable (the SDK returns error, not a result). Mirrors Python output.
6 No new SDK client, no new helper beyond shared.ResolvePipelineDefinition, no new package beyond internal/cmd/pipelines/delete. Mandate: minimal code.
7 Mocks for GetDefinitions and DeleteDefinition are already generated. Do not regenerate. Verified at internal/mocks/build_client_mock.go:837 and :226.

Command Signature

azdo pipelines delete [ORGANIZATION/]PROJECT/PIPELINE
  [--yes]
  • 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
--yes (bool) confirmation skip Suppresses the destructive-operation prompt

Output Contract

On success, print to stdout:

Pipeline {id} was deleted successfully.

No JSON output path is provided (the SDK call returns no resource on success). If a user pipes through --json, the command should be a no-op for output purposes (or print null / {}). See internal/cmd/util/json_flags.go to confirm whether non-JSON-output commands support the --json flag at all; if not, do not register it.

Command Wiring

  • Package path: internal/cmd/pipelines/delete
  • Files:
    • delete.goNewCmd(ctx util.CmdContext) *cobra.Command + deleteOptions + runDelete
    • shared/resolve.go (under internal/cmd/pipelines/shared/) — ResolvePipelineDefinition(ctx, clientFact, raw) (int, error) (positive-int fast path + GetDefinitions first-match lookup)
    • delete_test.go — table-driven gomock tests
  • Update internal/cmd/pipelines/pipelines.go to add delete.NewCmd(ctx) as a top-level leaf (cmd.AddCommand(...)). Update the Example block.
  • Higher-level parents must already remain wired: pipelinesdelete (top-level).

API Surface

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

  • build.Client.GetDefinitions → for name → ID resolution.
  • build.Client.DeleteDefinitionDefinitions - Delete (REST 7.1)
  • build.DeleteDefinitionArgs struct: {DefinitionId *int, Project *string}.
  • The call returns error; success means the resource was removed.

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

Reference Existing Patterns

  • azure-dev-ops-cli-extension/azure-dev-ops/azuredevops/azext_devops/dev/pipelines/pipeline.py#L141-L154pipeline_delete Python implementation.
  • azure-dev-ops-cli-extension/azure-dev-ops/azuredevops/azext_devops/dev/pipelines/commands.py#L78g.command('delete', 'pipeline_delete', confirmation='Are you sure you want to delete this pipeline?').
  • internal/cmd/pipelines/variablegroup/delete/delete.goclosest delete sibling (project-scoped, similar flag surface, has its own umbrella feat: Introduce azdo pipelines variable-group subgroup #117). Mirrors the modern delete pattern, including the confirmation prompt and --yes flag. The shared resolver at internal/cmd/pipelines/variablegroup/shared/resolve.go (ResolveVariableGroup) is the closest precedent for shared.ResolvePipelineDefinition.
  • internal/cmd/boards/workitem/list/list_test.go:765-844setupFakeDeps / stub* fixture.
  • internal/mocks/build_client_mock.go:226 — mock for DeleteDefinition (already generated).
  • internal/mocks/build_client_mock.go:837 — mock for GetDefinitions (already generated, used for name → ID resolution).
  • internal/azdo/factory.go:61ClientFactory().Build(...) accessor (reuse).
  • internal/cmd/util/scope.go:183util.ParseProjectTargetWithDefaultOrganization (project-scoped parser).

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions