@@ -153,6 +153,7 @@ func (r *RootCmd) editOrganizationRole(orgContext *OrganizationContext) *serpent
153
153
return err
154
154
}
155
155
156
+ createNewRole := true
156
157
var customRole codersdk.Role
157
158
if jsonInput {
158
159
// JSON Upload mode
@@ -174,17 +175,30 @@ func (r *RootCmd) editOrganizationRole(orgContext *OrganizationContext) *serpent
174
175
}
175
176
return xerrors .Errorf ("json input does not appear to be a valid role" )
176
177
}
178
+
179
+ existingRoles ,err := client .ListOrganizationRoles (ctx ,org .ID )
180
+ if err != nil {
181
+ return xerrors .Errorf ("listing existing roles: %w" ,err )
182
+ }
183
+ for _ ,existingRole := range existingRoles {
184
+ if strings .EqualFold (customRole .Name ,existingRole .Name ) {
185
+ // Editing an existing role
186
+ createNewRole = false
187
+ break
188
+ }
189
+ }
177
190
}else {
178
191
if len (inv .Args )== 0 {
179
192
return xerrors .Errorf ("missing role name argument, usage:\" coder organizations roles edit <role_name>\" " )
180
193
}
181
194
182
- interactiveRole ,err := interactiveOrgRoleEdit (inv ,org .ID ,client )
195
+ interactiveRole ,newRole , err := interactiveOrgRoleEdit (inv ,org .ID ,client )
183
196
if err != nil {
184
197
return xerrors .Errorf ("editing role: %w" ,err )
185
198
}
186
199
187
200
customRole = * interactiveRole
201
+ createNewRole = newRole
188
202
189
203
preview := fmt .Sprintf ("permissions: %d site, %d org, %d user" ,
190
204
len (customRole .SitePermissions ),len (customRole .OrganizationPermissions ),len (customRole .UserPermissions ))
@@ -203,7 +217,12 @@ func (r *RootCmd) editOrganizationRole(orgContext *OrganizationContext) *serpent
203
217
// Do not actually post
204
218
updated = customRole
205
219
}else {
206
- updated ,err = client .PatchOrganizationRole (ctx ,customRole )
220
+ switch createNewRole {
221
+ case true :
222
+ updated ,err = client .CreateOrganizationRole (ctx ,customRole )
223
+ default :
224
+ updated ,err = client .UpdateOrganizationRole (ctx ,customRole )
225
+ }
207
226
if err != nil {
208
227
return xerrors .Errorf ("patch role: %w" ,err )
209
228
}
@@ -223,11 +242,12 @@ func (r *RootCmd) editOrganizationRole(orgContext *OrganizationContext) *serpent
223
242
return cmd
224
243
}
225
244
226
- func interactiveOrgRoleEdit (inv * serpent.Invocation ,orgID uuid.UUID ,client * codersdk.Client ) (* codersdk.Role ,error ) {
245
+ func interactiveOrgRoleEdit (inv * serpent.Invocation ,orgID uuid.UUID ,client * codersdk.Client ) (* codersdk.Role ,bool ,error ) {
246
+ newRole := false
227
247
ctx := inv .Context ()
228
248
roles ,err := client .ListOrganizationRoles (ctx ,orgID )
229
249
if err != nil {
230
- return nil ,xerrors .Errorf ("listing roles: %w" ,err )
250
+ return nil ,newRole , xerrors .Errorf ("listing roles: %w" ,err )
231
251
}
232
252
233
253
// Make sure the role actually exists first
@@ -246,22 +266,23 @@ func interactiveOrgRoleEdit(inv *serpent.Invocation, orgID uuid.UUID, client *co
246
266
IsConfirm :true ,
247
267
})
248
268
if err != nil {
249
- return nil ,xerrors .Errorf ("abort: %w" ,err )
269
+ return nil ,newRole , xerrors .Errorf ("abort: %w" ,err )
250
270
}
251
271
252
272
originalRole .Role = codersdk.Role {
253
273
Name :inv .Args [0 ],
254
274
OrganizationID :orgID .String (),
255
275
}
276
+ newRole = true
256
277
}
257
278
258
279
// Some checks since interactive mode is limited in what it currently sees
259
280
if len (originalRole .SitePermissions )> 0 {
260
- return nil ,xerrors .Errorf ("unable to edit role in interactive mode, it contains site wide permissions" )
281
+ return nil ,newRole , xerrors .Errorf ("unable to edit role in interactive mode, it contains site wide permissions" )
261
282
}
262
283
263
284
if len (originalRole .UserPermissions )> 0 {
264
- return nil ,xerrors .Errorf ("unable to edit role in interactive mode, it contains user permissions" )
285
+ return nil ,newRole , xerrors .Errorf ("unable to edit role in interactive mode, it contains user permissions" )
265
286
}
266
287
267
288
role := & originalRole .Role
@@ -283,13 +304,13 @@ customRoleLoop:
283
304
Options :append (permissionPreviews (role ,allowedResources ),done ,abort ),
284
305
})
285
306
if err != nil {
286
- return role ,xerrors .Errorf ("selecting resource: %w" ,err )
307
+ return role ,newRole , xerrors .Errorf ("selecting resource: %w" ,err )
287
308
}
288
309
switch selected {
289
310
case done :
290
311
break customRoleLoop
291
312
case abort :
292
- return role ,xerrors .Errorf ("edit role %q aborted" ,role .Name )
313
+ return role ,newRole , xerrors .Errorf ("edit role %q aborted" ,role .Name )
293
314
default :
294
315
strs := strings .Split (selected ,"::" )
295
316
resource := strings .TrimSpace (strs [0 ])
@@ -300,7 +321,7 @@ customRoleLoop:
300
321
Defaults :defaultActions (role ,resource ),
301
322
})
302
323
if err != nil {
303
- return role ,xerrors .Errorf ("selecting actions for resource %q: %w" ,resource ,err )
324
+ return role ,newRole , xerrors .Errorf ("selecting actions for resource %q: %w" ,resource ,err )
304
325
}
305
326
applyOrgResourceActions (role ,resource ,actions )
306
327
// back to resources!
@@ -309,7 +330,7 @@ customRoleLoop:
309
330
// This println is required because the prompt ends us on the same line as some text.
310
331
_ ,_ = fmt .Println ()
311
332
312
- return role ,nil
333
+ return role ,newRole , nil
313
334
}
314
335
315
336
func applyOrgResourceActions (role * codersdk.Role ,resource string ,actions []string ) {