@@ -26,6 +26,45 @@ type parameterValue struct {
2626 Source parameterValueSource
2727}
2828
29+ type ResolverError struct {
30+ Diagnostics hcl.Diagnostics
31+ Parameter map [string ]hcl.Diagnostics
32+ }
33+
34+ // Error is a pretty bad format for these errors. Try to avoid using this.
35+ func (e * ResolverError ) Error () string {
36+ var diags hcl.Diagnostics
37+ diags = diags .Extend (e .Diagnostics )
38+ for _ , d := range e .Parameter {
39+ diags = diags .Extend (d )
40+ }
41+
42+ return diags .Error ()
43+ }
44+
45+ func (e * ResolverError ) HasError () bool {
46+ if e .Diagnostics .HasErrors () {
47+ return true
48+ }
49+
50+ for _ , diags := range e .Parameter {
51+ if diags .HasErrors () {
52+ return true
53+ }
54+ }
55+ return false
56+ }
57+
58+ func (e * ResolverError ) Extend (parameterName string , diag hcl.Diagnostics ) {
59+ if e .Parameter == nil {
60+ e .Parameter = make (map [string ]hcl.Diagnostics )
61+ }
62+ if _ , ok := e .Parameter [parameterName ]; ! ok {
63+ e .Parameter [parameterName ] = hcl.Diagnostics {}
64+ }
65+ e .Parameter [parameterName ] = e .Parameter [parameterName ].Extend (diag )
66+ }
67+
2968//nolint:revive // firstbuild is a control flag to turn on immutable validation
3069func ResolveParameters (
3170 ctx context.Context ,
@@ -35,7 +74,7 @@ func ResolveParameters(
3574 previousValues []database.WorkspaceBuildParameter ,
3675 buildValues []codersdk.WorkspaceBuildParameter ,
3776 presetValues []database.TemplateVersionPresetParameter ,
38- ) (map [string ]string , hcl. Diagnostics ) {
77+ ) (map [string ]string , error ) {
3978 previousValuesMap := slice .ToMap (previousValues , func (p database.WorkspaceBuildParameter ) (string , string ) {
4079 return p .Name , p .Value
4180 })
@@ -73,7 +112,10 @@ func ResolveParameters(
73112 // always be valid. If there is a case where this is not true, then this has to
74113 // be changed to allow the build to continue with a different set of values.
75114
76- return nil , diags
115+ return nil , & ResolverError {
116+ Diagnostics : diags ,
117+ Parameter : nil ,
118+ }
77119 }
78120
79121 // The user's input now needs to be validated against the parameters.
@@ -114,12 +156,16 @@ func ResolveParameters(
114156 // are fatal. Additional validation for immutability has to be done manually.
115157 output , diags = renderer .Render (ctx , ownerID , values .ValuesMap ())
116158 if diags .HasErrors () {
117- return nil , diags
159+ return nil , & ResolverError {
160+ Diagnostics : diags ,
161+ Parameter : nil ,
162+ }
118163 }
119164
120165 // parameterNames is going to be used to remove any excess values that were left
121166 // around without a parameter.
122167 parameterNames := make (map [string ]struct {}, len (output .Parameters ))
168+ parameterError := & ResolverError {}
123169 for _ , parameter := range output .Parameters {
124170 parameterNames [parameter .Name ] = struct {}{}
125171
@@ -133,20 +179,22 @@ func ResolveParameters(
133179 }
134180
135181 // An immutable parameter was changed, which is not allowed.
136- // Add the failed diagnostic to the output.
137- diags = diags .Append (& hcl.Diagnostic {
138- Severity : hcl .DiagError ,
139- Summary : "Immutable parameter changed" ,
140- Detail : fmt .Sprintf ("Parameter %q is not mutable, so it can't be updated after creating a workspace." , parameter .Name ),
141- Subject : src ,
182+ // Add a failed diagnostic to the output.
183+ parameterError .Extend (parameter .Name , hcl.Diagnostics {
184+ & hcl.Diagnostic {
185+ Severity : hcl .DiagError ,
186+ Summary : "Immutable parameter changed" ,
187+ Detail : fmt .Sprintf ("Parameter %q is not mutable, so it can't be updated after creating a workspace." , parameter .Name ),
188+ Subject : src ,
189+ },
142190 })
143191 }
144192 }
145193
146194 // TODO: Fix the `hcl.Diagnostics(...)` type casting. It should not be needed.
147195 if hcl .Diagnostics (parameter .Diagnostics ).HasErrors () {
148- // All validation errors are raised here.
149- diags = diags .Extend (hcl .Diagnostics (parameter .Diagnostics ))
196+ // All validation errors are raised here for each parameter .
197+ parameterError .Extend (parameter . Name , hcl .Diagnostics (parameter .Diagnostics ))
150198 }
151199
152200 // If the parameter has a value, but it was not set explicitly by the user at any
@@ -175,8 +223,13 @@ func ResolveParameters(
175223 }
176224 }
177225
226+ if parameterError .HasError () {
227+ // If there are any errors, return them.
228+ return nil , parameterError
229+ }
230+
178231 // Return the values to be saved for the build.
179- return values .ValuesMap (), diags
232+ return values .ValuesMap (), nil
180233}
181234
182235type parameterValueMap map [string ]parameterValue
0 commit comments