Skip to content

Commit 29508a9

Browse files
committed
Merge remote-tracking branch 'origin/main' into stevenmasley/bitbucket_server_defaults
2 parents f7a5742 + 23f0265 commit 29508a9

File tree

74 files changed

+1745
-1669
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1745
-1669
lines changed

cli/autoupdate.go

+58
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

+79
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: `invalid option "sometimes" must be either of`,
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, nil)
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/configssh_test.go

+35-59
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ import (
2222
"github.com/coder/coder/v2/agent/agenttest"
2323
"github.com/coder/coder/v2/cli/clitest"
2424
"github.com/coder/coder/v2/coderd/coderdtest"
25+
"github.com/coder/coder/v2/coderd/database"
26+
"github.com/coder/coder/v2/coderd/database/dbfake"
2527
"github.com/coder/coder/v2/codersdk"
26-
"github.com/coder/coder/v2/provisioner/echo"
2728
"github.com/coder/coder/v2/provisionersdk/proto"
2829
"github.com/coder/coder/v2/pty/ptytest"
2930
"github.com/coder/coder/v2/testutil"
@@ -64,8 +65,7 @@ func TestConfigSSH(t *testing.T) {
6465
const hostname = "test-coder."
6566
const expectedKey = "ConnectionAttempts"
6667
const removeKey = "ConnectionTimeout"
67-
client := coderdtest.New(t, &coderdtest.Options{
68-
IncludeProvisionerDaemon: true,
68+
client, db := coderdtest.NewWithDatabase(t, &coderdtest.Options{
6969
ConfigSSH: codersdk.SSHConfigResponse{
7070
HostnamePrefix: hostname,
7171
SSHConfigOptions: map[string]string{
@@ -76,32 +76,13 @@ func TestConfigSSH(t *testing.T) {
7676
},
7777
})
7878
owner := coderdtest.CreateFirstUser(t, client)
79-
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
80-
authToken := uuid.NewString()
81-
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{
82-
Parse: echo.ParseComplete,
83-
ProvisionPlan: []*proto.Response{{
84-
Type: &proto.Response_Plan{
85-
Plan: &proto.PlanComplete{
86-
Resources: []*proto.Resource{{
87-
Name: "example",
88-
Type: "aws_instance",
89-
Agents: []*proto.Agent{{
90-
Id: uuid.NewString(),
91-
Name: "example",
92-
}},
93-
}},
94-
},
95-
},
96-
}},
97-
ProvisionApply: echo.ProvisionApplyWithAgent(authToken),
79+
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
80+
ws, authToken := dbfake.WorkspaceWithAgent(t, db, database.Workspace{
81+
OrganizationID: owner.OrganizationID,
82+
OwnerID: memberUser.ID,
9883
})
99-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
100-
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
101-
workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID)
102-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
10384
_ = agenttest.New(t, client.URL, authToken)
104-
resources := coderdtest.AwaitWorkspaceAgents(t, client, workspace.ID)
85+
resources := coderdtest.AwaitWorkspaceAgents(t, client, ws.ID)
10586
agentConn, err := client.DialWorkspaceAgent(context.Background(), resources[0].Agents[0].ID, nil)
10687
require.NoError(t, err)
10788
defer agentConn.Close()
@@ -172,7 +153,7 @@ func TestConfigSSH(t *testing.T) {
172153

173154
home := filepath.Dir(filepath.Dir(sshConfigFile))
174155
// #nosec
175-
sshCmd := exec.Command("ssh", "-F", sshConfigFile, hostname+workspace.Name, "echo", "test")
156+
sshCmd := exec.Command("ssh", "-F", sshConfigFile, hostname+ws.Name, "echo", "test")
176157
pty = ptytest.New(t)
177158
// Set HOME because coder config is included from ~/.ssh/coder.
178159
sshCmd.Env = append(sshCmd.Env, fmt.Sprintf("HOME=%s", home))
@@ -213,13 +194,13 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
213194
match, write string
214195
}
215196
tests := []struct {
216-
name string
217-
args []string
218-
matches []match
219-
writeConfig writeConfig
220-
wantConfig wantConfig
221-
wantErr bool
222-
echoResponse *echo.Responses
197+
name string
198+
args []string
199+
matches []match
200+
writeConfig writeConfig
201+
wantConfig wantConfig
202+
wantErr bool
203+
hasAgent bool
223204
}{
224205
{
225206
name: "Config file is created",
@@ -576,11 +557,8 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
576557
args: []string{
577558
"-y", "--coder-binary-path", "/foo/bar/coder",
578559
},
579-
wantErr: false,
580-
echoResponse: &echo.Responses{
581-
Parse: echo.ParseComplete,
582-
ProvisionApply: echo.ProvisionApplyWithAgent(""),
583-
},
560+
wantErr: false,
561+
hasAgent: true,
584562
wantConfig: wantConfig{
585563
regexMatch: "ProxyCommand /foo/bar/coder",
586564
},
@@ -591,15 +569,14 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
591569
t.Run(tt.name, func(t *testing.T) {
592570
t.Parallel()
593571

594-
var (
595-
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
596-
user = coderdtest.CreateFirstUser(t, client)
597-
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, tt.echoResponse)
598-
_ = coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
599-
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
600-
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
601-
_ = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
602-
)
572+
client, db := coderdtest.NewWithDatabase(t, nil)
573+
user := coderdtest.CreateFirstUser(t, client)
574+
if tt.hasAgent {
575+
_, _ = dbfake.WorkspaceWithAgent(t, db, database.Workspace{
576+
OrganizationID: user.OrganizationID,
577+
OwnerID: user.UserID,
578+
})
579+
}
603580

604581
// Prepare ssh config files.
605582
sshConfigName := sshConfigFileName(t)
@@ -613,6 +590,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
613590
}
614591
args = append(args, tt.args...)
615592
inv, root := clitest.New(t, args...)
593+
//nolint:gocritic // This has always ran with the admin user.
616594
clitest.SetupConfig(t, client, root)
617595

618596
pty := ptytest.New(t)
@@ -710,17 +688,15 @@ func TestConfigSSH_Hostnames(t *testing.T) {
710688
resources = append(resources, resource)
711689
}
712690

713-
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
691+
client, db := coderdtest.NewWithDatabase(t, nil)
714692
owner := coderdtest.CreateFirstUser(t, client)
715-
member, _ := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
716-
// authToken := uuid.NewString()
717-
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID,
718-
echo.WithResources(resources))
719-
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
720-
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
721-
workspace := coderdtest.CreateWorkspace(t, member, owner.OrganizationID, template.ID)
722-
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
693+
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
723694

695+
ws := dbfake.Workspace(t, db, database.Workspace{
696+
OrganizationID: owner.OrganizationID,
697+
OwnerID: memberUser.ID,
698+
})
699+
dbfake.WorkspaceBuild(t, db, ws, database.WorkspaceBuild{}, resources...)
724700
sshConfigFile := sshConfigFileName(t)
725701

726702
inv, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile)
@@ -745,7 +721,7 @@ func TestConfigSSH_Hostnames(t *testing.T) {
745721

746722
var expectedHosts []string
747723
for _, hostnamePattern := range tt.expected {
748-
hostname := strings.ReplaceAll(hostnamePattern, "@", workspace.Name)
724+
hostname := strings.ReplaceAll(hostnamePattern, "@", ws.Name)
749725
expectedHosts = append(expectedHosts, hostname)
750726
}
751727

cli/create.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ func (r *RootCmd) create() *clibase.Cmd {
140140
}
141141

142142
richParameters, err := prepWorkspaceBuild(inv, client, prepWorkspaceBuildArgs{
143-
Action: WorkspaceCreate,
144-
Template: template,
145-
NewWorkspaceName: workspaceName,
143+
Action: WorkspaceCreate,
144+
TemplateVersionID: template.ActiveVersionID,
145+
NewWorkspaceName: workspaceName,
146146

147147
RichParameterFile: parameterFlags.richParameterFile,
148148
RichParameters: cliRichParameters,
@@ -224,10 +224,9 @@ func (r *RootCmd) create() *clibase.Cmd {
224224
}
225225

226226
type prepWorkspaceBuildArgs struct {
227-
Action WorkspaceCLIAction
228-
Template codersdk.Template
229-
NewWorkspaceName string
230-
WorkspaceID uuid.UUID
227+
Action WorkspaceCLIAction
228+
TemplateVersionID uuid.UUID
229+
NewWorkspaceName string
231230

232231
LastBuildParameters []codersdk.WorkspaceBuildParameter
233232

@@ -244,7 +243,7 @@ type prepWorkspaceBuildArgs struct {
244243
func prepWorkspaceBuild(inv *clibase.Invocation, client *codersdk.Client, args prepWorkspaceBuildArgs) ([]codersdk.WorkspaceBuildParameter, error) {
245244
ctx := inv.Context()
246245

247-
templateVersion, err := client.TemplateVersion(ctx, args.Template.ActiveVersionID)
246+
templateVersion, err := client.TemplateVersion(ctx, args.TemplateVersionID)
248247
if err != nil {
249248
return nil, xerrors.Errorf("get template version: %w", err)
250249
}

cli/exp_scaletest.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -600,9 +600,9 @@ func (r *RootCmd) scaletestCreateWorkspaces() *clibase.Cmd {
600600
}
601601

602602
richParameters, err := prepWorkspaceBuild(inv, client, prepWorkspaceBuildArgs{
603-
Action: WorkspaceCreate,
604-
Template: tpl,
605-
NewWorkspaceName: "scaletest-N", // TODO: the scaletest runner will pass in a different name here. Does this matter?
603+
Action: WorkspaceCreate,
604+
TemplateVersionID: tpl.ActiveVersionID,
605+
NewWorkspaceName: "scaletest-N", // TODO: the scaletest runner will pass in a different name here. Does this matter?
606606

607607
RichParameterFile: parameterFlags.richParameterFile,
608608
RichParameters: cliRichParameters,

0 commit comments

Comments
 (0)