Skip to content

Commit e5c3ec5

Browse files
committed
feat: add cli support for workspace automatic updates
1 parent 0c993ea commit e5c3ec5

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

cli/autoupdate.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"golang.org/x/xerrors"
8+
9+
"github.com/coder/coder/v2/cli/clibase"
10+
"github.com/coder/coder/v2/cli/cliui"
11+
"github.com/coder/coder/v2/codersdk"
12+
)
13+
14+
func (r *RootCmd) autoupdate() *clibase.Cmd {
15+
client := new(codersdk.Client)
16+
cmd := &clibase.Cmd{
17+
Annotations: workspaceCommand,
18+
Use: "autoupdate <workspace> <always|never>",
19+
Short: "Toggle auto-update policy for a workspace",
20+
Middleware: clibase.Chain(
21+
clibase.RequireNArgs(2),
22+
r.InitClient(client),
23+
),
24+
Handler: func(inv *clibase.Invocation) error {
25+
policy := strings.ToLower(inv.Args[1])
26+
err := validateAutoUpdatePolicy(policy)
27+
if err != nil {
28+
return xerrors.Errorf("validate policy: %w", err)
29+
}
30+
31+
workspace, err := namedWorkspace(inv.Context(), client, inv.Args[0])
32+
if err != nil {
33+
return xerrors.Errorf("get workspace: %w", err)
34+
}
35+
36+
err = client.UpdateWorkspaceAutomaticUpdates(inv.Context(), workspace.ID, codersdk.UpdateWorkspaceAutomaticUpdatesRequest{
37+
AutomaticUpdates: codersdk.AutomaticUpdates(policy),
38+
})
39+
if err != nil {
40+
return xerrors.Errorf("update workspace automatic updates policy: %w", err)
41+
}
42+
_, _ = fmt.Fprintf(inv.Stdout, "Updated workspace %q auto-update policy to %q\n", workspace.Name, policy)
43+
return nil
44+
},
45+
}
46+
47+
cmd.Options = append(cmd.Options, cliui.SkipPromptOption())
48+
return cmd
49+
}
50+
51+
func validateAutoUpdatePolicy(arg string) error {
52+
switch codersdk.AutomaticUpdates(arg) {
53+
case codersdk.AutomaticUpdatesAlways, codersdk.AutomaticUpdatesNever:
54+
return nil
55+
default:
56+
return xerrors.Errorf("invalid option %q must be either of %q or %q", arg, codersdk.AutomaticUpdatesAlways, codersdk.AutomaticUpdatesNever)
57+
}
58+
}

cli/autoupdate_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cli_test
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/cli/clitest"
11+
"github.com/coder/coder/v2/coderd/coderdtest"
12+
"github.com/coder/coder/v2/codersdk"
13+
)
14+
15+
func TestAutoUpdate(t *testing.T) {
16+
t.Parallel()
17+
18+
t.Run("OK", func(t *testing.T) {
19+
t.Parallel()
20+
21+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
22+
owner := coderdtest.CreateFirstUser(t, client)
23+
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
24+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, nil)
25+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
26+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
27+
workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID)
28+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
29+
require.Equal(t, codersdk.AutomaticUpdatesNever, workspace.AutomaticUpdates)
30+
31+
expectedPolicy := codersdk.AutomaticUpdatesAlways
32+
inv, root := clitest.New(t, "autoupdate", workspace.Name, string(expectedPolicy))
33+
clitest.SetupConfig(t, member, root)
34+
var buf bytes.Buffer
35+
inv.Stdout = &buf
36+
err := inv.Run()
37+
require.NoError(t, err)
38+
require.Contains(t, buf.String(), fmt.Sprintf("Updated workspace %q auto-update policy to %q", workspace.Name, expectedPolicy))
39+
40+
workspace = coderdtest.MustWorkspace(t, client, workspace.ID)
41+
require.Equal(t, expectedPolicy, workspace.AutomaticUpdates)
42+
})
43+
44+
t.Run("InvalidArgs", func(t *testing.T) {
45+
type testcase struct {
46+
Name string
47+
Args []string
48+
ErrorContains string
49+
}
50+
51+
cases := []testcase{
52+
{
53+
Name: "NoPolicy",
54+
Args: []string{"autoupdate", "ws"},
55+
ErrorContains: "wanted 2 args but got 1",
56+
},
57+
{
58+
Name: "InvalidPolicy",
59+
Args: []string{"autoupdate", "ws", "sometimes"},
60+
ErrorContains: fmt.Sprintf("invalid option %q must be either of", "sometimes"),
61+
},
62+
}
63+
64+
for _, c := range cases {
65+
c := c
66+
t.Run(c.Name, func(t *testing.T) {
67+
t.Parallel()
68+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
69+
_ = coderdtest.CreateFirstUser(t, client)
70+
71+
inv, root := clitest.New(t, c.Args...)
72+
clitest.SetupConfig(t, client, root)
73+
err := inv.Run()
74+
require.Error(t, err)
75+
require.Contains(t, err.Error(), c.ErrorContains)
76+
})
77+
}
78+
})
79+
}

cli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ func (r *RootCmd) Core() []*clibase.Cmd {
9797
r.version(defaultVersionInfo),
9898

9999
// Workspace Commands
100+
r.autoupdate(),
100101
r.configSSH(),
101102
r.create(),
102103
r.deleteWorkspace(),

0 commit comments

Comments
 (0)