@@ -106,7 +106,7 @@ func ResolveParameters(
106
106
//
107
107
// This is how the form should look to the user on their workspace settings page.
108
108
// This is the original form truth that our validations should initially be based on.
109
- output , diags := renderer .Render (ctx , ownerID , values . ValuesMap () )
109
+ output , diags := renderer .Render (ctx , ownerID , previousValuesMap )
110
110
if diags .HasErrors () {
111
111
// Top level diagnostics should break the build. Previous values (and new) should
112
112
// always be valid. If there is a case where this is not true, then this has to
@@ -123,6 +123,7 @@ func ResolveParameters(
123
123
//
124
124
// To enforce these, the user's input values are trimmed based on the
125
125
// mutability and ephemeral parameters defined in the template version.
126
+ wasImmutable := make (map [string ]struct {})
126
127
for _ , parameter := range output .Parameters {
127
128
// Ephemeral parameters should not be taken from the previous build.
128
129
// They must always be explicitly set in every build.
@@ -140,6 +141,7 @@ func ResolveParameters(
140
141
//
141
142
// We do this so the next form render uses the original immutable value.
142
143
if ! firstBuild && ! parameter .Mutable {
144
+ wasImmutable [parameter .Name ] = struct {}{}
143
145
delete (values , parameter .Name )
144
146
prev , ok := previousValuesMap [parameter .Name ]
145
147
if ok {
@@ -168,7 +170,12 @@ func ResolveParameters(
168
170
for _ , parameter := range output .Parameters {
169
171
parameterNames [parameter .Name ] = struct {}{}
170
172
171
- if ! firstBuild && ! parameter .Mutable {
173
+ // Immutability is sourced from the current `mutable` argument, and also the
174
+ // previous parameter's `mutable` argument. This means you cannot flip an
175
+ // `immutable` parameter to `mutable` in a single build. This is to preserve the
176
+ // original mutability of the parameter.
177
+ _ , wi := wasImmutable [parameter .Name ]
178
+ if ! firstBuild && (! parameter .Mutable || wi ) {
172
179
originalValue , ok := originalValues [parameter .Name ]
173
180
// Immutable parameters should not be changed after the first build.
174
181
// If the value matches the original value, that is fine.
@@ -182,13 +189,19 @@ func ResolveParameters(
182
189
if parameter .Source != nil {
183
190
src = & parameter .Source .HCLBlock ().TypeRange
184
191
}
192
+ errTitle := "Immutable"
193
+ // In the strange case someone flips mutability from `true` to `false`.
194
+ // Change the error title to indicate that this was previously immutable.
195
+ if wi && parameter .Mutable {
196
+ errTitle = "Previously immutable"
197
+ }
185
198
186
199
// An immutable parameter was changed, which is not allowed.
187
200
// Add a failed diagnostic to the output.
188
201
parameterError .Extend (parameter .Name , hcl.Diagnostics {
189
202
& hcl.Diagnostic {
190
203
Severity : hcl .DiagError ,
191
- Summary : "Immutable parameter changed" ,
204
+ Summary : fmt . Sprintf ( "%s parameter changed", errTitle ) ,
192
205
Detail : fmt .Sprintf ("Parameter %q is not mutable, so it can't be updated after creating a workspace." , parameter .Name ),
193
206
Subject : src ,
194
207
},
0 commit comments