6
6
"encoding/json"
7
7
"fmt"
8
8
"io"
9
+ "slices"
9
10
"strings"
10
11
11
12
"cdr.dev/slog"
@@ -1053,7 +1054,7 @@ func markActive(ctx context.Context, client *codersdk.Client, templateID uuid.UU
1053
1054
ID : versionID ,
1054
1055
})
1055
1056
if err != nil {
1056
- return fmt .Errorf ("Failed to update active template version: %s" , err )
1057
+ return fmt .Errorf ("failed to update active template version: %s" , err )
1057
1058
}
1058
1059
tflog .Info (ctx , "marked template version as active" )
1059
1060
return nil
@@ -1231,8 +1232,9 @@ type LastVersionsByHash = map[string][]PreviousTemplateVersion
1231
1232
var LastVersionsKey = "last_versions"
1232
1233
1233
1234
type PreviousTemplateVersion struct {
1234
- ID uuid.UUID `json:"id"`
1235
- Name string `json:"name"`
1235
+ ID uuid.UUID `json:"id"`
1236
+ Name string `json:"name"`
1237
+ TFVars map [string ]string
1236
1238
}
1237
1239
1238
1240
type privateState interface {
@@ -1244,18 +1246,24 @@ func (v Versions) setPrivateState(ctx context.Context, ps privateState) (diags d
1244
1246
lv := make (LastVersionsByHash )
1245
1247
for _ , version := range v {
1246
1248
vbh , ok := lv [version .DirectoryHash .ValueString ()]
1249
+ tfVars := make (map [string ]string , len (version .TerraformVariables ))
1250
+ for _ , tfVar := range version .TerraformVariables {
1251
+ tfVars [tfVar .Name .ValueString ()] = tfVar .Value .ValueString ()
1252
+ }
1247
1253
// Store the IDs and names of all versions with the same directory hash,
1248
1254
// in the order they appear
1249
1255
if ok {
1250
1256
lv [version .DirectoryHash .ValueString ()] = append (vbh , PreviousTemplateVersion {
1251
- ID : version .ID .ValueUUID (),
1252
- Name : version .Name .ValueString (),
1257
+ ID : version .ID .ValueUUID (),
1258
+ Name : version .Name .ValueString (),
1259
+ TFVars : tfVars ,
1253
1260
})
1254
1261
} else {
1255
1262
lv [version .DirectoryHash .ValueString ()] = []PreviousTemplateVersion {
1256
1263
{
1257
- ID : version .ID .ValueUUID (),
1258
- Name : version .Name .ValueString (),
1264
+ ID : version .ID .ValueUUID (),
1265
+ Name : version .Name .ValueString (),
1266
+ TFVars : tfVars ,
1259
1267
},
1260
1268
}
1261
1269
}
@@ -1269,6 +1277,13 @@ func (v Versions) setPrivateState(ctx context.Context, ps privateState) (diags d
1269
1277
}
1270
1278
1271
1279
func (planVersions Versions ) reconcileVersionIDs (lv LastVersionsByHash , configVersions Versions ) {
1280
+ // We remove versions that we've matched from `lv`, so make a copy for
1281
+ // resolving tfvar changes at the end.
1282
+ fullLv := make (LastVersionsByHash )
1283
+ for k , v := range lv {
1284
+ fullLv [k ] = slices .Clone (v )
1285
+ }
1286
+
1272
1287
for i := range planVersions {
1273
1288
prevList , ok := lv [planVersions [i ].DirectoryHash .ValueString ()]
1274
1289
// If not in state, mark as known after apply since we'll create a new version.
@@ -1308,4 +1323,47 @@ func (planVersions Versions) reconcileVersionIDs(lv LastVersionsByHash, configVe
1308
1323
lv [planVersions [i ].DirectoryHash .ValueString ()] = prevList [1 :]
1309
1324
}
1310
1325
}
1326
+
1327
+ // If only the Terraform variables have changed,
1328
+ // we need to create a new version with the new variables.
1329
+ for i := range planVersions {
1330
+ if ! planVersions [i ].ID .IsUnknown () {
1331
+ prevs , ok := fullLv [planVersions [i ].DirectoryHash .ValueString ()]
1332
+ if ! ok {
1333
+ continue
1334
+ }
1335
+ if tfVariablesChanged (prevs , & planVersions [i ]) {
1336
+ planVersions [i ].ID = NewUUIDUnknown ()
1337
+ // We could always set the name to unknown here, to generate a
1338
+ // random one (this is what the Web UI currently does when
1339
+ // only updating tfvars).
1340
+ // However, I think it'd be weird if the provider just started
1341
+ // ignoring the name you set in the config, we'll instead
1342
+ // require that users update the name if they update the tfvars.
1343
+ if configVersions [i ].Name .IsNull () {
1344
+ planVersions [i ].Name = types .StringUnknown ()
1345
+ }
1346
+ }
1347
+ }
1348
+ }
1349
+ }
1350
+
1351
+ func tfVariablesChanged (prevs []PreviousTemplateVersion , planned * TemplateVersion ) bool {
1352
+ for _ , prev := range prevs {
1353
+ if prev .ID == planned .ID .ValueUUID () {
1354
+ // If the previous version has no TFVars, then it was created using
1355
+ // an older provider version.
1356
+ if prev .TFVars == nil {
1357
+ return true
1358
+ }
1359
+ for _ , tfVar := range planned .TerraformVariables {
1360
+ if prev .TFVars [tfVar .Name .ValueString ()] != tfVar .Value .ValueString () {
1361
+ return true
1362
+ }
1363
+ }
1364
+ return false
1365
+ }
1366
+ }
1367
+ return true
1368
+
1311
1369
}
0 commit comments