@@ -19,9 +19,10 @@ import (
19
19
func (r * RootCmd ) editRole () * serpent.Command {
20
20
formatter := cliui .NewOutputFormatter (
21
21
cliui .ChangeFormatterData (
22
- cliui .TableFormat ([]codersdk. Role {}, []string {"name" , "display_name" , "site_permissions" , "org_permissions" , "user_permissions" }),
22
+ cliui .TableFormat ([]roleTableView {}, []string {"name" , "display_name" , "site_permissions" , "org_permissions" , "user_permissions" }),
23
23
func (data any ) (any , error ) {
24
- return []codersdk.Role {data .(codersdk.Role )}, nil
24
+ typed , _ := data .(codersdk.Role )
25
+ return []roleTableView {roleToTableView (typed )}, nil
25
26
},
26
27
),
27
28
cliui .JSONFormat (),
@@ -51,108 +52,126 @@ func (r *RootCmd) editRole() *serpent.Command {
51
52
},
52
53
},
53
54
Middleware : serpent .Chain (
54
- serpent .RequireNArgs ( 1 ),
55
+ serpent .RequireRangeArgs ( 0 , 1 ),
55
56
r .InitClient (client ),
56
57
),
57
58
Handler : func (inv * serpent.Invocation ) error {
58
59
ctx := inv .Context ()
59
- roles , err := client .ListSiteRoles (ctx )
60
- if err != nil {
61
- return xerrors .Errorf ("listing roles: %w" , err )
62
- }
63
-
64
- // Make sure the role actually exists first
65
- var originalRole codersdk.AssignableRoles
66
- for _ , r := range roles {
67
- if strings .EqualFold (inv .Args [0 ], r .Name ) {
68
- originalRole = r
69
- break
70
- }
71
- }
72
-
73
- if originalRole .Name == "" {
74
- _ , err = cliui .Prompt (inv , cliui.PromptOptions {
75
- Text : "No role exists with that name, do you want to create one?" ,
76
- Default : "yes" ,
77
- IsConfirm : true ,
78
- })
79
- if err != nil {
80
- return xerrors .Errorf ("abort: %w" , err )
81
- }
82
60
83
- originalRole .Role = codersdk.Role {
84
- Name : inv .Args [0 ],
85
- }
86
- }
87
-
88
- var customRole * codersdk.Role
89
- // Either interactive, or take input mode.
61
+ var customRole codersdk.Role
90
62
fi , _ := os .Stdin .Stat ()
91
63
if (fi .Mode () & os .ModeCharDevice ) == 0 {
64
+ // JSON Upload mode
92
65
bytes , err := io .ReadAll (os .Stdin )
93
66
if err != nil {
94
67
return xerrors .Errorf ("reading stdin: %w" , err )
95
68
}
96
69
97
- err = json .Unmarshal (bytes , customRole )
70
+ err = json .Unmarshal (bytes , & customRole )
98
71
if err != nil {
99
72
return xerrors .Errorf ("parsing stdin json: %w" , err )
100
73
}
101
- } else {
102
- // Interactive mode
103
- if len (originalRole .OrganizationPermissions ) > 0 {
104
- return xerrors .Errorf ("unable to edit role in interactive mode, it contains organization permissions" )
105
- }
106
74
107
- if len (originalRole .UserPermissions ) > 0 {
108
- return xerrors .Errorf ("unable to edit role in interactive mode, it contains user permissions" )
75
+ if customRole .Name == "" {
76
+ arr := make ([]json.RawMessage , 0 )
77
+ err = json .Unmarshal (bytes , & arr )
78
+ if err == nil && len (arr ) > 0 {
79
+ return xerrors .Errorf ("the input appears to be an array, only 1 role can be sent at a time" )
80
+ }
81
+ return xerrors .Errorf ("json input does not appear to be a valid role" )
109
82
}
110
-
111
- customRole , err = interactiveEdit (inv , & originalRole . Role )
83
+ } else {
84
+ interactiveRole , err : = interactiveEdit (inv , client )
112
85
if err != nil {
113
86
return xerrors .Errorf ("editing role: %w" , err )
114
87
}
115
- }
116
88
117
- totalOrg := 0
118
- for _ , o := range customRole .OrganizationPermissions {
119
- totalOrg += len (o )
120
- }
121
- preview := fmt .Sprintf ("perms: %d site, %d over %d orgs, %d user" ,
122
- len (customRole .SitePermissions ), totalOrg , len (customRole .OrganizationPermissions ), len (customRole .UserPermissions ))
123
- _ , err = cliui .Prompt (inv , cliui.PromptOptions {
124
- Text : "Are you sure you wish to update the role? " + preview ,
125
- Default : "yes" ,
126
- IsConfirm : true ,
127
- })
128
- if err != nil {
129
- return xerrors .Errorf ("abort: %w" , err )
89
+ customRole = * interactiveRole
90
+
91
+ // Only the interactive can answer prompts.
92
+ totalOrg := 0
93
+ for _ , o := range customRole .OrganizationPermissions {
94
+ totalOrg += len (o )
95
+ }
96
+ preview := fmt .Sprintf ("perms: %d site, %d over %d orgs, %d user" ,
97
+ len (customRole .SitePermissions ), totalOrg , len (customRole .OrganizationPermissions ), len (customRole .UserPermissions ))
98
+ _ , err = cliui .Prompt (inv , cliui.PromptOptions {
99
+ Text : "Are you sure you wish to update the role? " + preview ,
100
+ Default : "yes" ,
101
+ IsConfirm : true ,
102
+ })
103
+ if err != nil {
104
+ return xerrors .Errorf ("abort: %w" , err )
105
+ }
130
106
}
131
107
108
+ var err error
132
109
var updated codersdk.Role
133
110
if dryRun {
134
111
// Do not actually post
135
- updated = * customRole
112
+ updated = customRole
136
113
} else {
137
- updated , err = client .PatchRole (ctx , * customRole )
114
+ updated , err = client .PatchRole (ctx , customRole )
138
115
if err != nil {
139
116
return fmt .Errorf ("patch role: %w" , err )
140
117
}
141
118
}
142
119
143
- _ , err = formatter .Format (ctx , updated )
120
+ output , err : = formatter .Format (ctx , updated )
144
121
if err != nil {
145
122
return xerrors .Errorf ("formatting: %w" , err )
146
123
}
147
- return nil
124
+
125
+ _ , err = fmt .Fprintln (inv .Stdout , output )
126
+ return err
148
127
},
149
128
}
150
129
151
130
formatter .AttachOptions (& cmd .Options )
152
131
return cmd
153
132
}
154
133
155
- func interactiveEdit (inv * serpent.Invocation , role * codersdk.Role ) (* codersdk.Role , error ) {
134
+ func interactiveEdit (inv * serpent.Invocation , client * codersdk.Client ) (* codersdk.Role , error ) {
135
+ ctx := inv .Context ()
136
+ roles , err := client .ListSiteRoles (ctx )
137
+ if err != nil {
138
+ return nil , xerrors .Errorf ("listing roles: %w" , err )
139
+ }
140
+
141
+ // Make sure the role actually exists first
142
+ var originalRole codersdk.AssignableRoles
143
+ for _ , r := range roles {
144
+ if strings .EqualFold (inv .Args [0 ], r .Name ) {
145
+ originalRole = r
146
+ break
147
+ }
148
+ }
149
+
150
+ if originalRole .Name == "" {
151
+ _ , err = cliui .Prompt (inv , cliui.PromptOptions {
152
+ Text : "No role exists with that name, do you want to create one?" ,
153
+ Default : "yes" ,
154
+ IsConfirm : true ,
155
+ })
156
+ if err != nil {
157
+ return nil , xerrors .Errorf ("abort: %w" , err )
158
+ }
159
+
160
+ originalRole .Role = codersdk.Role {
161
+ Name : inv .Args [0 ],
162
+ }
163
+ }
164
+
165
+ // Some checks since interactive mode is limited in what it currently sees
166
+ if len (originalRole .OrganizationPermissions ) > 0 {
167
+ return nil , xerrors .Errorf ("unable to edit role in interactive mode, it contains organization permissions" )
168
+ }
169
+
170
+ if len (originalRole .UserPermissions ) > 0 {
171
+ return nil , xerrors .Errorf ("unable to edit role in interactive mode, it contains user permissions" )
172
+ }
173
+
174
+ role := & originalRole .Role
156
175
allowedResources := []codersdk.RBACResource {
157
176
codersdk .ResourceTemplate ,
158
177
codersdk .ResourceWorkspace ,
0 commit comments