From d05f3311ce12a681d6fbf485202336c80dee9fda Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 12 Jul 2023 13:36:05 +0200 Subject: [PATCH 1/6] Flag: create --- cli/templatepush.go | 7 +++++++ cli/testdata/coder_templates_push_--help.golden | 3 +++ docs/cli/templates_push.md | 9 +++++++++ 3 files changed, 19 insertions(+) diff --git a/cli/templatepush.go b/cli/templatepush.go index bc5516b092ef9..93b0a34151a1c 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -163,6 +163,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd { provisionerTags []string uploadFlags templateUploadFlags activate bool + create bool ) client := new(codersdk.Client) cmd := &clibase.Cmd{ @@ -290,6 +291,12 @@ func (r *RootCmd) templatePush() *clibase.Cmd { Default: "true", Value: clibase.BoolOf(&activate), }, + { + Flag: "create", + Description: "Create the template if it does not exist.", + Default: "false", + Value: clibase.BoolOf(&create), + }, cliui.SkipPromptOption(), } cmd.Options = append(cmd.Options, uploadFlags.options()...) diff --git a/cli/testdata/coder_templates_push_--help.golden b/cli/testdata/coder_templates_push_--help.golden index 6aeff1641fd0d..7dc7b2e87ff7f 100644 --- a/cli/testdata/coder_templates_push_--help.golden +++ b/cli/testdata/coder_templates_push_--help.golden @@ -10,6 +10,9 @@ Push a new template version from the current directory or as specified by flag Always prompt all parameters. Does not pull parameter values from active template version. + --create bool (default: false) + Create the template if it does not exist. + -d, --directory string (default: .) Specify the directory to create from, use '-' to read tar from stdin. diff --git a/docs/cli/templates_push.md b/docs/cli/templates_push.md index 4043de558198b..fb3068ed5b15d 100644 --- a/docs/cli/templates_push.md +++ b/docs/cli/templates_push.md @@ -29,6 +29,15 @@ Whether the new template will be marked active. Always prompt all parameters. Does not pull parameter values from active template version. +### --create + +| | | +| ------- | ------------------ | +| Type | bool | +| Default | false | + +Create the template if it does not exist. + ### -d, --directory | | | From ceebc7580dabb7e70581ef0013c0cfd9c55de815 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 12 Jul 2023 14:44:56 +0200 Subject: [PATCH 2/6] Create the template if it does not exist --- cli/templatepush.go | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/cli/templatepush.go b/cli/templatepush.go index 93b0a34151a1c..8798602f0a142 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -186,8 +186,11 @@ func (r *RootCmd) templatePush() *clibase.Cmd { return err } + var templateExists bool template, err := client.TemplateByName(inv.Context(), organization.ID, name) - if err != nil { + if create && err == nil { + templateExists = true + } else if !create && err != nil { return err } @@ -208,19 +211,24 @@ func (r *RootCmd) templatePush() *clibase.Cmd { return err } - job, err := createValidTemplateVersion(inv, createValidTemplateVersionArgs{ - Name: versionName, + args := createValidTemplateVersionArgs{ Message: message, Client: client, Organization: organization, Provisioner: database.ProvisionerType(provisioner), FileID: resp.ID, + ProvisionerTags: tags, VariablesFile: variablesFile, Variables: variables, - Template: &template, - ReuseParameters: !alwaysPrompt, - ProvisionerTags: tags, - }) + } + + if templateExists { + args.Name = versionName + args.Template = &template + args.ReuseParameters = !alwaysPrompt + } + + job, err := createValidTemplateVersion(inv, args) if err != nil { return err } @@ -229,7 +237,19 @@ func (r *RootCmd) templatePush() *clibase.Cmd { return xerrors.Errorf("job failed: %s", job.Job.Status) } - if activate { + if !templateExists { + _, err = client.CreateTemplate(inv.Context(), organization.ID, codersdk.CreateTemplateRequest{ + Name: name, + VersionID: job.ID, + }) + if err != nil { + return err + } + + _, _ = fmt.Fprintln(inv.Stdout, "\n"+cliui.DefaultStyles.Wrap.Render( + "The "+cliui.DefaultStyles.Keyword.Render(name)+" template has been created at "+cliui.DefaultStyles.DateTimeStamp.Render(time.Now().Format(time.Stamp))+"! "+ + "Developers can provision a workspace with this template using:")+"\n") + } else if activate { err = client.UpdateActiveTemplateVersion(inv.Context(), template.ID, codersdk.UpdateActiveTemplateVersion{ ID: job.ID, }) From 9401f385ea3203a981d934ae36bfe9dd979be096 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 12 Jul 2023 15:41:17 +0200 Subject: [PATCH 3/6] Unit test --- cli/templatepush_test.go | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index c890ea6593b94..e78b5bad82b26 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -613,6 +613,48 @@ func TestTemplatePush(t *testing.T) { require.Equal(t, "second_variable", templateVariables[1].Name) require.Equal(t, "foobar", templateVariables[1].Value) }) + + t.Run("CreateTemplate", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionApply: provisionCompleteWithAgent, + }) + + const templateName = "my-template" + args := []string{ + "templates", + "push", + templateName, + "--directory", source, + "--test.provisioner", string(database.ProvisionerTypeEcho), + "--create", + } + inv, root := clitest.New(t, args...) + clitest.SetupConfig(t, client, root) + pty := ptytest.New(t).Attach(inv) + + waiter := clitest.StartWithWaiter(t, inv) + + matches := []struct { + match string + write string + }{ + {match: "Upload", write: "yes"}, + } + for _, m := range matches { + pty.ExpectMatch(m.match) + pty.WriteLine(m.write) + } + + waiter.RequireSuccess() + + template, err := client.TemplateByName(context.Background(), user.OrganizationID, templateName) + require.NoError(t, err) + require.Equal(t, templateName, template.Name) + }) }) } From 836b9d2cd0440d763f75974a711b0529a6d9c3f7 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 12 Jul 2023 15:46:13 +0200 Subject: [PATCH 4/6] fix --- cli/templatepush_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index e78b5bad82b26..d87ce626d7c76 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -654,6 +655,7 @@ func TestTemplatePush(t *testing.T) { template, err := client.TemplateByName(context.Background(), user.OrganizationID, templateName) require.NoError(t, err) require.Equal(t, templateName, template.Name) + require.NotEqual(t, uuid.Nil, template.ActiveVersionID) }) }) } From 9fd4c97359eaff22b7821c81da50a798278bae87 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 12 Jul 2023 15:49:20 +0200 Subject: [PATCH 5/6] fix --- cli/templatepush.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cli/templatepush.go b/cli/templatepush.go index 8798602f0a142..524cd0287e883 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -186,12 +186,14 @@ func (r *RootCmd) templatePush() *clibase.Cmd { return err } - var templateExists bool + var createTemplate bool template, err := client.TemplateByName(inv.Context(), organization.ID, name) - if create && err == nil { - templateExists = true - } else if !create && err != nil { - return err + if err != nil { + if create { + createTemplate = true + } else { + return err + } } err = uploadFlags.checkForLockfile(inv) @@ -222,7 +224,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd { Variables: variables, } - if templateExists { + if !createTemplate { args.Name = versionName args.Template = &template args.ReuseParameters = !alwaysPrompt @@ -237,7 +239,7 @@ func (r *RootCmd) templatePush() *clibase.Cmd { return xerrors.Errorf("job failed: %s", job.Job.Status) } - if !templateExists { + if createTemplate { _, err = client.CreateTemplate(inv.Context(), organization.ID, codersdk.CreateTemplateRequest{ Name: name, VersionID: job.ID, From c503d156860777eb1a67624b645b17128311324a Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 13 Jul 2023 09:46:31 +0200 Subject: [PATCH 6/6] tests --- cli/templatepush.go | 5 ++--- cli/templatepush_test.go | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cli/templatepush.go b/cli/templatepush.go index 524cd0287e883..1b0639e55c2af 100644 --- a/cli/templatepush.go +++ b/cli/templatepush.go @@ -189,11 +189,10 @@ func (r *RootCmd) templatePush() *clibase.Cmd { var createTemplate bool template, err := client.TemplateByName(inv.Context(), organization.ID, name) if err != nil { - if create { - createTemplate = true - } else { + if !create { return err } + createTemplate = true } err = uploadFlags.checkForLockfile(inv) diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index d87ce626d7c76..88a1ce250543c 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -644,10 +644,13 @@ func TestTemplatePush(t *testing.T) { write string }{ {match: "Upload", write: "yes"}, + {match: "template has been created"}, } for _, m := range matches { pty.ExpectMatch(m.match) - pty.WriteLine(m.write) + if m.write != "" { + pty.WriteLine(m.write) + } } waiter.RequireSuccess()