feat: make dynamic parameters opt-in by default for new templates (#19006)

resolves #18975 

---------

Co-authored-by: Steven Masley <stevenmasley@gmail.com>
Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
This commit is contained in:
Jaayden Halko
2025-07-28 20:41:49 -05:00
committed by GitHub
co-authored by Steven Masley blink-so[bot]
parent faac75389b
commit 1320b8d5be
35 changed files with 476 additions and 91 deletions
+103
View File
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"strings"
"text/template"
"github.com/google/uuid"
"golang.org/x/xerrors"
@@ -377,6 +378,45 @@ func TarWithOptions(ctx context.Context, logger slog.Logger, responses *Response
logger.Debug(context.Background(), "extra file written", slog.F("name", name), slog.F("bytes_written", n))
}
// Write a main.tf with the appropriate parameters. This is to write terraform
// that matches the parameters defined in the responses. Dynamic parameters
// parsed these, even in the echo provisioner.
var mainTF bytes.Buffer
for _, respPlan := range responses.ProvisionPlan {
plan := respPlan.GetPlan()
if plan == nil {
continue
}
for _, param := range plan.Parameters {
paramTF, err := ParameterTerraform(param)
if err != nil {
return nil, xerrors.Errorf("parameter terraform: %w", err)
}
_, _ = mainTF.WriteString(paramTF)
}
}
if mainTF.Len() > 0 {
mainTFData := `
terraform {
required_providers {
coder = {
source = "coder/coder"
}
}
}
` + mainTF.String()
_ = writer.WriteHeader(&tar.Header{
Name: `main.tf`,
Size: int64(len(mainTFData)),
Mode: 0o644,
})
_, _ = writer.Write([]byte(mainTFData))
}
// `writer.Close()` function flushes the writer buffer, and adds extra padding to create a legal tarball.
err := writer.Close()
if err != nil {
@@ -385,6 +425,69 @@ func TarWithOptions(ctx context.Context, logger slog.Logger, responses *Response
return buffer.Bytes(), nil
}
// ParameterTerraform will create a Terraform data block for the provided parameter.
func ParameterTerraform(param *proto.RichParameter) (string, error) {
tmpl := template.Must(template.New("parameter").Funcs(map[string]any{
"showValidation": func(v *proto.RichParameter) bool {
return v != nil && (v.ValidationMax != nil || v.ValidationMin != nil ||
v.ValidationError != "" || v.ValidationRegex != "" ||
v.ValidationMonotonic != "")
},
"formType": func(v *proto.RichParameter) string {
s, _ := proto.ProviderFormType(v.FormType)
return string(s)
},
}).Parse(`
data "coder_parameter" "{{ .Name }}" {
name = "{{ .Name }}"
display_name = "{{ .DisplayName }}"
description = "{{ .Description }}"
icon = "{{ .Icon }}"
mutable = {{ .Mutable }}
ephemeral = {{ .Ephemeral }}
order = {{ .Order }}
{{- if .DefaultValue }}
default = {{ .DefaultValue }}
{{- end }}
{{- if .Type }}
type = "{{ .Type }}"
{{- end }}
{{- if .FormType }}
form_type = "{{ formType . }}"
{{- end }}
{{- range .Options }}
option {
name = "{{ .Name }}"
value = "{{ .Value }}"
}
{{- end }}
{{- if showValidation .}}
validation {
{{- if .ValidationRegex }}
regex = "{{ .ValidationRegex }}"
{{- end }}
{{- if .ValidationError }}
error = "{{ .ValidationError }}"
{{- end }}
{{- if .ValidationMin }}
min = {{ .ValidationMin }}
{{- end }}
{{- if .ValidationMax }}
max = {{ .ValidationMax }}
{{- end }}
{{- if .ValidationMonotonic }}
monotonic = "{{ .ValidationMonotonic }}"
{{- end }}
}
{{- end }}
}
`))
var buf bytes.Buffer
err := tmpl.Execute(&buf, param)
return buf.String(), err
}
func WithResources(resources []*proto.Resource) *Responses {
return &Responses{
Parse: ParseComplete,