diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index bbafcbecb32b1..3f1904e5fd6c9 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -1,6 +1,7 @@ package cli_test import ( + "io" "os" "testing" @@ -197,6 +198,53 @@ func TestTemplateCreate(t *testing.T) { require.EqualError(t, <-execDone, "Parameter value absent in parameter file for \"region\"!") removeTmpDirUntilSuccess(t, tempDir) }) + + t.Run("Recreate template with same name (create, delete, create)", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) + coderdtest.CreateFirstUser(t, client) + + create := func() error { + source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: provisionCompleteWithAgent, + }) + args := []string{ + "templates", + "create", + "my-template", + "--yes", + "--directory", source, + "--test.provisioner", string(database.ProvisionerTypeEcho), + } + cmd, root := clitest.New(t, args...) + clitest.SetupConfig(t, client, root) + cmd.SetOut(io.Discard) + cmd.SetErr(io.Discard) + + return cmd.Execute() + } + del := func() error { + args := []string{ + "templates", + "delete", + "my-template", + } + cmd, root := clitest.New(t, args...) + clitest.SetupConfig(t, client, root) + cmd.SetOut(io.Discard) + cmd.SetErr(io.Discard) + + return cmd.Execute() + } + + err := create() + require.NoError(t, err, "Template must be created without error") + err = del() + require.NoError(t, err, "Template must be deleted without error") + err = create() + require.NoError(t, err, "Template must be recreated without error") + }) } func createTestParseResponse() []*proto.Parse_Response { diff --git a/cli/templatedelete.go b/cli/templatedelete.go index 26ba6ca2a01f1..e698335c672a6 100644 --- a/cli/templatedelete.go +++ b/cli/templatedelete.go @@ -76,7 +76,7 @@ func templateDelete() *cobra.Command { return xerrors.Errorf("delete template %q: %w", template.Name, err) } - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Deleted template "+cliui.Styles.Code.Render(template.Name)+"!") + _, _ = fmt.Fprintln(cmd.OutOrStdout(), "Deleted template "+cliui.Styles.Code.Render(template.Name)+"!") } return nil diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index dee75904e13e7..61dae91780ed3 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -399,9 +399,6 @@ ALTER TABLE ONLY template_versions ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name); -ALTER TABLE ONLY templates - ADD CONSTRAINT templates_organization_id_name_key UNIQUE (organization_id, name); - ALTER TABLE ONLY templates ADD CONSTRAINT templates_pkey PRIMARY KEY (id); @@ -453,13 +450,11 @@ CREATE UNIQUE INDEX idx_organization_name ON organizations USING btree (name); CREATE UNIQUE INDEX idx_organization_name_lower ON organizations USING btree (lower(name)); -CREATE UNIQUE INDEX idx_templates_name_lower ON templates USING btree (lower((name)::text)); - CREATE UNIQUE INDEX idx_users_email ON users USING btree (email); CREATE UNIQUE INDEX idx_users_username ON users USING btree (username); -CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, name) WHERE (deleted = false); +CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, lower((name)::text)) WHERE (deleted = false); CREATE UNIQUE INDEX users_username_lower_idx ON users USING btree (lower(username)); diff --git a/coderd/database/migrations/000026_allow_template_name_re_use.down.sql b/coderd/database/migrations/000026_allow_template_name_re_use.down.sql new file mode 100644 index 0000000000000..8b58f9fdcac21 --- /dev/null +++ b/coderd/database/migrations/000026_allow_template_name_re_use.down.sql @@ -0,0 +1,5 @@ +DROP INDEX templates_organization_id_name_idx; +CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates USING btree (organization_id, name) WHERE deleted = false; +CREATE UNIQUE INDEX idx_templates_name_lower ON templates USING btree (lower(name)); + +ALTER TABLE ONLY templates ADD CONSTRAINT templates_organization_id_name_key UNIQUE (organization_id, name); diff --git a/coderd/database/migrations/000026_allow_template_name_re_use.up.sql b/coderd/database/migrations/000026_allow_template_name_re_use.up.sql new file mode 100644 index 0000000000000..7aebd5ca751f3 --- /dev/null +++ b/coderd/database/migrations/000026_allow_template_name_re_use.up.sql @@ -0,0 +1,5 @@ +DROP INDEX idx_templates_name_lower; +DROP INDEX templates_organization_id_name_idx; +CREATE UNIQUE INDEX templates_organization_id_name_idx ON templates (organization_id, lower(name)) WHERE deleted = false; + +ALTER TABLE ONLY templates DROP CONSTRAINT templates_organization_id_name_key;