@@ -261,17 +261,6 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
261
261
e .mut .Lock ()
262
262
defer e .mut .Unlock ()
263
263
264
- // TODO: defunct?
265
- // var isPrebuild bool
266
- // for _, v := range env {
267
- // if envName(v) == provider.IsPrebuildEnvironmentVariable() && envVar(v) == "true" {
268
- // isPrebuild = true
269
- // break
270
- // }
271
- // }
272
-
273
- // _ = isPrebuild
274
-
275
264
planfilePath := getPlanFilePath (e .workdir )
276
265
args := []string {
277
266
"plan" ,
@@ -341,6 +330,68 @@ func onlyDataResources(sm tfjson.StateModule) tfjson.StateModule {
341
330
return filtered
342
331
}
343
332
333
+ func (e * executor )logResourceReplacements (ctx context.Context ,plan * tfjson.Plan ) {
334
+ if plan == nil {
335
+ return
336
+ }
337
+
338
+ if len (plan .ResourceChanges )== 0 {
339
+ return
340
+ }
341
+ var (
342
+ count int
343
+ replacements = make (map [string ][]string ,len (plan .ResourceChanges ))
344
+ )
345
+
346
+ for _ ,ch := range plan .ResourceChanges {
347
+ // No change, no problem!
348
+ if ch .Change == nil {
349
+ continue
350
+ }
351
+
352
+ // No-op change, no problem!
353
+ if ch .Change .Actions .NoOp () {
354
+ continue
355
+ }
356
+
357
+ // No replacements, no problem!
358
+ if len (ch .Change .ReplacePaths )== 0 {
359
+ continue
360
+ }
361
+
362
+ // Replacing our resources, no problem!
363
+ if strings .Index (ch .Type ,"coder_" )== 0 {
364
+ continue
365
+ }
366
+
367
+ for _ ,p := range ch .Change .ReplacePaths {
368
+ var path string
369
+ switch p := p .(type ) {
370
+ case []interface {}:
371
+ segs := p
372
+ list := make ([]string ,0 ,len (segs ))
373
+ for _ ,s := range segs {
374
+ list = append (list ,fmt .Sprintf ("%v" ,s ))
375
+ }
376
+ path = strings .Join (list ,"." )
377
+ default :
378
+ path = fmt .Sprintf ("%v" ,p )
379
+ }
380
+
381
+ replacements [ch .Address ]= append (replacements [ch .Address ],path )
382
+ }
383
+
384
+ count ++
385
+ }
386
+
387
+ if count > 0 {
388
+ e .server .logger .Warn (ctx ,"plan introduces resource changes" ,slog .F ("count" ,count ))
389
+ for n ,p := range replacements {
390
+ e .server .logger .Warn (ctx ,"resource will be replaced!" ,slog .F ("name" ,n ),slog .F ("replacement_paths" ,strings .Join (p ,"," )))
391
+ }
392
+ }
393
+ }
394
+
344
395
// planResources must only be called while the lock is held.
345
396
func (e * executor )planResources (ctx ,killCtx context.Context ,planfilePath string ) (* State , json.RawMessage ,error ) {
346
397
ctx ,span := e .server .startTrace (ctx ,tracing .FuncName ())
@@ -351,6 +402,8 @@ func (e *executor) planResources(ctx, killCtx context.Context, planfilePath stri
351
402
return nil ,nil ,xerrors .Errorf ("show terraform plan file: %w" ,err )
352
403
}
353
404
405
+ e .logResourceReplacements (ctx ,plan )
406
+
354
407
rawGraph ,err := e .graph (ctx ,killCtx )
355
408
if err != nil {
356
409
return nil ,nil ,xerrors .Errorf ("graph: %w" ,err )