Skip to content

Commit fccb695

Browse files
dwahlerkylecarbs
authored andcommitted
feat: support fully-qualified workspace names in CLI (#2036)
1 parent 1e88668 commit fccb695

File tree

12 files changed

+91
-16
lines changed

12 files changed

+91
-16
lines changed

cli/autostart.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func autostartShow() *cobra.Command {
4646
return err
4747
}
4848

49-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
49+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
5050
if err != nil {
5151
return err
5252
}
@@ -104,7 +104,7 @@ func autostartEnable() *cobra.Command {
104104
return err
105105
}
106106

107-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
107+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
108108
if err != nil {
109109
return err
110110
}
@@ -147,7 +147,7 @@ func autostartDisable() *cobra.Command {
147147
return err
148148
}
149149

150-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
150+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
151151
if err != nil {
152152
return err
153153
}

cli/bump.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func bump() *cobra.Command {
4848
return xerrors.Errorf("get current org: %w", err)
4949
}
5050

51-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
51+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
5252
if err != nil {
5353
return xerrors.Errorf("get workspace: %w", err)
5454
}

cli/delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func delete() *cobra.Command {
3434
if err != nil {
3535
return err
3636
}
37-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
37+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
3838
if err != nil {
3939
return err
4040
}

cli/delete_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package cli_test
22

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

78
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
810

911
"github.com/coder/coder/cli/clitest"
1012
"github.com/coder/coder/coderd/coderdtest"
13+
"github.com/coder/coder/codersdk"
1114
"github.com/coder/coder/pty/ptytest"
1215
)
1316

@@ -38,4 +41,55 @@ func TestDelete(t *testing.T) {
3841
pty.ExpectMatch("Cleaning Up")
3942
<-doneChan
4043
})
44+
45+
t.Run("DifferentUser", func(t *testing.T) {
46+
t.Parallel()
47+
adminClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true})
48+
adminUser := coderdtest.CreateFirstUser(t, adminClient)
49+
orgID := adminUser.OrganizationID
50+
client := coderdtest.CreateAnotherUser(t, adminClient, orgID)
51+
user, err := client.User(context.Background(), codersdk.Me)
52+
require.NoError(t, err)
53+
54+
version := coderdtest.CreateTemplateVersion(t, adminClient, orgID, nil)
55+
coderdtest.AwaitTemplateVersionJob(t, adminClient, version.ID)
56+
template := coderdtest.CreateTemplate(t, adminClient, orgID, version.ID)
57+
workspace := coderdtest.CreateWorkspace(t, client, orgID, template.ID)
58+
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
59+
60+
cmd, root := clitest.New(t, "delete", user.Username+"/"+workspace.Name, "-y")
61+
clitest.SetupConfig(t, adminClient, root)
62+
doneChan := make(chan struct{})
63+
pty := ptytest.New(t)
64+
cmd.SetIn(pty.Input())
65+
cmd.SetOut(pty.Output())
66+
go func() {
67+
defer close(doneChan)
68+
err := cmd.Execute()
69+
// When running with the race detector on, we sometimes get an EOF.
70+
if err != nil {
71+
assert.ErrorIs(t, err, io.EOF)
72+
}
73+
}()
74+
75+
pty.ExpectMatch("Cleaning Up")
76+
<-doneChan
77+
78+
workspace, err = client.Workspace(context.Background(), workspace.ID)
79+
require.ErrorContains(t, err, "was deleted")
80+
})
81+
82+
t.Run("InvalidWorkspaceIdentifier", func(t *testing.T) {
83+
t.Parallel()
84+
client := coderdtest.New(t, nil)
85+
cmd, root := clitest.New(t, "delete", "a/b/c", "-y")
86+
clitest.SetupConfig(t, client, root)
87+
doneChan := make(chan struct{})
88+
go func() {
89+
defer close(doneChan)
90+
err := cmd.Execute()
91+
assert.ErrorContains(t, err, "invalid workspace name: \"a/b/c\"")
92+
}()
93+
<-doneChan
94+
})
4195
}

cli/root.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"golang.org/x/xerrors"
1111

12+
"github.com/google/uuid"
1213
"github.com/kirsle/configdir"
1314
"github.com/mattn/go-isatty"
1415
"github.com/spf13/cobra"
@@ -176,6 +177,27 @@ func currentOrganization(cmd *cobra.Command, client *codersdk.Client) (codersdk.
176177
return orgs[0], nil
177178
}
178179

180+
// namedWorkspace fetches and returns a workspace by an identifier, which may be either
181+
// a bare name (for a workspace owned by the current user) or a "user/workspace" combination,
182+
// where user is either a username or UUID.
183+
func namedWorkspace(cmd *cobra.Command, client *codersdk.Client, orgID uuid.UUID, identifier string) (codersdk.Workspace, error) {
184+
parts := strings.Split(identifier, "/")
185+
186+
var owner, name string
187+
switch len(parts) {
188+
case 1:
189+
owner = codersdk.Me
190+
name = parts[0]
191+
case 2:
192+
owner = parts[0]
193+
name = parts[1]
194+
default:
195+
return codersdk.Workspace{}, xerrors.Errorf("invalid workspace name: %q", identifier)
196+
}
197+
198+
return client.WorkspaceByOwnerAndName(cmd.Context(), orgID, owner, name)
199+
}
200+
179201
// createConfig consumes the global configuration flag to produce a config root.
180202
func createConfig(cmd *cobra.Command) config.Root {
181203
globalRoot, err := cmd.Flags().GetString(varGlobalConfig)

cli/show.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"golang.org/x/xerrors"
66

77
"github.com/coder/coder/cli/cliui"
8-
"github.com/coder/coder/codersdk"
98
)
109

1110
func show() *cobra.Command {
@@ -23,7 +22,7 @@ func show() *cobra.Command {
2322
if err != nil {
2423
return err
2524
}
26-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
25+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
2726
if err != nil {
2827
return xerrors.Errorf("get workspace: %w", err)
2928
}

cli/ssh.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func getWorkspaceAndAgent(cmd *cobra.Command, client *codersdk.Client, orgID uui
207207
return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err
208208
}
209209
} else {
210-
workspace, err = client.WorkspaceByOwnerAndName(cmd.Context(), orgID, userID, workspaceParts[0])
210+
workspace, err = namedWorkspace(cmd, client, orgID, workspaceParts[0])
211211
if err != nil {
212212
return codersdk.Workspace{}, codersdk.WorkspaceAgent{}, err
213213
}

cli/start.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func start() *cobra.Command {
3232
if err != nil {
3333
return err
3434
}
35-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
35+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
3636
if err != nil {
3737
return err
3838
}

cli/state.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func statePull() *cobra.Command {
3535
return err
3636
}
3737

38-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
38+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
3939
if err != nil {
4040
return err
4141
}
@@ -81,7 +81,7 @@ func statePush() *cobra.Command {
8181
return err
8282
}
8383

84-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
84+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
8585
if err != nil {
8686
return err
8787
}

cli/stop.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func stop() *cobra.Command {
3232
if err != nil {
3333
return err
3434
}
35-
workspace, err := client.WorkspaceByOwnerAndName(cmd.Context(), organization.ID, codersdk.Me, args[0])
35+
workspace, err := namedWorkspace(cmd, client, organization.ID, args[0])
3636
if err != nil {
3737
return err
3838
}

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