@@ -2,9 +2,11 @@ package coder
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"io"
6
7
"net/http"
7
8
"net/url"
9
+ "strings"
8
10
"time"
9
11
10
12
"cdr.dev/wsep"
@@ -364,3 +366,146 @@ func (c *DefaultClient) WorkspacesByWorkspaceProvider(ctx context.Context, wpID
364
366
}
365
367
return workspaces , nil
366
368
}
369
+
370
+ const (
371
+ // SkipTemplateOrg allows skipping checks on organizations.
372
+ SkipTemplateOrg = "SKIP_ORG"
373
+ )
374
+
375
+ type TemplateScope string
376
+
377
+ const (
378
+ // TemplateScopeSite is the scope for a site wide policy template.
379
+ TemplateScopeSite = "site"
380
+ )
381
+
382
+ type SetPolicyTemplateRequest struct {
383
+ TemplateID string `json:"template_id"`
384
+ Type string `json:"type"` // site, org
385
+ }
386
+
387
+ type SetPolicyTemplateResponse struct {
388
+ MergeConflicts []* WorkspaceTemplateMergeConflict `json:"merge_conflicts"`
389
+ }
390
+
391
+ type WorkspaceTemplateMergeConflict struct {
392
+ WorkspaceID string `json:"workspace_id"`
393
+ CurrentTemplateWarnings []string `json:"current_template_warnings"`
394
+ CurrentTemplateError * TplError `json:"current_template_errors"`
395
+ LatestTemplateWarnings []string `json:"latest_template_warnings"`
396
+ LatestTemplateError * TplError `json:"latest_template_errors"`
397
+ CurrentTemplateIsLatest bool `json:"current_template_is_latest"`
398
+ Message string `json:"message"`
399
+ }
400
+
401
+ func (mc WorkspaceTemplateMergeConflict ) String () string {
402
+ var sb strings.Builder
403
+
404
+ if mc .Message != "" {
405
+ sb .WriteString (mc .Message )
406
+ }
407
+
408
+ currentConflicts := len (mc .CurrentTemplateWarnings ) != 0 || mc .CurrentTemplateError != nil
409
+ updateConflicts := len (mc .LatestTemplateWarnings ) != 0 || mc .LatestTemplateError != nil
410
+
411
+ if ! currentConflicts && ! updateConflicts {
412
+ sb .WriteString ("No workspace conflicts\n " )
413
+ return sb .String ()
414
+ }
415
+
416
+ if currentConflicts {
417
+ if len (mc .CurrentTemplateWarnings ) != 0 {
418
+ fmt .Fprintf (& sb , "Warnings: \n %s\n " , strings .Join (mc .CurrentTemplateWarnings , "\n " ))
419
+ }
420
+ if mc .CurrentTemplateError != nil {
421
+ fmt .Fprintf (& sb , "Errors: \n %s\n " , strings .Join (mc .CurrentTemplateError .Msgs , "\n " ))
422
+ }
423
+ }
424
+
425
+ if ! mc .CurrentTemplateIsLatest && updateConflicts {
426
+ sb .WriteString ("If workspace is updated to the latest template:\n " )
427
+ if len (mc .LatestTemplateWarnings ) != 0 {
428
+ fmt .Fprintf (& sb , "Warnings: \n %s\n " , strings .Join (mc .LatestTemplateWarnings , "\n " ))
429
+ }
430
+ if mc .LatestTemplateError != nil {
431
+ fmt .Fprintf (& sb , "Errors: \n %s\n " , strings .Join (mc .LatestTemplateError .Msgs , "\n " ))
432
+ }
433
+ }
434
+
435
+ return sb .String ()
436
+ }
437
+
438
+ type WorkspaceTemplateMergeConflicts []* WorkspaceTemplateMergeConflict
439
+
440
+ func (mcs WorkspaceTemplateMergeConflicts ) Summary () string {
441
+ var (
442
+ sb strings.Builder
443
+ currentWarnings int
444
+ updateWarnings int
445
+ currentErrors int
446
+ updateErrors int
447
+ )
448
+
449
+ for _ , mc := range mcs {
450
+ if len (mc .CurrentTemplateWarnings ) != 0 {
451
+ currentWarnings ++
452
+ }
453
+ if len (mc .LatestTemplateWarnings ) != 0 {
454
+ updateWarnings ++
455
+ }
456
+ if mc .CurrentTemplateError != nil {
457
+ currentErrors ++
458
+ }
459
+ if mc .LatestTemplateError != nil {
460
+ updateErrors ++
461
+ }
462
+ }
463
+
464
+ if currentErrors == 0 && updateErrors == 0 && currentWarnings == 0 && updateWarnings == 0 {
465
+ sb .WriteString ("No workspace conflicts\n " )
466
+ return sb .String ()
467
+ }
468
+
469
+ if currentErrors != 0 {
470
+ fmt .Fprintf (& sb , "%d workspaces will not be able to be rebuilt\n " , currentErrors )
471
+ }
472
+ if updateErrors != 0 {
473
+ fmt .Fprintf (& sb , "%d workspaces will not be able to be rebuilt if updated to the latest version\n " , updateErrors )
474
+ }
475
+ if currentWarnings != 0 {
476
+ fmt .Fprintf (& sb , "%d workspaces will be impacted\n " , currentWarnings )
477
+ }
478
+ if updateWarnings != 0 {
479
+ fmt .Fprintf (& sb , "%d workspaces will be impacted if updated to the latest version\n " , updateWarnings )
480
+ }
481
+
482
+ return sb .String ()
483
+ }
484
+
485
+ type TplError struct {
486
+ // Msgs are the human facing strings to present to the user. Since there can be multiple
487
+ // problems with a template, there might be multiple strings
488
+ Msgs []string `json:"messages"`
489
+ }
490
+
491
+ func (c * DefaultClient ) SetPolicyTemplate (ctx context.Context , templateID string , templateScope TemplateScope , dryRun bool ) (* SetPolicyTemplateResponse , error ) {
492
+ var (
493
+ resp SetPolicyTemplateResponse
494
+ query = url.Values {}
495
+ )
496
+
497
+ req := SetPolicyTemplateRequest {
498
+ TemplateID : templateID ,
499
+ Type : string (templateScope ),
500
+ }
501
+
502
+ if dryRun {
503
+ query .Set ("dry-run" , "true" )
504
+ }
505
+
506
+ if err := c .requestBody (ctx , http .MethodPost , "/api/private/workspaces/template/policy" , req , & resp , withQueryParams (query )); err != nil {
507
+ return nil , err
508
+ }
509
+
510
+ return & resp , nil
511
+ }
0 commit comments