Skip to content

feat: Introduce azdo pipelines runs command group #214

Description

@tmeckel

Command Group Description

Introduce a new runs subgroup under the existing azdo pipelines command group (umbrella tracked in #116). The runs subgroup is a thin router: it has no leaf commands of its own at the moment — it currently exists to register the list leaf (tracked in #212) and to be the natural home for future modern-Pipelines-API commands (e.g. show, cancel).

The runs subgroup surfaces the modern Azure Pipelines API surface (the az pipelines runs group from the Azure CLI). It is distinct from the build subgroup (#213), which surfaces the legacy Azure DevOps Build API surface. Both subgroups share the same vendored SDK client (build.Client) — the split is purely CLI ergonomics to match the Azure CLI's terminology and Python extension's command group registration.

Why two subgroups against the same SDK call? The Azure CLI and Python extension both expose pipelines build and pipelines runs as separate groups with different flag names (--definition-ids vs --pipeline-ids), different default tables, and different subcommand sets. azdo mirrors that user-facing split exactly. Internally, both groups call the same build.Client.GetBuilds method because the Azure DevOps REST API does not differentiate "builds" from "runs" — they are the same resource. Documenting this explicitly here so future implementers do not assume a duplicate SDK call exists.

Implementation Notes

  • The runs subgroup has no behavior of its own. Its sole responsibility is to register child leaf commands via cmd.AddCommand(...).
  • The first child is azdo pipelines runs list (tracked in feat: Implement azdo pipelines runs list command #212). Future children will follow the same leaf issue template.
  • No new SDK client is required — build.Client is already wired in internal/azdo/connection.go:50-51 (interface) and internal/azdo/factory.go:61 (impl). No new mocks are required — MockBuildClient is fully present.
  • No new shared helpers are required for this parent. Future shared logic across multiple runs leaves (e.g. a common runTableRow helper) may be extracted into this package's runs.go or a separate internal/cmd/pipelines/runs/shared package — do not pre-extract.
  • The Use: line should be runs (no description on the Use line itself; the Short and Long fields provide description text).
  • Aliases are not provided on group commands; only on leaf commands.

Command Wiring

  1. Create internal/cmd/pipelines/runs/runs.go:
package runs

import (
	"github.com/spf13/cobra"

	"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/runs/list"
	"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/runs/show"
	"github.com/tmeckel/azdo-cli/internal/cmd/util"
)

func NewCmd(ctx util.CmdContext) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "runs",
		Short: "Manage Azure DevOps pipeline runs (modern Pipelines API).",
		Long: `Surface for the modern Azure Pipelines API.

Mirrors the 'az pipelines runs' group from the Azure CLI. Routes to child
commands that operate on pipeline runs and their artifacts.`,
	}

	cmd.AddCommand(list.NewCmd(ctx))
	cmd.AddCommand(show.NewCmd(ctx))   // new in #242
	return cmd
}
  1. Register the new subgroup in the existing umbrella at internal/cmd/pipelines/pipelines.go:
import (
	// ... existing imports ...
	"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/build"
	"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/runs"
	// ...
)

func NewCmd(ctx util.CmdContext) *cobra.Command {
	cmd := &cobra.Command{ /* ... existing ... */ }
	cmd.AddCommand(variablegroup.NewCmd(ctx))
	cmd.AddCommand(variable.NewCmd(ctx))
	cmd.AddCommand(build.NewCmd(ctx))     // new in #213
	cmd.AddCommand(runs.NewCmd(ctx))      // new in #214
	return cmd
}
  1. No change is required to internal/cmd/root/root.go (the pipelines group is already registered).

SDK / Client Requirements

The same client powers both pipelines build (#213) and pipelines runs (#214). The Azure DevOps REST API does not differentiate "builds" from "runs" — they are the same resource, and the SDK exposes a single Build resource. The azdo CLI matches the Azure CLI's user-facing split while internally sharing the same SDK call. (Reference: azure-dev-ops-cli-extension/azure-devops/azext_devops/dev/pipelines/pipeline_run.py imports the same build client as build.py.)

Sub-Issues

Each new leaf will be filed as a follow-up issue using the same canonical 12-section body format. When filed, the issue number will replace the placeholder in the checklist above.

Tooling & Validation

  • go build ./... is clean.
  • go test ./internal/cmd/pipelines/runs/... passes.
  • go run cmd/azdo/azdo.go pipelines runs --help renders the subgroup's short and long descriptions and lists list and show as children.
  • go run cmd/azdo/azdo.go pipelines --help shows runs alongside variable-group, variable, and build.
  • make lint passes (golangci-lint, per .golangci.yml).
  • make docs regenerates docs/pipelines_runs.md with the new subgroup.

References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions