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

Commit6de1a82

Browse files
committed
feat: addsharing show command to the CLI
1 parent909acbc commit6de1a82

File tree

3 files changed

+201
-34
lines changed

3 files changed

+201
-34
lines changed

‎cli/sharing.go‎

Lines changed: 88 additions & 34 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

@@ -29,26 +30,59 @@ func (r *RootCmd) sharing() *serpent.Command {
2930
Handler:func(inv*serpent.Invocation)error {
3031
returninv.Command.HelpHandler(inv)
3132
},
32-
Children: []*serpent.Command{r.shareWorkspace(orgContext)},
33-
Hidden:true,
33+
Children: []*serpent.Command{
34+
r.shareWorkspace(orgContext),
35+
r.statusWorkspaceSharing(),
36+
},
37+
Hidden:true,
3438
}
3539

3640
orgContext.AttachOptions(cmd)
3741
returncmd
3842
}
3943

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

5488
cmd:=&serpent.Command{
@@ -175,37 +209,12 @@ func (r *RootCmd) shareWorkspace(orgContext *OrganizationContext) *serpent.Comma
175209
returnerr
176210
}
177211

178-
workspaceACL,err:=client.WorkspaceACL(inv.Context(),workspace.ID)
212+
acl,err:=client.WorkspaceACL(inv.Context(),workspace.ID)
179213
iferr!=nil {
180214
returnxerrors.Errorf("could not fetch current workspace ACL after sharing %w",err)
181215
}
182216

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)
217+
out,err:=workspaceACLToTable(inv.Context(),&acl)
209218
iferr!=nil {
210219
returnerr
211220
}
@@ -229,3 +238,48 @@ func stringToWorkspaceRole(role string) (codersdk.WorkspaceRole, error) {
229238
role,codersdk.WorkspaceRoleAdmin,codersdk.WorkspaceRoleUse)
230239
}
231240
}
241+
242+
funcworkspaceACLToTable(ctx context.Context,acl*codersdk.WorkspaceACL) (string,error) {
243+
typeworkspaceShareRowstruct {
244+
Userstring`table:"user"`
245+
Groupstring`table:"group,default_sort"`
246+
Role codersdk.WorkspaceRole`table:"role"`
247+
}
248+
249+
formatter:=cliui.NewOutputFormatter(
250+
cliui.TableFormat(
251+
[]workspaceShareRow{}, []string{"User","Group","Role"}),
252+
cliui.JSONFormat())
253+
254+
outputRows:=make([]workspaceShareRow,0)
255+
for_,user:=rangeacl.Users {
256+
ifuser.Role==codersdk.WorkspaceRoleDeleted {
257+
continue
258+
}
259+
260+
outputRows=append(outputRows,workspaceShareRow{
261+
User:user.Username,
262+
Group:defaultGroupDisplay,
263+
Role:user.Role,
264+
})
265+
}
266+
for_,group:=rangeacl.Groups {
267+
ifgroup.Role==codersdk.WorkspaceRoleDeleted {
268+
continue
269+
}
270+
271+
for_,user:=rangegroup.Members {
272+
outputRows=append(outputRows,workspaceShareRow{
273+
User:user.Username,
274+
Group:group.Name,
275+
Role:group.Role,
276+
})
277+
}
278+
}
279+
out,err:=formatter.Format(ctx,outputRows)
280+
iferr!=nil {
281+
return"",err
282+
}
283+
284+
returnout,nil
285+
}

‎cli/sharing_test.go‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,55 @@ 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+
}
215+
216+
iffound {
217+
break
218+
}
219+
}
220+
assert.True(t,found,"expected to find username %s with role %s in the output: %s",toShareWithUser.Username,codersdk.WorkspaceRoleUse,out.String())
221+
})
222+
}

‎enterprise/cli/sharing_test.go‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,67 @@ 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+
}
242+
243+
iffound {
244+
break
245+
}
246+
}
247+
assert.True(t,found,"expected to find username %s with role %s in the output: %s",orgMember.Username,codersdk.WorkspaceRoleUse,out.String())
248+
})
249+
}
250+
190251
funccreateGroupWithMembers(ctx context.Context,client*codersdk.Client,orgID uuid.UUID,namestring,memberIDs []uuid.UUID) (codersdk.Group,error) {
191252
group,err:=client.CreateGroup(ctx,orgID, codersdk.CreateGroupRequest{
192253
Name:name,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp