Skip to content

Commit

Permalink
feat: Add support for deleting Git runbooks (#444)
Browse files Browse the repository at this point in the history
  • Loading branch information
geofflamrock authored Dec 2, 2024
1 parent 438a28b commit 64915bc
Show file tree
Hide file tree
Showing 6 changed files with 448 additions and 24 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/OctopusDeploy/go-octodiff v1.0.0
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.59.0
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.62.0
github.com/bmatcuk/doublestar/v4 v4.4.0
github.com/briandowns/spinner v1.19.0
github.com/google/uuid v1.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63n
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/OctopusDeploy/go-octodiff v1.0.0 h1:U+ORg6azniwwYo+O44giOw6TiD5USk8S4VDhOQ0Ven0=
github.com/OctopusDeploy/go-octodiff v1.0.0/go.mod h1:Mze0+EkOWTgTmi8++fyUc6r0aLZT7qD9gX+31t8MmIU=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.59.0 h1:Yb2VqkRTFAAow/YQRVVuKbJSEzmSoCzUhj7q6uiL6Aw=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.59.0/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.62.0 h1:p2qapGMs+BGZfRmKa+1K6j7J9g+n6bxTWPZFeHZ/W0o=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.62.0/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
github.com/bmatcuk/doublestar/v4 v4.4.0 h1:LmAwNwhjEbYtyVLzjcP/XeVw4nhuScHGkF/XWXnvIic=
github.com/bmatcuk/doublestar/v4 v4.4.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/briandowns/spinner v1.19.0 h1:s8aq38H+Qju89yhp89b4iIiMzMm8YN3p6vGpwyh/a8E=
Expand Down
100 changes: 84 additions & 16 deletions pkg/cmd/runbook/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ package delete

import (
"errors"
"fmt"

"github.com/MakeNowJust/heredoc/v2"
"github.com/OctopusDeploy/cli/pkg/cmd"
"github.com/OctopusDeploy/cli/pkg/cmd/runbook/shared"
"github.com/OctopusDeploy/cli/pkg/constants"
"github.com/OctopusDeploy/cli/pkg/factory"
"github.com/OctopusDeploy/cli/pkg/output"
"github.com/OctopusDeploy/cli/pkg/question"
"github.com/OctopusDeploy/cli/pkg/question/selectors"
"github.com/OctopusDeploy/cli/pkg/util/flag"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
"github.com/spf13/cobra"
Expand All @@ -21,18 +23,21 @@ const resourceDescription = "runbook"
const (
FlagProject = "project"
FlagRunbook = "runbook"
FlagGitRef = "git-ref"
)

type DeleteFlags struct {
Project *flag.Flag[string]
Runbook *flag.Flag[string]
GitRef *flag.Flag[string]
SkipConfirmation bool
}

func NewDeleteFlags() *DeleteFlags {
return &DeleteFlags{
Project: flag.New[string](FlagProject, false),
Runbook: flag.New[string](FlagRunbook, false),
GitRef: flag.New[string](FlagGitRef, false),
}
}

Expand Down Expand Up @@ -71,45 +76,104 @@ func NewCmdDelete(f factory.Factory) *cobra.Command {
deleteFlags.Runbook.Value = args[0]
}

return deleteRun(opts)
return DeleteRun(opts)
},
}

flags := cmd.Flags()
flags.StringVarP(&deleteFlags.Project.Value, deleteFlags.Project.Name, "p", "", "Name or ID of the project to delete a runbook from")
flags.StringVarP(&deleteFlags.Runbook.Value, deleteFlags.Runbook.Name, "r", "", "Name or ID of the runbook to delete")
flags.StringVarP(&deleteFlags.GitRef.Value, deleteFlags.GitRef.Name, "", "", "Git reference to delete runbook for e.g. refs/heads/main. Only relevant for config-as-code projects where runbooks are stored in Git.")
question.RegisterConfirmDeletionFlag(cmd, &deleteFlags.SkipConfirmation, resourceDescription)

return cmd
}

func deleteRun(opts *DeleteOptions) error {
func DeleteRun(opts *DeleteOptions) error {
project, err := getProject(opts)
if err != nil {
return err
}

runbook, err := getRunbook(opts, project)
if err != nil {
return err
runbooksAreInGit := false

if project.PersistenceSettings.Type() == projects.PersistenceSettingsTypeVersionControlled {
runbooksAreInGit = project.PersistenceSettings.(projects.GitPersistenceSettings).RunbooksAreInGit()
}

if opts.SkipConfirmation {
return delete(opts.Client, runbook)
if runbooksAreInGit {
gitReference, err := getGitReference(opts, project)
if err != nil {
return err
}

runbook, err := getGitRunbook(opts, project, gitReference)
if err != nil {
return err
}

if opts.SkipConfirmation {
return deleteGitRunbook(opts, runbook, gitReference)
} else {
return question.DeleteWithConfirmation(opts.Ask, resourceDescription, runbook.Name, runbook.GetID(), func() error {
return deleteGitRunbook(opts, runbook, gitReference)
})
}
} else {
return question.DeleteWithConfirmation(opts.Ask, resourceDescription, runbook.Name, runbook.GetID(), func() error {
return delete(opts.Client, runbook)
runbook, err := getDbRunbook(opts, project)
if err != nil {
return err
}

if opts.SkipConfirmation {
return deleteDbRunbook(opts, runbook)
} else {
return question.DeleteWithConfirmation(opts.Ask, resourceDescription, runbook.Name, runbook.GetID(), func() error {
return deleteDbRunbook(opts, runbook)
})
}
}

}

func getDbRunbook(opts *DeleteOptions, project *projects.Project) (*runbooks.Runbook, error) {
var runbook *runbooks.Runbook
var err error
if opts.Runbook.Value == "" {
runbook, err = selectors.Select(opts.Ask, "Select the runbook you wish to delete:", func() ([]*runbooks.Runbook, error) { return opts.GetDbRunbooksCallback(project.GetID()) }, func(runbook *runbooks.Runbook) string { return runbook.Name })
} else {
runbook, err = opts.GetDbRunbookCallback(project.GetID(), opts.Runbook.Value)
}

if runbook == nil {
return nil, errors.New("unable to find runbook")
}

return runbook, err
}

func getGitReference(opts *DeleteOptions, project *projects.Project) (string, error) {
if opts.GitRef.Value == "" { // we need a git ref; ask for one
gitRef, err := selectors.Select(opts.Ask, "Select the Git reference to delete runbook for:", func() ([]*projects.GitReference, error) { return opts.GetGitReferencesCallback(project) }, func(gitReference *projects.GitReference) string {
return fmt.Sprintf("%s %s", gitReference.Name, output.Dimf("(%s)", gitReference.Type.Description()))
})
if err != nil {
return "", err
}
return gitRef.CanonicalName, nil // e.g /refs/heads/main
} else {
return opts.GitRef.Value, nil
}
}

func getRunbook(opts *DeleteOptions, project *projects.Project) (*runbooks.Runbook, error) {
func getGitRunbook(opts *DeleteOptions, project *projects.Project, gitRef string) (*runbooks.Runbook, error) {
var runbook *runbooks.Runbook
var err error

if opts.Runbook.Value == "" {
runbook, err = selectors.Select(opts.Ask, "Select the runbook you wish to delete:", func() ([]*runbooks.Runbook, error) { return opts.GetRunbooksCallback(project.GetID()) }, func(runbook *runbooks.Runbook) string { return runbook.Name })
runbook, err = selectors.Select(opts.Ask, "Select the runbook you wish to delete:", func() ([]*runbooks.Runbook, error) { return opts.GetGitRunbooksCallback(project.GetID(), gitRef) }, func(runbook *runbooks.Runbook) string { return runbook.Name })
} else {
runbook, err = selectors.FindRunbook(opts.Client, project, opts.Runbook.Value)
runbook, err = opts.GetGitRunbookCallback(project.GetID(), gitRef, opts.Runbook.Value)
}

if runbook == nil {
Expand All @@ -125,7 +189,7 @@ func getProject(opts *DeleteOptions) (*projects.Project, error) {
if opts.Project.Value == "" {
project, err = selectors.Select(opts.Ask, "Select the project containing the runbook you wish to delete:", opts.GetAllProjectsCallback, func(project *projects.Project) string { return project.GetName() })
} else {
project, err = selectors.FindProject(opts.Client, opts.Project.Value)
project, err = opts.GetProjectCallback(opts.Project.Value)
}

if project == nil {
Expand All @@ -135,6 +199,10 @@ func getProject(opts *DeleteOptions) (*projects.Project, error) {
return project, err
}

func delete(client *client.Client, itemToDelete *runbooks.Runbook) error {
return client.Runbooks.DeleteByID(itemToDelete.GetID())
func deleteDbRunbook(opts *DeleteOptions, runbook *runbooks.Runbook) error {
return opts.DeleteDbRunbookCallback(runbook)
}

func deleteGitRunbook(opts *DeleteOptions, runbook *runbooks.Runbook, gitRef string) error {
return opts.DeleteGitRunbookCallback(runbook, gitRef)
}
Loading

0 comments on commit 64915bc

Please sign in to comment.