@@ -335,15 +335,38 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
335
335
return
336
336
}
337
337
338
- api .postWorkspaceBuildsInternal (rw ,r ,apiKey ,workspace ,createBuild )
338
+ apiBuild ,err := api .postWorkspaceBuildsInternal (
339
+ ctx ,
340
+ apiKey ,
341
+ workspace ,
342
+ createBuild ,
343
+ func (action policy.Action ,object rbac.Objecter )bool {
344
+ return api .Authorize (r ,action ,object )
345
+ },
346
+ audit .WorkspaceBuildBaggageFromRequest (r ),
347
+ )
348
+ if err != nil {
349
+ httperror .WriteWorkspaceBuildError (ctx ,rw ,err )
350
+ return
351
+ }
352
+
353
+ httpapi .Write (ctx ,rw ,http .StatusCreated ,apiBuild )
339
354
}
340
355
341
356
// postWorkspaceBuildsInternal handles the internal logic for creating
342
357
// workspace builds, can be called by other handlers and must not
343
358
// reference httpmw.
344
- func (api * API )postWorkspaceBuildsInternal (rw http.ResponseWriter ,r * http.Request ,apiKey database.APIKey ,workspace database.Workspace ,createBuild codersdk.CreateWorkspaceBuildRequest ) {
345
- ctx := r .Context ()
346
-
359
+ func (api * API )postWorkspaceBuildsInternal (
360
+ ctx context.Context ,
361
+ apiKey database.APIKey ,
362
+ workspace database.Workspace ,
363
+ createBuild codersdk.CreateWorkspaceBuildRequest ,
364
+ authorize func (action policy.Action ,object rbac.Objecter )bool ,
365
+ workspaceBuildBaggage audit.WorkspaceBuildBaggage ,
366
+ ) (
367
+ codersdk.WorkspaceBuild ,
368
+ error ,
369
+ ) {
347
370
transition := database .WorkspaceTransition (createBuild .Transition )
348
371
builder := wsbuilder .New (workspace ,transition ,* api .BuildUsageChecker .Load ()).
349
372
Initiator (apiKey .UserID ).
@@ -370,11 +393,10 @@ func (api *API) postWorkspaceBuildsInternal(rw http.ResponseWriter, r *http.Requ
370
393
previousWorkspaceBuild ,err = tx .GetLatestWorkspaceBuildByWorkspaceID (ctx ,workspace .ID )
371
394
if err != nil && ! xerrors .Is (err ,sql .ErrNoRows ) {
372
395
api .Logger .Error (ctx ,"failed fetching previous workspace build" ,slog .F ("workspace_id" ,workspace .ID ),slog .Error (err ))
373
- httpapi . Write ( ctx , rw , http .StatusInternalServerError , codersdk.Response {
396
+ return httperror . NewResponseError ( http .StatusInternalServerError , codersdk.Response {
374
397
Message :"Internal error fetching previous workspace build" ,
375
398
Detail :err .Error (),
376
399
})
377
- return nil
378
400
}
379
401
380
402
if createBuild .TemplateVersionID != uuid .Nil {
@@ -383,16 +405,14 @@ func (api *API) postWorkspaceBuildsInternal(rw http.ResponseWriter, r *http.Requ
383
405
384
406
if createBuild .Orphan {
385
407
if createBuild .Transition != codersdk .WorkspaceTransitionDelete {
386
- httpapi . Write ( ctx , rw , http .StatusBadRequest , codersdk.Response {
408
+ return httperror . NewResponseError ( http .StatusBadRequest , codersdk.Response {
387
409
Message :"Orphan is only permitted when deleting a workspace." ,
388
410
})
389
- return nil
390
411
}
391
412
if len (createBuild .ProvisionerState )> 0 {
392
- httpapi . Write ( ctx , rw , http .StatusBadRequest , codersdk.Response {
413
+ return httperror . NewResponseError ( http .StatusBadRequest , codersdk.Response {
393
414
Message :"ProvisionerState cannot be set alongside Orphan since state intent is unclear." ,
394
415
})
395
- return nil
396
416
}
397
417
builder = builder .Orphan ()
398
418
}
@@ -405,24 +425,23 @@ func (api *API) postWorkspaceBuildsInternal(rw http.ResponseWriter, r *http.Requ
405
425
tx ,
406
426
api .FileCache ,
407
427
func (action policy.Action ,object rbac.Objecter )bool {
408
- if auth := api . Authorize ( r , action ,object );auth {
428
+ if auth := authorize ( action ,object );auth {
409
429
return true
410
430
}
411
431
// Special handling for prebuilt workspace deletion
412
432
if action == policy .ActionDelete {
413
433
if workspaceObj ,ok := object .(database.PrebuiltWorkspaceResource );ok && workspaceObj .IsPrebuild () {
414
- return api . Authorize ( r , action ,workspaceObj .AsPrebuild ())
434
+ return authorize ( action ,workspaceObj .AsPrebuild ())
415
435
}
416
436
}
417
437
return false
418
438
},
419
- audit . WorkspaceBuildBaggageFromRequest ( r ) ,
439
+ workspaceBuildBaggage ,
420
440
)
421
441
return err
422
442
},nil )
423
443
if err != nil {
424
- httperror .WriteWorkspaceBuildError (ctx ,rw ,err )
425
- return
444
+ return codersdk.WorkspaceBuild {},err
426
445
}
427
446
428
447
var queuePos database.GetProvisionerJobsByIDsWithQueuePositionRow
@@ -486,11 +505,13 @@ func (api *API) postWorkspaceBuildsInternal(rw http.ResponseWriter, r *http.Requ
486
505
provisionerDaemons ,
487
506
)
488
507
if err != nil {
489
- httpapi .Write (ctx ,rw ,http .StatusInternalServerError , codersdk.Response {
490
- Message :"Internal error converting workspace build." ,
491
- Detail :err .Error (),
492
- })
493
- return
508
+ return codersdk.WorkspaceBuild {},httperror .NewResponseError (
509
+ http .StatusInternalServerError ,
510
+ codersdk.Response {
511
+ Message :"Internal error converting workspace build." ,
512
+ Detail :err .Error (),
513
+ },
514
+ )
494
515
}
495
516
496
517
// If this workspace build has a different template version ID to the previous build
@@ -517,7 +538,7 @@ func (api *API) postWorkspaceBuildsInternal(rw http.ResponseWriter, r *http.Requ
517
538
WorkspaceID :workspace .ID ,
518
539
})
519
540
520
- httpapi . Write ( ctx , rw , http . StatusCreated , apiBuild )
541
+ return apiBuild , nil
521
542
}
522
543
523
544
func (api * API )notifyWorkspaceUpdated (