Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
86 changes: 86 additions & 0 deletions cli/templatedelete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cli

import (
"fmt"

"github.com/spf13/cobra"
"golang.org/x/xerrors"

"github.com/coder/coder/cli/cliui"
"github.com/coder/coder/codersdk"
)

func templateDelete() *cobra.Command {
return &cobra.Command{
Use: "delete [name]",
Args: cobra.MaximumNArgs(1),
Short: "Delete a template.",
RunE: func(cmd *cobra.Command, args []string) error {
var (
ctx = cmd.Context()
templateNames = []string{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can only be a max of 1 right? I don't believe this needs to be an array!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to remove the max 1 limit! I think it's nicer if we take in more than one since it plays nicer with xargs.

templates = []codersdk.Template{}
)

client, err := createClient(cmd)
if err != nil {
return err
}
organization, err := currentOrganization(cmd, client)
if err != nil {
return err
}

if len(args) > 0 {
templateNames = args
} else {
allTemplates, err := client.TemplatesByOrganization(ctx, organization.ID)
if err != nil {
return xerrors.Errorf("get templates by organization: %w", err)
}

if len(allTemplates) == 0 {
return xerrors.Errorf("no templates exist in the current organization %q", organization.Name)
}

opts := make([]string, 0, len(allTemplates))
for _, template := range allTemplates {
opts = append(opts, template.Name)
}

selection, err := cliui.Select(cmd, cliui.SelectOptions{
Options: opts,
})
if err != nil {
return xerrors.Errorf("select template: %w", err)
}

for _, template := range allTemplates {
if template.Name == selection {
templates = append(templates, template)
}
}
}

for _, templateName := range templateNames {
template, err := client.TemplateByName(ctx, organization.ID, templateName)
if err != nil {
return xerrors.Errorf("get template by name: %w", err)
}

templates = append(templates, template)
}

for _, template := range templates {
err := client.DeleteTemplate(ctx, template.ID)
if err != nil {
return xerrors.Errorf("delete template %q: %w", template.Name, err)
}

_, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Deleted template "+cliui.Styles.Code.Render(template.Name)+"!")
}

return nil
},
}
}
64 changes: 64 additions & 0 deletions cli/templatedelete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cli_test

import (
"context"
"testing"

"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/pty/ptytest"
"github.com/davecgh/go-spew/spew"
"github.com/stretchr/testify/require"
)

func TestTemplateDelete(t *testing.T) {
t.Parallel()

t.Run("Ok", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_ = coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)

cmd, root := clitest.New(t, "templates", "delete", template.Name)
clitest.SetupConfig(t, client, root)
require.NoError(t, cmd.Execute())

template, err := client.Template(context.Background(), template.ID)
spew.Dump(template, err)
require.Error(t, err, "template should not exist")
})

t.Run("Selector", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_ = coderdtest.NewProvisionerDaemon(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)

cmd, root := clitest.New(t, "templates", "delete")
clitest.SetupConfig(t, client, root)

pty := ptytest.New(t)
cmd.SetIn(pty.Input())
cmd.SetOut(pty.Output())

execDone := make(chan error)
go func() {
execDone <- cmd.Execute()
}()

pty.WriteLine("docker-local")
require.NoError(t, <-execDone)

_, err := client.Template(context.Background(), template.ID)
require.Error(t, err, "template should not exist")
})
}
1 change: 1 addition & 0 deletions cli/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func templates() *cobra.Command {
templatePlan(),
templateUpdate(),
templateVersions(),
templateDelete(),
)

return cmd
Expand Down
6 changes: 6 additions & 0 deletions coderd/httpmw/templateparam.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ func ExtractTemplateParam(db database.Store) func(http.Handler) http.Handler {
return
}

if template.Deleted {
httpapi.Write(rw, http.StatusNotFound, httpapi.Response{
Message: fmt.Sprintf("template %q does not exist", templateID),
})
}

ctx := context.WithValue(r.Context(), templateParamContextKey{}, template)
chi.RouteContext(ctx).URLParams.Add("organization", template.OrganizationID.String())
next.ServeHTTP(rw, r.WithContext(ctx))
Expand Down
1 change: 1 addition & 0 deletions coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
// Returns a single template.
func (api *api) template(rw http.ResponseWriter, r *http.Request) {
template := httpmw.TemplateParam(r)

workspaceCounts, err := api.Database.GetWorkspaceOwnerCountsByTemplateIDs(r.Context(), []uuid.UUID{template.ID})
if errors.Is(err, sql.ErrNoRows) {
err = nil
Expand Down