Files
coder/scripts/templatebuildermodulegen/write.go
T
Jeremy Ruppel a30631198d feat: template builder backend fixes (DEVEX-287) (#26432)
Part of the Template Builder wizard PR stack.

## Backend fixes

1. **Registry URL scheme fix**: Default
`CODER_TEMPLATE_BUILDER_REGISTRY_URL` was `https://registry.coder.com`
but Terraform module registry addresses must be scheme-less. Changed to
`registry.coder.com`.

2. **Sensitive variable defaults**: Module `.tf.tmpl` files for
claude-code, aider, amazon-q had sensitive `variable` blocks without
`default`, causing `terraform plan` to fail during template import. Also
fixed the `templatebuildermodulegen` script.

3. **Auto-quote string variables**: The backend now accepts raw string
values from callers and wraps them in HCL quotes automatically.
Previously callers were required to send pre-quoted HCL literals, which
is not a reasonable API contract.

---
> [!NOTE]
> Generated by Coder Agents on behalf of @jeremyruppel
2026-06-23 09:17:14 -04:00

83 lines
1.8 KiB
Go

package main
import (
"encoding/json"
"os"
"text/template"
)
func writeModuleJSON(path string, m ModuleManifest) error {
data, err := json.MarshalIndent(m, "", " ")
if err != nil {
return err
}
data = append(data, '\n')
return os.WriteFile(path, data, 0o600)
}
var tfTmplTemplate = template.Must(template.New("tf.tmpl").Funcs(template.FuncMap{
"hclValue": func(v ModuleVariable) string {
if v.Sensitive {
return "var." + v.Name
}
return "{{ .Variables." + v.Name + " }}"
},
}).Parse(`{{- range .SensitiveVars }}
variable "{{ .Name }}" {
description = "{{ .Description }}"
type = {{ .Type }}
sensitive = true
default = ""
}
{{ end -}}
module "{{ .ID }}" {
count = data.coder_workspace.me.start_count
source = "{{"{{"}} .RegistryBase {{"}}"}}/coder/{{ .ID }}/coder"
version = "{{"{{"}} .PinnedVersion {{"}}"}}"
agent_id = coder_agent.{{"{{"}} .AgentResourceName {{"}}"}}.id
{{- range .NonComputedVars }}
{{- if .Sensitive }}
{{ .Name }} = var.{{ .Name }}
{{- else }}
{{ .Name }} = {{"{{"}} .Variables.{{ .Name }} {{"}}"}}
{{- end }}
{{- end }}
}
`))
type tfTmplData struct {
ID string
SensitiveVars []ModuleVariable
NonComputedVars []ModuleVariable
}
func writeTFTmpl(path string, m ModuleManifest) error {
var sensitiveVars []ModuleVariable
var nonComputedVars []ModuleVariable
for _, v := range m.Variables {
if v.Computed {
continue
}
nonComputedVars = append(nonComputedVars, v)
if v.Sensitive {
sensitiveVars = append(sensitiveVars, v)
}
}
data := tfTmplData{
ID: m.ID,
SensitiveVars: sensitiveVars,
NonComputedVars: nonComputedVars,
}
f, err := os.Create(path)
if err != nil {
return err
}
err = tfTmplTemplate.Execute(f, data)
if closeErr := f.Close(); err == nil {
err = closeErr
}
return err
}