8
8
"os"
9
9
"path/filepath"
10
10
"strings"
11
+ "text/template"
11
12
12
13
"github.com/google/uuid"
13
14
"golang.org/x/xerrors"
@@ -377,6 +378,45 @@ func TarWithOptions(ctx context.Context, logger slog.Logger, responses *Response
377
378
378
379
logger .Debug (context .Background (), "extra file written" , slog .F ("name" , name ), slog .F ("bytes_written" , n ))
379
380
}
381
+
382
+ // Write a main.tf with the appropriate parameters. This is to write terraform
383
+ // that matches the parameters defined in the responses. Dynamic parameters
384
+ // parsed these, even in the echo provisioner.
385
+ var mainTF bytes.Buffer
386
+ for _ , respPlan := range responses .ProvisionPlan {
387
+ plan := respPlan .GetPlan ()
388
+ if plan == nil {
389
+ continue
390
+ }
391
+
392
+ for _ , param := range plan .Parameters {
393
+ paramTF , err := ParameterTerraform (param )
394
+ if err != nil {
395
+ return nil , xerrors .Errorf ("parameter terraform: %w" , err )
396
+ }
397
+ mainTF .WriteString (paramTF )
398
+ }
399
+ }
400
+
401
+ if mainTF .Len () > 0 {
402
+ mainTFData := `
403
+ terraform {
404
+ required_providers {
405
+ coder = {
406
+ source = "coder/coder"
407
+ }
408
+ }
409
+ }
410
+ ` + mainTF .String ()
411
+
412
+ _ = writer .WriteHeader (& tar.Header {
413
+ Name : `main.tf` ,
414
+ Size : int64 (len (mainTFData )),
415
+ Mode : 0o644 ,
416
+ })
417
+ _ , _ = writer .Write ([]byte (mainTFData ))
418
+ }
419
+
380
420
// `writer.Close()` function flushes the writer buffer, and adds extra padding to create a legal tarball.
381
421
err := writer .Close ()
382
422
if err != nil {
@@ -385,6 +425,65 @@ func TarWithOptions(ctx context.Context, logger slog.Logger, responses *Response
385
425
return buffer .Bytes (), nil
386
426
}
387
427
428
+ // ParameterTerraform will create a Terraform data block for the provided parameter.
429
+ func ParameterTerraform (param * proto.RichParameter ) (string , error ) {
430
+ tmpl := template .Must (template .New ("parameter" ).Funcs (map [string ]any {
431
+ "showValidation" : func (v * proto.RichParameter ) bool {
432
+ return v != nil && (v .ValidationMax != nil || v .ValidationMin != nil ||
433
+ v .ValidationError != "" || v .ValidationRegex != "" ||
434
+ v .ValidationMonotonic != "" )
435
+ },
436
+ }).Parse (`
437
+ data "coder_parameter" "{{ .Name }}" {
438
+ name = "{{ .Name }}"
439
+ display_name = "{{ .DisplayName }}"
440
+ description = "{{ .Description }}"
441
+ icon = "{{ .Icon }}"
442
+ mutable = {{ .Mutable }}
443
+ ephemeral = {{ .Ephemeral }}
444
+ order = {{ .Order }}
445
+ {{- if .DefaultValue }}
446
+ default = "{{ .DefaultValue }}"
447
+ {{- end }}
448
+ {{- if .Type }}
449
+ type = "{{ .Type }}"
450
+ {{- end }}
451
+ {{- if .FormType }}
452
+ form_type = "{{ .FormType }}"
453
+ {{- end }}
454
+ {{- range .Options }}
455
+ option {
456
+ name = "{{ .Name }}"
457
+ value = "{{ .Value }}"
458
+ }
459
+ {{- end }}
460
+ {{- if showValidation .}}
461
+ validation {
462
+ {{- if .ValidationRegex }}
463
+ regex = "{{ .ValidationRegex }}"
464
+ {{- end }}
465
+ {{- if .ValidationError }}
466
+ error = "{{ .ValidationError }}"
467
+ {{- end }}
468
+ {{- if .ValidationMin }}
469
+ min = {{ .ValidationMin }}
470
+ {{- end }}
471
+ {{- if .ValidationMax }}
472
+ max = {{ .ValidationMax }}
473
+ {{- end }}
474
+ {{- if .ValidationMonotonic }}
475
+ monotonic = {{ .ValidationMonotonic }}
476
+ {{- end }}
477
+ }
478
+ {{- end }}
479
+ }
480
+ ` ))
481
+
482
+ var buf bytes.Buffer
483
+ err := tmpl .Execute (& buf , param )
484
+ return buf .String (), err
485
+ }
486
+
388
487
func WithResources (resources []* proto.Resource ) * Responses {
389
488
return & Responses {
390
489
Parse : ParseComplete ,
0 commit comments