Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/azdo_help_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,20 @@ Aliases
view, status
```

### `azdo pipelines delete [ORGANIZATION/]PROJECT/PIPELINE [flags]`

Delete a pipeline definition

```
-y, --yes Skip the confirmation prompt.
```

Aliases

```
d, del, rm
```

### `azdo pipelines list [ORGANIZATION/]PROJECT [flags]`

List pipeline definitions
Expand Down
8 changes: 8 additions & 0 deletions docs/azdo_pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Manage Azure DevOps pipelines
### Available commands

* [azdo pipelines agent](./azdo_pipelines_agent.md)
* [azdo pipelines delete](./azdo_pipelines_delete.md)
* [azdo pipelines list](./azdo_pipelines_list.md)
* [azdo pipelines pool](./azdo_pipelines_pool.md)
* [azdo pipelines runs](./azdo_pipelines_runs.md)
Expand All @@ -15,6 +16,13 @@ Manage Azure DevOps pipelines

- `p`

### Examples

```bash
# Delete a pipeline definition
azdo pipelines delete Fabrikam/42 --yes
```

### See also

* [azdo](./azdo.md)
41 changes: 41 additions & 0 deletions docs/azdo_pipelines_delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
## Command `azdo pipelines delete`

```
azdo pipelines delete [ORGANIZATION/]PROJECT/PIPELINE [flags]
```

Delete a pipeline definition by ID or name.

The command prompts for confirmation unless --yes is supplied.


### Options


* `-y`, `--yes`

Skip the confirmation prompt.


### ALIASES

- `d`
- `del`
- `rm`

### Examples

```bash
# Delete a pipeline by ID using the default organization
azdo pipelines delete Fabrikam/42 --yes

# Delete a pipeline by name
azdo pipelines delete 'myorg/Fabrikam/My Pipeline'

# Delete with confirmation
azdo pipelines delete Fabrikam/MyPipeline
```

### See also

* [azdo pipelines](./azdo_pipelines.md)
129 changes: 129 additions & 0 deletions internal/cmd/pipelines/delete/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package delete

import (
"fmt"

"github.com/MakeNowJust/heredoc/v2"
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/build"
"github.com/spf13/cobra"
"go.uber.org/zap"

"github.com/tmeckel/azdo-cli/internal/cmd/pipelines/shared"
"github.com/tmeckel/azdo-cli/internal/cmd/util"
"github.com/tmeckel/azdo-cli/internal/types"
)

type deleteOptions struct {
targetArg string
yes bool
}

func NewCmd(ctx util.CmdContext) *cobra.Command {
opts := &deleteOptions{}

cmd := &cobra.Command{
Use: "delete [ORGANIZATION/]PROJECT/PIPELINE",
Short: "Delete a pipeline definition",
Long: heredoc.Doc(`
Delete a pipeline definition by ID or name.

The command prompts for confirmation unless --yes is supplied.
`),
Example: heredoc.Doc(`
# Delete a pipeline by ID using the default organization
azdo pipelines delete Fabrikam/42 --yes

# Delete a pipeline by name
azdo pipelines delete 'myorg/Fabrikam/My Pipeline'

# Delete with confirmation
azdo pipelines delete Fabrikam/MyPipeline
`),
Aliases: []string{
"d",
"del",
"rm",
},
Args: util.ExactArgs(1, "pipeline target is required"),
RunE: func(cmd *cobra.Command, args []string) error {
opts.targetArg = args[0]
return runDelete(ctx, opts)
},
}

cmd.Flags().BoolVarP(&opts.yes, "yes", "y", false, "Skip the confirmation prompt.")

return cmd
}

func runDelete(cmdCtx util.CmdContext, opts *deleteOptions) error {
ios, err := cmdCtx.IOStreams()
if err != nil {
return err
}
ios.StartProgressIndicator()
defer ios.StopProgressIndicator()

scope, err := util.ParseProjectTargetWithDefaultOrganization(cmdCtx, opts.targetArg)
if err != nil {
return util.FlagErrorWrap(err)
}

buildClient, err := cmdCtx.ClientFactory().Build(cmdCtx.Context(), scope.Organization)
if err != nil {
return fmt.Errorf("failed to create Build client: %w", err)
}

pipelineID, err := shared.ResolvePipelineDefinition(cmdCtx, buildClient, scope.Project, scope.Targets[0])
if err != nil {
return err
}

zap.L().Debug(
"resolved pipeline definition",
zap.String("organization", scope.Organization),
zap.String("project", scope.Project),
zap.String("input", scope.Targets[0]),
zap.Int("pipelineId", pipelineID),
)

if !opts.yes {
if !ios.CanPrompt() {
return util.FlagErrorf("--yes required when not running interactively")
}
ios.StopProgressIndicator()
prompter, err := cmdCtx.Prompter()
if err != nil {
return err
}
confirmed, err := prompter.Confirm("Are you sure you want to delete this pipeline?", false)
if err != nil {
return err
}
if !confirmed {
zap.L().Debug("pipeline deletion canceled by user", zap.Int("pipelineId", pipelineID))
return util.ErrCancel
}
ios.StartProgressIndicator()
}

if err := buildClient.DeleteDefinition(cmdCtx.Context(), build.DeleteDefinitionArgs{
Project: types.ToPtr(scope.Project),
DefinitionId: types.ToPtr(pipelineID),
}); err != nil {
return fmt.Errorf("failed to delete pipeline %d: %w", pipelineID, err)
}

zap.L().Debug(
"pipeline definition deleted",
zap.String("organization", scope.Organization),
zap.String("project", scope.Project),
zap.Int("pipelineId", pipelineID),
)

ios.StopProgressIndicator()

// ponytail: SDK delete returns no resource, so keep stdout text only.
fmt.Fprintf(ios.Out, "Pipeline %d was deleted successfully.\n", pipelineID)
return nil
}
Loading
Loading