Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit065c7c3

Browse files
authored
feat: addsharing show command to the CLI (#19707)
Closescoder/internal#860
1 parent9f66395 commit065c7c3

File tree

3 files changed

+195
-40
lines changed

3 files changed

+195
-40
lines changed

‎cli/sharing.go‎

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"fmt"
56
"regexp"
67

@@ -13,12 +14,6 @@ import (
1314

1415
constdefaultGroupDisplay="-"
1516

16-
typeworkspaceShareRowstruct {
17-
Userstring`table:"user"`
18-
Groupstring`table:"group,default_sort"`
19-
Role codersdk.WorkspaceRole`table:"role"`
20-
}
21-
2217
func (r*RootCmd)sharing()*serpent.Command {
2318
orgContext:=NewOrganizationContext()
2419

@@ -29,26 +24,59 @@ func (r *RootCmd) sharing() *serpent.Command {
2924
Handler:func(inv*serpent.Invocation)error {
3025
returninv.Command.HelpHandler(inv)
3126
},
32-
Children: []*serpent.Command{r.shareWorkspace(orgContext)},
33-
Hidden:true,
27+
Children: []*serpent.Command{
28+
r.shareWorkspace(orgContext),
29+
r.statusWorkspaceSharing(),
30+
},
31+
Hidden:true,
3432
}
3533

3634
orgContext.AttachOptions(cmd)
3735
returncmd
3836
}
3937

38+
func (r*RootCmd)statusWorkspaceSharing()*serpent.Command {
39+
client:=new(codersdk.Client)
40+
41+
cmd:=&serpent.Command{
42+
Use:"status <workspace>",
43+
Short:"List all users and groups the given Workspace is shared with.",
44+
Aliases: []string{"list"},
45+
Middleware:serpent.Chain(
46+
r.InitClient(client),
47+
serpent.RequireNArgs(1),
48+
),
49+
Handler:func(inv*serpent.Invocation)error {
50+
workspace,err:=namedWorkspace(inv.Context(),client,inv.Args[0])
51+
iferr!=nil {
52+
returnxerrors.Errorf("unable to fetch Workspace %s: %w",inv.Args[0],err)
53+
}
54+
55+
acl,err:=client.WorkspaceACL(inv.Context(),workspace.ID)
56+
iferr!=nil {
57+
returnxerrors.Errorf("unable to fetch ACL for Workspace: %w",err)
58+
}
59+
60+
out,err:=workspaceACLToTable(inv.Context(),&acl)
61+
iferr!=nil {
62+
returnerr
63+
}
64+
65+
_,err=fmt.Fprintln(inv.Stdout,out)
66+
returnerr
67+
},
68+
}
69+
70+
returncmd
71+
}
72+
4073
func (r*RootCmd)shareWorkspace(orgContext*OrganizationContext)*serpent.Command {
4174
var (
4275
// Username regex taken from codersdk/name.go
4376
nameRoleRegex=regexp.MustCompile(`(^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*)+(?::([A-Za-z0-9-]+))?`)
4477
client=new(codersdk.Client)
4578
users []string
4679
groups []string
47-
formatter=cliui.NewOutputFormatter(
48-
cliui.TableFormat(
49-
[]workspaceShareRow{}, []string{"User","Group","Role"}),
50-
cliui.JSONFormat(),
51-
)
5280
)
5381

5482
cmd:=&serpent.Command{
@@ -175,37 +203,12 @@ func (r *RootCmd) shareWorkspace(orgContext *OrganizationContext) *serpent.Comma
175203
returnerr
176204
}
177205

178-
workspaceACL,err:=client.WorkspaceACL(inv.Context(),workspace.ID)
206+
acl,err:=client.WorkspaceACL(inv.Context(),workspace.ID)
179207
iferr!=nil {
180208
returnxerrors.Errorf("could not fetch current workspace ACL after sharing %w",err)
181209
}
182210

183-
outputRows:=make([]workspaceShareRow,0)
184-
for_,user:=rangeworkspaceACL.Users {
185-
ifuser.Role==codersdk.WorkspaceRoleDeleted {
186-
continue
187-
}
188-
189-
outputRows=append(outputRows,workspaceShareRow{
190-
User:user.Username,
191-
Group:defaultGroupDisplay,
192-
Role:user.Role,
193-
})
194-
}
195-
for_,group:=rangeworkspaceACL.Groups {
196-
ifgroup.Role==codersdk.WorkspaceRoleDeleted {
197-
continue
198-
}
199-
200-
for_,user:=rangegroup.Members {
201-
outputRows=append(outputRows,workspaceShareRow{
202-
User:user.Username,
203-
Group:group.Name,
204-
Role:group.Role,
205-
})
206-
}
207-
}
208-
out,err:=formatter.Format(inv.Context(),outputRows)
211+
out,err:=workspaceACLToTable(inv.Context(),&acl)
209212
iferr!=nil {
210213
returnerr
211214
}
@@ -229,3 +232,48 @@ func stringToWorkspaceRole(role string) (codersdk.WorkspaceRole, error) {
229232
role,codersdk.WorkspaceRoleAdmin,codersdk.WorkspaceRoleUse)
230233
}
231234
}
235+
236+
funcworkspaceACLToTable(ctx context.Context,acl*codersdk.WorkspaceACL) (string,error) {
237+
typeworkspaceShareRowstruct {
238+
Userstring`table:"user"`
239+
Groupstring`table:"group,default_sort"`
240+
Role codersdk.WorkspaceRole`table:"role"`
241+
}
242+
243+
formatter:=cliui.NewOutputFormatter(
244+
cliui.TableFormat(
245+
[]workspaceShareRow{}, []string{"User","Group","Role"}),
246+
cliui.JSONFormat())
247+
248+
outputRows:=make([]workspaceShareRow,0)
249+
for_,user:=rangeacl.Users {
250+
ifuser.Role==codersdk.WorkspaceRoleDeleted {
251+
continue
252+
}
253+
254+
outputRows=append(outputRows,workspaceShareRow{
255+
User:user.Username,
256+
Group:defaultGroupDisplay,
257+
Role:user.Role,
258+
})
259+
}
260+
for_,group:=rangeacl.Groups {
261+
ifgroup.Role==codersdk.WorkspaceRoleDeleted {
262+
continue
263+
}
264+
265+
for_,user:=rangegroup.Members {
266+
outputRows=append(outputRows,workspaceShareRow{
267+
User:user.Username,
268+
Group:group.Name,
269+
Role:group.Role,
270+
})
271+
}
272+
}
273+
out,err:=formatter.Format(ctx,outputRows)
274+
iferr!=nil {
275+
return"",err
276+
}
277+
278+
returnout,nil
279+
}

‎cli/sharing_test.go‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,52 @@ func TestSharingShare(t *testing.T) {
168168
assert.True(t,found,fmt.Sprintf("expected to find the username %s and role %s in the command: %s",toShareWithUser.Username,codersdk.WorkspaceRoleAdmin,out.String()))
169169
})
170170
}
171+
172+
funcTestSharingStatus(t*testing.T) {
173+
t.Parallel()
174+
175+
dv:=coderdtest.DeploymentValues(t)
176+
dv.Experiments= []string{string(codersdk.ExperimentWorkspaceSharing)}
177+
178+
t.Run("ListSharedUsers",func(t*testing.T) {
179+
t.Parallel()
180+
181+
var (
182+
client,db=coderdtest.NewWithDatabase(t,&coderdtest.Options{
183+
DeploymentValues:dv,
184+
})
185+
orgOwner=coderdtest.CreateFirstUser(t,client)
186+
workspaceOwnerClient,workspaceOwner=coderdtest.CreateAnotherUser(t,client,orgOwner.OrganizationID,rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
187+
workspace=dbfake.WorkspaceBuild(t,db, database.WorkspaceTable{
188+
OwnerID:workspaceOwner.ID,
189+
OrganizationID:orgOwner.OrganizationID,
190+
}).Do().Workspace
191+
_,toShareWithUser=coderdtest.CreateAnotherUser(t,client,orgOwner.OrganizationID)
192+
ctx=testutil.Context(t,testutil.WaitMedium)
193+
)
194+
195+
err:=client.UpdateWorkspaceACL(ctx,workspace.ID, codersdk.UpdateWorkspaceACL{
196+
UserRoles:map[string]codersdk.WorkspaceRole{
197+
toShareWithUser.ID.String():codersdk.WorkspaceRoleUse,
198+
},
199+
})
200+
require.NoError(t,err)
201+
202+
inv,root:=clitest.New(t,"sharing","status",workspace.Name,"--org",orgOwner.OrganizationID.String())
203+
clitest.SetupConfig(t,workspaceOwnerClient,root)
204+
205+
out:=bytes.NewBuffer(nil)
206+
inv.Stdout=out
207+
err=inv.WithContext(ctx).Run()
208+
require.NoError(t,err)
209+
210+
found:=false
211+
for_,line:=rangestrings.Split(out.String(),"\n") {
212+
ifstrings.Contains(line,toShareWithUser.Username)&&strings.Contains(line,string(codersdk.WorkspaceRoleUse)) {
213+
found=true
214+
break
215+
}
216+
}
217+
assert.True(t,found,"expected to find username %s with role %s in the output: %s",toShareWithUser.Username,codersdk.WorkspaceRoleUse,out.String())
218+
})
219+
}

‎enterprise/cli/sharing_test.go‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,64 @@ func TestSharingShareEnterprise(t *testing.T) {
187187
})
188188
}
189189

190+
funcTestSharingStatus(t*testing.T) {
191+
t.Parallel()
192+
193+
dv:=coderdtest.DeploymentValues(t)
194+
dv.Experiments= []string{string(codersdk.ExperimentWorkspaceSharing)}
195+
196+
t.Run("ListSharedUsers",func(t*testing.T) {
197+
t.Parallel()
198+
199+
var (
200+
client,db,orgOwner=coderdenttest.NewWithDatabase(t,&coderdenttest.Options{
201+
Options:&coderdtest.Options{
202+
DeploymentValues:dv,
203+
},
204+
LicenseOptions:&coderdenttest.LicenseOptions{
205+
Features: license.Features{
206+
codersdk.FeatureTemplateRBAC:1,
207+
},
208+
},
209+
})
210+
workspaceOwnerClient,workspaceOwner=coderdtest.CreateAnotherUser(t,client,orgOwner.OrganizationID,rbac.ScopedRoleOrgAuditor(orgOwner.OrganizationID))
211+
workspace=dbfake.WorkspaceBuild(t,db, database.WorkspaceTable{
212+
OwnerID:workspaceOwner.ID,
213+
OrganizationID:orgOwner.OrganizationID,
214+
}).Do().Workspace
215+
_,orgMember=coderdtest.CreateAnotherUser(t,client,orgOwner.OrganizationID)
216+
ctx=testutil.Context(t,testutil.WaitMedium)
217+
)
218+
219+
group,err:=createGroupWithMembers(ctx,client,orgOwner.OrganizationID,"new-group", []uuid.UUID{orgMember.ID})
220+
require.NoError(t,err)
221+
222+
err=client.UpdateWorkspaceACL(ctx,workspace.ID, codersdk.UpdateWorkspaceACL{
223+
GroupRoles:map[string]codersdk.WorkspaceRole{
224+
group.ID.String():codersdk.WorkspaceRoleUse,
225+
},
226+
})
227+
require.NoError(t,err)
228+
229+
inv,root:=clitest.New(t,"sharing","status",workspace.Name,"--org",orgOwner.OrganizationID.String())
230+
clitest.SetupConfig(t,workspaceOwnerClient,root)
231+
232+
out:=bytes.NewBuffer(nil)
233+
inv.Stdout=out
234+
err=inv.WithContext(ctx).Run()
235+
require.NoError(t,err)
236+
237+
found:=false
238+
for_,line:=rangestrings.Split(out.String(),"\n") {
239+
ifstrings.Contains(line,orgMember.Username)&&strings.Contains(line,string(codersdk.WorkspaceRoleUse))&&strings.Contains(line,group.Name) {
240+
found=true
241+
break
242+
}
243+
}
244+
assert.True(t,found,"expected to find username %s with role %s in the output: %s",orgMember.Username,codersdk.WorkspaceRoleUse,out.String())
245+
})
246+
}
247+
190248
funccreateGroupWithMembers(ctx context.Context,client*codersdk.Client,orgID uuid.UUID,namestring,memberIDs []uuid.UUID) (codersdk.Group,error) {
191249
group,err:=client.CreateGroup(ctx,orgID, codersdk.CreateGroupRequest{
192250
Name:name,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp