From 191449078cbe0146620b27b74f4156826f276829 Mon Sep 17 00:00:00 2001 From: Joobi S B Date: Fri, 11 Oct 2024 18:30:11 +0530 Subject: [PATCH] feat: implement feature to support template version while creating workspace using cli (#14880) --- cli/create.go | 23 +++++++-- cli/create_test.go | 64 +++++++++++++++++++++++++ cli/testdata/coder_create_--help.golden | 3 ++ docs/reference/cli/create.md | 9 ++++ 4 files changed, 95 insertions(+), 4 deletions(-) diff --git a/cli/create.go b/cli/create.go index 5384ec094f..49002777cf 100644 --- a/cli/create.go +++ b/cli/create.go @@ -22,10 +22,11 @@ import ( func (r *RootCmd) create() *serpent.Command { var ( - templateName string - startAt string - stopAfter time.Duration - workspaceName string + templateName string + templateVersion string + startAt string + stopAfter time.Duration + workspaceName string parameterFlags workspaceParameterFlags autoUpdates string @@ -202,6 +203,14 @@ func (r *RootCmd) create() *serpent.Command { templateVersionID = template.ActiveVersionID } + if len(templateVersion) > 0 { + version, err := client.TemplateVersionByName(inv.Context(), template.ID, templateVersion) + if err != nil { + return xerrors.Errorf("get template version by name: %w", err) + } + templateVersionID = version.ID + } + // If the user specified an organization via a flag or env var, the template **must** // be in that organization. Otherwise, we should throw an error. orgValue, orgValueSource := orgContext.ValueSource(inv) @@ -314,6 +323,12 @@ func (r *RootCmd) create() *serpent.Command { Description: "Specify a template name.", Value: serpent.StringOf(&templateName), }, + serpent.Option{ + Flag: "template-version", + Env: "CODER_TEMPLATE_VERSION", + Description: "Specify a template version name.", + Value: serpent.StringOf(&templateVersion), + }, serpent.Option{ Flag: "start-at", Env: "CODER_WORKSPACE_START_AT", diff --git a/cli/create_test.go b/cli/create_test.go index b6294f50b4..1f505d0523 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -133,6 +133,70 @@ func TestCreate(t *testing.T) { } }) + t.Run("CreateWithSpecificTemplateVersion", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + owner := coderdtest.CreateFirstUser(t, client) + member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent()) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) + + // Create a new version + version2 := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent(), func(ctvr *codersdk.CreateTemplateVersionRequest) { + ctvr.TemplateID = template.ID + }) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version2.ID) + + args := []string{ + "create", + "my-workspace", + "--template", template.Name, + "--template-version", version2.Name, + "--start-at", "9:30AM Mon-Fri US/Central", + "--stop-after", "8h", + "--automatic-updates", "always", + } + inv, root := clitest.New(t, args...) + clitest.SetupConfig(t, member, root) + doneChan := make(chan struct{}) + pty := ptytest.New(t).Attach(inv) + go func() { + defer close(doneChan) + err := inv.Run() + assert.NoError(t, err) + }() + matches := []struct { + match string + write string + }{ + {match: "compute.main"}, + {match: "smith (linux, i386)"}, + {match: "Confirm create", write: "yes"}, + } + for _, m := range matches { + pty.ExpectMatch(m.match) + if len(m.write) > 0 { + pty.WriteLine(m.write) + } + } + <-doneChan + + ws, err := member.WorkspaceByOwnerAndName(context.Background(), codersdk.Me, "my-workspace", codersdk.WorkspaceOptions{}) + if assert.NoError(t, err, "expected workspace to be created") { + assert.Equal(t, ws.TemplateName, template.Name) + // Check if the workspace is using the new template version + assert.Equal(t, ws.LatestBuild.TemplateVersionID, version2.ID, "expected workspace to use the specified template version") + if assert.NotNil(t, ws.AutostartSchedule) { + assert.Equal(t, *ws.AutostartSchedule, "CRON_TZ=US/Central 30 9 * * Mon-Fri") + } + if assert.NotNil(t, ws.TTLMillis) { + assert.Equal(t, *ws.TTLMillis, 8*time.Hour.Milliseconds()) + } + assert.Equal(t, codersdk.AutomaticUpdatesAlways, ws.AutomaticUpdates) + } + }) + t.Run("InheritStopAfterFromTemplate", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) diff --git a/cli/testdata/coder_create_--help.golden b/cli/testdata/coder_create_--help.golden index e4949750f2..ab426bcb37 100644 --- a/cli/testdata/coder_create_--help.golden +++ b/cli/testdata/coder_create_--help.golden @@ -42,6 +42,9 @@ OPTIONS: -t, --template string, $CODER_TEMPLATE_NAME Specify a template name. + --template-version string, $CODER_TEMPLATE_VERSION + Specify a template version name. + -y, --yes bool Bypass prompts. diff --git a/docs/reference/cli/create.md b/docs/reference/cli/create.md index d4003e2f9e..c165b33f4e 100644 --- a/docs/reference/cli/create.md +++ b/docs/reference/cli/create.md @@ -29,6 +29,15 @@ coder create [flags] [name] Specify a template name. +### --template-version + +| | | +| ----------- | ------------------------------------ | +| Type | string | +| Environment | $CODER_TEMPLATE_VERSION | + +Specify a template version name. + ### --start-at | | |