Skip to content

Commit 5ebc748

Browse files
joobisbmatifali
andauthored
feat: allow promoting an existing template version to active from CLI (#15051)
Co-authored-by: Muhammad Atif Ali <atif@coder.com>
1 parent 46cce33 commit 5ebc748

7 files changed

+225
-0
lines changed

cli/templateversions.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func (r *RootCmd) templateVersions() *serpent.Command {
3232
r.templateVersionsList(),
3333
r.archiveTemplateVersion(),
3434
r.unarchiveTemplateVersion(),
35+
r.templateVersionsPromote(),
3536
},
3637
}
3738

@@ -169,3 +170,66 @@ func templateVersionsToRows(activeVersionID uuid.UUID, templateVersions ...coder
169170

170171
return rows
171172
}
173+
174+
func (r *RootCmd) templateVersionsPromote() *serpent.Command {
175+
var (
176+
templateName string
177+
templateVersionName string
178+
orgContext = NewOrganizationContext()
179+
)
180+
client := new(codersdk.Client)
181+
cmd := &serpent.Command{
182+
Use: "promote --template=<template_name> --template-version=<template_version_name>",
183+
Short: "Promote a template version to active.",
184+
Long: "Promote an existing template version to be the active version for the specified template.",
185+
Middleware: serpent.Chain(
186+
r.InitClient(client),
187+
),
188+
Handler: func(inv *serpent.Invocation) error {
189+
organization, err := orgContext.Selected(inv, client)
190+
if err != nil {
191+
return err
192+
}
193+
194+
template, err := client.TemplateByName(inv.Context(), organization.ID, templateName)
195+
if err != nil {
196+
return xerrors.Errorf("get template by name: %w", err)
197+
}
198+
199+
version, err := client.TemplateVersionByName(inv.Context(), template.ID, templateVersionName)
200+
if err != nil {
201+
return xerrors.Errorf("get template version by name: %w", err)
202+
}
203+
204+
err = client.UpdateActiveTemplateVersion(inv.Context(), template.ID, codersdk.UpdateActiveTemplateVersion{
205+
ID: version.ID,
206+
})
207+
if err != nil {
208+
return xerrors.Errorf("update active template version: %w", err)
209+
}
210+
211+
_, _ = fmt.Fprintf(inv.Stdout, "Successfully promoted version %q to active for template %q\n", templateVersionName, templateName)
212+
return nil
213+
},
214+
}
215+
216+
cmd.Options = serpent.OptionSet{
217+
{
218+
Flag: "template",
219+
FlagShorthand: "t",
220+
Env: "CODER_TEMPLATE_NAME",
221+
Description: "Specify the template name.",
222+
Required: true,
223+
Value: serpent.StringOf(&templateName),
224+
},
225+
{
226+
Flag: "template-version",
227+
Description: "Specify the template version name to promote.",
228+
Env: "CODER_TEMPLATE_VERSION_NAME",
229+
Required: true,
230+
Value: serpent.StringOf(&templateVersionName),
231+
},
232+
}
233+
orgContext.AttachOptions(cmd)
234+
return cmd
235+
}

cli/templateversions_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package cli_test
22

33
import (
4+
"context"
45
"testing"
56

7+
"github.com/stretchr/testify/assert"
68
"github.com/stretchr/testify/require"
79

810
"github.com/coder/coder/v2/cli/clitest"
911
"github.com/coder/coder/v2/coderd/coderdtest"
12+
"github.com/coder/coder/v2/codersdk"
1013
"github.com/coder/coder/v2/pty/ptytest"
1114
)
1215

@@ -38,3 +41,85 @@ func TestTemplateVersions(t *testing.T) {
3841
pty.ExpectMatch("Active")
3942
})
4043
}
44+
45+
func TestTemplateVersionsPromote(t *testing.T) {
46+
t.Parallel()
47+
48+
t.Run("PromoteVersion", func(t *testing.T) {
49+
t.Parallel()
50+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
51+
owner := coderdtest.CreateFirstUser(t, client)
52+
53+
// Create a template with two versions
54+
version1 := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent())
55+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version1.ID)
56+
57+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version1.ID)
58+
59+
version2 := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent(), func(ctvr *codersdk.CreateTemplateVersionRequest) {
60+
ctvr.TemplateID = template.ID
61+
ctvr.Name = "2.0.0"
62+
})
63+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version2.ID)
64+
65+
// Ensure version1 is active
66+
updatedTemplate, err := client.Template(context.Background(), template.ID)
67+
assert.NoError(t, err)
68+
assert.Equal(t, version1.ID, updatedTemplate.ActiveVersionID)
69+
70+
args := []string{
71+
"templates",
72+
"versions",
73+
"promote",
74+
"--template", template.Name,
75+
"--template-version", version2.Name,
76+
}
77+
78+
inv, root := clitest.New(t, args...)
79+
//nolint:gocritic // Creating a workspace for another user requires owner permissions.
80+
clitest.SetupConfig(t, client, root)
81+
errC := make(chan error)
82+
go func() {
83+
errC <- inv.Run()
84+
}()
85+
86+
require.NoError(t, <-errC)
87+
88+
// Verify that version2 is now the active version
89+
updatedTemplate, err = client.Template(context.Background(), template.ID)
90+
require.NoError(t, err)
91+
assert.Equal(t, version2.ID, updatedTemplate.ActiveVersionID)
92+
})
93+
94+
t.Run("PromoteNonExistentVersion", func(t *testing.T) {
95+
t.Parallel()
96+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
97+
owner := coderdtest.CreateFirstUser(t, client)
98+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
99+
100+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
101+
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
102+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
103+
104+
inv, root := clitest.New(t, "templates", "versions", "promote", "--template", template.Name, "--template-version", "non-existent-version")
105+
clitest.SetupConfig(t, member, root)
106+
107+
err := inv.Run()
108+
require.Error(t, err)
109+
require.Contains(t, err.Error(), "get template version by name")
110+
})
111+
112+
t.Run("PromoteVersionInvalidTemplate", func(t *testing.T) {
113+
t.Parallel()
114+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
115+
owner := coderdtest.CreateFirstUser(t, client)
116+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
117+
118+
inv, root := clitest.New(t, "templates", "versions", "promote", "--template", "non-existent-template", "--template-version", "some-version")
119+
clitest.SetupConfig(t, member, root)
120+
121+
err := inv.Run()
122+
require.Error(t, err)
123+
require.Contains(t, err.Error(), "get template by name")
124+
})
125+
}

cli/testdata/coder_templates_versions_--help.golden

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ USAGE:
1414
SUBCOMMANDS:
1515
archive Archive a template version(s).
1616
list List all the versions of the specified template
17+
promote Promote a template version to active.
1718
unarchive Unarchive a template version(s).
1819

1920
———
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
coder v0.0.0-devel
2+
3+
USAGE:
4+
coder templates versions promote [flags] --template=<template_name>
5+
--template-version=<template_version_name>
6+
7+
Promote a template version to active.
8+
9+
Promote an existing template version to be the active version for the
10+
specified template.
11+
12+
OPTIONS:
13+
-O, --org string, $CODER_ORGANIZATION
14+
Select which organization (uuid or name) to use.
15+
16+
-t, --template string, $CODER_TEMPLATE_NAME
17+
Specify the template name.
18+
19+
--template-version string, $CODER_TEMPLATE_VERSION_NAME
20+
Specify the template version name to promote.
21+
22+
———
23+
Run `coder --help` for a list of global options.

docs/manifest.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,11 @@
13141314
"description": "List all the versions of the specified template",
13151315
"path": "reference/cli/templates_versions_list.md"
13161316
},
1317+
{
1318+
"title": "templates versions promote",
1319+
"description": "Promote a template version to active.",
1320+
"path": "reference/cli/templates_versions_promote.md"
1321+
},
13171322
{
13181323
"title": "templates versions unarchive",
13191324
"description": "Unarchive a template version(s).",

docs/reference/cli/templates_versions.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/cli/templates_versions_promote.md

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy