@@ -26,6 +26,45 @@ type parameterValue struct {
2626Source 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 (
3170ctx context.Context ,
@@ -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.
@@ -113,12 +155,16 @@ func ResolveParameters(
113155// are fatal. Additional validation for immutability has to be done manually.
114156output ,diags = renderer .Render (ctx ,ownerID ,values .ValuesMap ())
115157if diags .HasErrors () {
116- return nil ,diags
158+ return nil ,& ResolverError {
159+ Diagnostics :diags ,
160+ Parameter :nil ,
161+ }
117162}
118163
119164// parameterNames is going to be used to remove any excess values that were left
120165// around without a parameter.
121166parameterNames := make (map [string ]struct {},len (output .Parameters ))
167+ parameterError := & ResolverError {}
122168for _ ,parameter := range output .Parameters {
123169parameterNames [parameter .Name ]= struct {}{}
124170
@@ -132,20 +178,22 @@ func ResolveParameters(
132178}
133179
134180// An immutable parameter was changed, which is not allowed.
135- // Add the failed diagnostic to the output.
136- diags = diags .Append (& hcl.Diagnostic {
137- Severity :hcl .DiagError ,
138- Summary :"Immutable parameter changed" ,
139- Detail :fmt .Sprintf ("Parameter %q is not mutable, so it can't be updated after creating a workspace." ,parameter .Name ),
140- Subject :src ,
181+ // Add a failed diagnostic to the output.
182+ parameterError .Extend (parameter .Name , hcl.Diagnostics {
183+ & hcl.Diagnostic {
184+ Severity :hcl .DiagError ,
185+ Summary :"Immutable parameter changed" ,
186+ Detail :fmt .Sprintf ("Parameter %q is not mutable, so it can't be updated after creating a workspace." ,parameter .Name ),
187+ Subject :src ,
188+ },
141189})
142190}
143191}
144192
145193// TODO: Fix the `hcl.Diagnostics(...)` type casting. It should not be needed.
146194if hcl .Diagnostics (parameter .Diagnostics ).HasErrors () {
147- // All validation errors are raised here.
148- diags = diags .Extend (hcl .Diagnostics (parameter .Diagnostics ))
195+ // All validation errors are raised here for each parameter .
196+ parameterError .Extend (parameter . Name , hcl .Diagnostics (parameter .Diagnostics ))
149197}
150198
151199// If the parameter has a value, but it was not set explicitly by the user at any
@@ -174,8 +222,13 @@ func ResolveParameters(
174222}
175223}
176224
225+ if parameterError .HasError () {
226+ // If there are any errors, return them.
227+ return nil ,parameterError
228+ }
229+
177230// Return the values to be saved for the build.
178- return values .ValuesMap (),diags
231+ return values .ValuesMap (),nil
179232}
180233
181234type parameterValueMap map [string ]parameterValue