Skip to content

Commit 16160ea

Browse files
authored
Merge branch 'main' into fix-render-remote-template
2 parents 608c81e + 1389227 commit 16160ea

7 files changed

Lines changed: 139 additions & 3 deletions

File tree

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ env: &env
77
TERRAFORM_VERSION: 1.5.7
88
TOFU_VERSION: 1.8.0
99
PACKER_VERSION: 1.10.0
10-
TERRAGRUNT_VERSION: v0.52.0
10+
TERRAGRUNT_VERSION: v0.69.8
1111
OPA_VERSION: v0.33.1
1212
GO_VERSION: 1.21.1
1313
GO111MODULE: auto

.github/pull_request_template.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Read the [Gruntwork contribution guidelines](https://gruntwork.notion.site/Grunt
1414
- [ ] Run the relevant tests successfully, including pre-commit checks.
1515
- [ ] Ensure any 3rd party code adheres with our [license policy](https://www.notion.so/gruntwork/Gruntwork-licenses-and-open-source-usage-policy-f7dece1f780341c7b69c1763f22b1378) or delete this line if its not applicable.
1616
- [ ] Include release notes. If this PR is backward incompatible, include a migration guide.
17+
- [ ] Make a plan for release of the functionality in this PR. If it delivers value to an end user, you are responsible for ensuring it is released promptly, and correctly. If you are not a maintainer, you are responsible for finding a maintainer to do this for you.
1718

1819
## Release Notes (draft)
1920

modules/terraform/cmd.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ const (
3939

4040
// TerraformDefaultPath to run terraform
4141
TerraformDefaultPath = "terraform"
42+
43+
// TerragruntDefaultPath to run terragrunt
44+
TerragruntDefaultPath = "terragrunt"
4245
)
4346

4447
var DefaultExecutable = defaultTerraformExecutable()
@@ -49,8 +52,22 @@ func GetCommonOptions(options *Options, args ...string) (*Options, []string) {
4952
options.TerraformBinary = DefaultExecutable
5053
}
5154

52-
if options.TerraformBinary == "terragrunt" {
55+
if options.TerraformBinary == TerragruntDefaultPath {
5356
args = append(args, "--terragrunt-non-interactive")
57+
// for newer Terragrunt version, setting simplified log formatting
58+
if options.EnvVars == nil {
59+
options.EnvVars = map[string]string{}
60+
}
61+
_, tgLogSet := options.EnvVars["TERRAGRUNT_LOG_FORMAT"]
62+
if !tgLogSet {
63+
// key-value format for terragrunt logs to avoid colors and have plain form
64+
// https://terragrunt.gruntwork.io/docs/reference/cli-options/#terragrunt-log-format
65+
options.EnvVars["TERRAGRUNT_LOG_FORMAT"] = "key-value"
66+
}
67+
_, tgLogFormat := options.EnvVars["TERRAGRUNT_LOG_CUSTOM_FORMAT"]
68+
if !tgLogFormat {
69+
options.EnvVars["TERRAGRUNT_LOG_CUSTOM_FORMAT"] = "%msg(color=disable)"
70+
}
5471
}
5572

5673
if options.Parallelism > 0 && len(args) > 0 && collections.ListContains(commandsWithParallelism, args[0]) {

modules/terraform/output.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,23 @@ import (
55
"errors"
66
"fmt"
77
"reflect"
8+
"regexp"
89
"strconv"
10+
"strings"
911

1012
"github.com/gruntwork-io/terratest/modules/testing"
1113
"github.com/stretchr/testify/require"
1214
)
1315

16+
const skipJsonLogLine = " msg="
17+
18+
var (
19+
// ansiLineRegex matches lines starting with ANSI escape codes for text formatting (e.g., colors, styles).
20+
ansiLineRegex = regexp.MustCompile(`(?m)^\x1b\[[0-9;]*m.*`)
21+
// tgLogLevel matches log lines containing fields for time, level, prefix, binary, and message, each with non-whitespace values.
22+
tgLogLevel = regexp.MustCompile(`.*time=\S+ level=\S+ prefix=\S+ binary=\S+ msg=.*`)
23+
)
24+
1425
// Output calls terraform output for the given variable and return its string value representation.
1526
// It only designed to work with primitive terraform types: string, number and bool.
1627
// Please use OutputStruct for anything else.
@@ -279,7 +290,11 @@ func OutputJsonE(t testing.TestingT, options *Options, key string) (string, erro
279290
args = append(args, key)
280291
}
281292

282-
return RunTerraformCommandAndGetStdoutE(t, options, args...)
293+
rawJson, err := RunTerraformCommandAndGetStdoutE(t, options, args...)
294+
if err != nil {
295+
return rawJson, err
296+
}
297+
return cleanJson(rawJson)
283298
}
284299

285300
// OutputStruct calls terraform output for the given variable and stores the
@@ -348,3 +363,33 @@ func OutputAll(t testing.TestingT, options *Options) map[string]interface{} {
348363
func OutputAllE(t testing.TestingT, options *Options) (map[string]interface{}, error) {
349364
return OutputForKeysE(t, options, nil)
350365
}
366+
367+
// clean the ANSI characters from the JSON and update formating
368+
func cleanJson(input string) (string, error) {
369+
// Remove ANSI escape codes
370+
cleaned := ansiLineRegex.ReplaceAllString(input, "")
371+
cleaned = tgLogLevel.ReplaceAllString(cleaned, "")
372+
373+
lines := strings.Split(cleaned, "\n")
374+
var result []string
375+
for _, line := range lines {
376+
trimmed := strings.TrimSpace(line)
377+
if trimmed != "" && !strings.Contains(trimmed, skipJsonLogLine) {
378+
result = append(result, trimmed)
379+
}
380+
}
381+
ansiClean := strings.Join(result, "\n")
382+
383+
var jsonObj interface{}
384+
if err := json.Unmarshal([]byte(ansiClean), &jsonObj); err != nil {
385+
return "", err
386+
}
387+
388+
// Format JSON output with indentation
389+
normalized, err := json.MarshalIndent(jsonObj, "", " ")
390+
if err != nil {
391+
return "", err
392+
}
393+
394+
return string(normalized), nil
395+
}

modules/terraform/output_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package terraform
22

33
import (
44
"fmt"
5+
"path/filepath"
56
"testing"
67

8+
"github.com/stretchr/testify/assert"
9+
710
"github.com/gruntwork-io/terratest/modules/files"
811
"github.com/stretchr/testify/require"
912
)
@@ -31,6 +34,40 @@ func TestOutputString(t *testing.T) {
3134

3235
num1 := Output(t, options, "number1")
3336
require.Equal(t, num1, "3", "Number %q should match %q", "3", num1)
37+
38+
unicodeString := Output(t, options, "unicode_string")
39+
require.Equal(t, "söme chäräcter", unicodeString)
40+
}
41+
42+
func TestTgOutputString(t *testing.T) {
43+
t.Parallel()
44+
45+
testFolder, err := files.CopyTerraformFolderToTemp("../../test/fixtures/terraform-output", t.Name())
46+
require.NoError(t, err)
47+
48+
WriteFile(t, filepath.Join(testFolder, "terragrunt.hcl"), []byte{})
49+
50+
options := &Options{
51+
TerraformDir: testFolder,
52+
TerraformBinary: "terragrunt",
53+
}
54+
55+
InitAndApply(t, options)
56+
57+
b := Output(t, options, "bool")
58+
require.Equal(t, b, "true", "Bool %q should match %q", "true", b)
59+
60+
str := Output(t, options, "string")
61+
require.Equal(t, str, "This is a string.", "String %q should match %q", "This is a string.", str)
62+
63+
num := Output(t, options, "number")
64+
require.Equal(t, num, "3.14", "Number %q should match %q", "3.14", num)
65+
66+
num1 := Output(t, options, "number1")
67+
require.Equal(t, num1, "3", "Number %q should match %q", "3", num1)
68+
69+
unicodeString := Output(t, options, "unicode_string")
70+
require.Equal(t, "söme chäräcter", unicodeString)
3471
}
3572

3673
func TestOutputList(t *testing.T) {
@@ -310,6 +347,11 @@ func TestOutputJson(t *testing.T) {
310347
"sensitive": false,
311348
"type": "string",
312349
"value": "This is a string."
350+
},
351+
"unicode_string": {
352+
"sensitive": false,
353+
"type": "string",
354+
"value": "söme chäräcter"
313355
}
314356
}`
315357

@@ -433,3 +475,27 @@ func TestOutputsForKeysError(t *testing.T) {
433475

434476
require.Error(t, err)
435477
}
478+
479+
func TestTgOutputJsonParsing(t *testing.T) {
480+
t.Parallel()
481+
482+
testFolder, err := files.CopyTerraformFolderToTemp("../../test/fixtures/terraform-output-map", t.Name())
483+
require.NoError(t, err)
484+
485+
WriteFile(t, filepath.Join(testFolder, "terragrunt.hcl"), []byte{})
486+
487+
options := &Options{
488+
TerraformDir: testFolder,
489+
TerraformBinary: "terragrunt",
490+
}
491+
492+
InitAndApply(t, options)
493+
494+
output, err := OutputAllE(t, options)
495+
496+
require.NoError(t, err)
497+
assert.NotNil(t, output)
498+
assert.NotEmpty(t, output)
499+
assert.Contains(t, output, "mogwai")
500+
assert.Equal(t, "söme chäräcter", output["not_a_map_unicode"])
501+
}

test/fixtures/terraform-output-map/output.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ output "not_a_map" {
1111
value = "This is not a map."
1212
}
1313

14+
output "not_a_map_unicode" {
15+
value = "söme chäräcter"
16+
}

test/fixtures/terraform-output/output.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ output "number" {
1313
output "number1" {
1414
value = 3
1515
}
16+
17+
output "unicode_string" {
18+
value = "söme chäräcter"
19+
}

0 commit comments

Comments
 (0)