Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
backport of commit 116646a
  • Loading branch information
nfagerlund committed Dec 9, 2025
commit 46cbd84580b3456a9e2a8dff800fed8953affae6
26 changes: 25 additions & 1 deletion internal/configs/source_bundle_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,31 @@ func (p *SourceBundleParser) LoadConfigDir(source sourceaddrs.FinalSource) (*Mod
})
return nil, diags
}
mod.SourceDir = sourceDir

// The result of sources.LocalPathForSource is an absolute path, but we
// don't actually want to pass an absolute path for a module's SourceDir;
// doing so will cause the value of `path.module` in Terraform configs to
// differ across plans and applies, since tfc-agent performs plans and
// applies in temporary directories. Instead, we try to resolve a relative
// path from Terraform's working directory, which should always be a
// reasonable SourceDir value.
workDir, err := os.Getwd()
if err != nil {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Cannot resolve working directory",
Detail: fmt.Sprintf("Failed to resolve current working directory: %s. This is a bug in Terraform - please report it.", err),
})
}
relativeSourceDir, err := filepath.Rel(workDir, sourceDir)
if err != nil {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Cannot resolve relative path",
Detail: fmt.Sprintf("Failed to resolve relative path to module directory: %s. This is a bug in Terraform - please report it.", err),
})
}
mod.SourceDir = relativeSourceDir

return mod, diags
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -852,29 +851,21 @@ func TestPlanning_PathValues(t *testing.T) {
t.Fatalf("failed to get current working directory: %s", err)
}

normalizePath := func(path string) string {
rel, err := filepath.Rel(cwd, path)
if err != nil {
t.Errorf("rel(%s,%s): %s", cwd, path, err)
return path
}
return rel
}

// path.cwd should be absolute and all others should be relative, as per documentation.
expected := map[string]string{
"cwd": ".",
"cwd": cwd,
"root": "testdata/sourcebundle/planning/path_values/module", // this is the root module of the component
"module": "testdata/sourcebundle/planning/path_values/module", // this is the root module
"child_root": "testdata/sourcebundle/planning/path_values/module", // should be the same for all modules
"child_module": "testdata/sourcebundle/planning/path_values/module/child", // this is the child module
}

actual := map[string]string{
"cwd": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "cwd"}].AsString()),
"root": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "root"}].AsString()),
"module": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "module"}].AsString()),
"child_root": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "child_root"}].AsString()),
"child_module": normalizePath(component.PlannedOutputValues[addrs.OutputValue{Name: "child_module"}].AsString()),
"cwd": component.PlannedOutputValues[addrs.OutputValue{Name: "cwd"}].AsString(),
"root": component.PlannedOutputValues[addrs.OutputValue{Name: "root"}].AsString(),
"module": component.PlannedOutputValues[addrs.OutputValue{Name: "module"}].AsString(),
"child_root": component.PlannedOutputValues[addrs.OutputValue{Name: "child_root"}].AsString(),
"child_module": component.PlannedOutputValues[addrs.OutputValue{Name: "child_module"}].AsString(),
}

if cmp.Diff(expected, actual) != "" {
Expand Down