diff --git a/cli/commands/hclfmt/action.go b/cli/commands/hclfmt/action.go
index 58888b194..b5eee59d3 100644
--- a/cli/commands/hclfmt/action.go
+++ b/cli/commands/hclfmt/action.go
@@ -4,8 +4,10 @@
package hclfmt
import (
+ "bufio"
"bytes"
"fmt"
+ "io"
"os"
"os/exec"
"path/filepath"
@@ -28,6 +30,16 @@ import (
func Run(opts *options.TerragruntOptions) error {
workingDir := opts.WorkingDir
targetFile := opts.HclFile
+ stdIn := opts.HclFromStdin
+
+ if stdIn {
+ if targetFile != "" {
+ opts.Logger.Debugf("Both stdin and path flags are specified")
+ return errors.Errorf("both stdin and path flags are specified")
+ }
+
+ return formatFromStdin(opts)
+ }
// handle when option specifies a particular file
if targetFile != "" {
@@ -81,6 +93,39 @@ func Run(opts *options.TerragruntOptions) error {
return formatErrors.ErrorOrNil()
}
+func formatFromStdin(opts *options.TerragruntOptions) error {
+ contents, err := io.ReadAll(os.Stdin)
+
+ if err != nil {
+ opts.Logger.Errorf("Error reading from stdin: %s", err)
+ return err
+ }
+
+ err = checkErrors(opts.Logger, opts.DisableLogColors, contents, "stdin")
+ if err != nil {
+ opts.Logger.Errorf("Error parsing hcl from stdin")
+ return err
+ }
+
+ newContents := hclwrite.Format(contents)
+
+ buf := bufio.NewWriter(os.Stdout)
+ _, err = buf.Write(newContents)
+
+ if err != nil {
+ opts.Logger.Errorf("Failed to write to stdout")
+ return err
+ }
+
+ err = buf.Flush()
+ if err != nil {
+ opts.Logger.Errorf("Failed to flush to stdout")
+ return err
+ }
+
+ return nil
+}
+
// formatTgHCL uses the hcl2 library to format the hcl file. This will attempt to parse the HCL file first to
// ensure that there are no syntax errors, before attempting to format it.
func formatTgHCL(opts *options.TerragruntOptions, tgHclFile string) error {
@@ -125,7 +170,7 @@ func formatTgHCL(opts *options.TerragruntOptions, tgHclFile string) error {
}
if opts.Check && fileUpdated {
- return fmt.Errorf("Invalid file format %s", tgHclFile)
+ return fmt.Errorf("invalid file format %s", tgHclFile)
}
if fileUpdated {
diff --git a/cli/commands/hclfmt/action_test.go b/cli/commands/hclfmt/action_test.go
index 2cc085113..6fd58cbb7 100644
--- a/cli/commands/hclfmt/action_test.go
+++ b/cli/commands/hclfmt/action_test.go
@@ -263,6 +263,41 @@ func TestHCLFmtFile(t *testing.T) {
}
}
+func TestHCLFmtStdin(t *testing.T) {
+ t.Parallel()
+
+ realStdin := os.Stdin
+ realStdout := os.Stdout
+
+ tempStdoutFile, err := os.CreateTemp(t.TempDir(), "stdout.hcl")
+ defer func() {
+ _ = tempStdoutFile.Close()
+ }()
+ require.NoError(t, err)
+
+ os.Stdout = tempStdoutFile
+ defer func() { os.Stdout = realStdout }()
+
+ os.Stdin, err = os.Open("../../../test/fixture-hclfmt-stdin/terragrunt.hcl")
+ defer func() { os.Stdin = realStdin }()
+ require.NoError(t, err)
+
+ expected, err := os.ReadFile("../../../test/fixture-hclfmt-stdin/expected.hcl")
+ require.NoError(t, err)
+
+ tgOptions, err := options.NewTerragruntOptionsForTest("")
+ require.NoError(t, err)
+
+ // format hcl from stdin
+ tgOptions.HclFromStdin = true
+ err = hclfmt.Run(tgOptions)
+ require.NoError(t, err)
+
+ formatted, err := os.ReadFile(tempStdoutFile.Name())
+ require.NoError(t, err)
+ assert.Equal(t, expected, formatted)
+}
+
func TestHCLFmtHeredoc(t *testing.T) {
t.Parallel()
diff --git a/cli/commands/hclfmt/command.go b/cli/commands/hclfmt/command.go
index bdda06c81..8585f182b 100644
--- a/cli/commands/hclfmt/command.go
+++ b/cli/commands/hclfmt/command.go
@@ -8,9 +8,10 @@ import (
const (
CommandName = "hclfmt"
- FlagNameTerragruntHCLFmt = "terragrunt-hclfmt-file"
- FlagNameTerragruntCheck = "terragrunt-check"
- FlagNameTerragruntDiff = "terragrunt-diff"
+ FlagNameTerragruntHCLFmt = "terragrunt-hclfmt-file"
+ FlagNameTerragruntCheck = "terragrunt-check"
+ FlagNameTerragruntDiff = "terragrunt-diff"
+ FlagNameTerragruntHCLFmtStdin = "terragrunt-hclfmt-stdin"
)
func NewFlags(opts *options.TerragruntOptions) cli.Flags {
@@ -32,6 +33,12 @@ func NewFlags(opts *options.TerragruntOptions) cli.Flags {
EnvVar: "TERRAGRUNT_DIFF",
Usage: "Print diff between original and modified file versions when running with 'hclfmt'.",
},
+ &cli.BoolFlag{
+ Name: FlagNameTerragruntHCLFmtStdin,
+ Destination: &opts.HclFromStdin,
+ EnvVar: "TERRAGRUNT_HCLFMT_STDIN",
+ Usage: "Format HCL from stdin and print result to stdout.",
+ },
}
}
diff --git a/docs/_docs/04_reference/cli-options.md b/docs/_docs/04_reference/cli-options.md
index 462b71563..7556db615 100644
--- a/docs/_docs/04_reference/cli-options.md
+++ b/docs/_docs/04_reference/cli-options.md
@@ -65,6 +65,7 @@ This page documents the CLI commands and options available with Terragrunt:
- [terragrunt-check](#terragrunt-check)
- [terragrunt-diff](#terragrunt-diff)
- [terragrunt-hclfmt-file](#terragrunt-hclfmt-file)
+ - [terragrunt-hclfmt-stdin](#terragrunt-hclfmt-stdin)
- [terragrunt-hclvalidate-json](#terragrunt-hclvalidate-json)
- [terragrunt-hclvalidate-show-config-path](#terragrunt-hclvalidate-show-config-path)
- [terragrunt-override-attr](#terragrunt-override-attr)
@@ -769,6 +770,7 @@ prefix `--terragrunt-` (e.g., `--terragrunt-config`). The currently available op
- [terragrunt-check](#terragrunt-check)
- [terragrunt-diff](#terragrunt-diff)
- [terragrunt-hclfmt-file](#terragrunt-hclfmt-file)
+ - [terragrunt-hclfmt-stdin](#terragrunt-hclfmt-stdin)
- [terragrunt-hclvalidate-json](#terragrunt-hclvalidate-json)
- [terragrunt-hclvalidate-show-config-path](#terragrunt-hclvalidate-show-config-path)
- [terragrunt-override-attr](#terragrunt-override-attr)
@@ -1149,7 +1151,15 @@ When passed in, running `hclfmt` will print diff between original and modified f
- [hclfmt](#hclfmt)
-When passed in, run `hclfmt` only on specified hcl file.
+### terragrunt-hclfmt-stdin
+
+**CLI Arg**: `--terragrunt-hclfmt-stdin`
+**Environment Variable**: `TERRAGRUNT_HCLFMT_STDIN` (set to `true`)
+**Commands**:
+
+- [hclfmt](#hclfmt)
+
+When passed in, run `hclfmt` only on hcl passed to `stdin`, result is printed to `stdout`.
### terragrunt-hclvalidate-json
diff --git a/options/options.go b/options/options.go
index 439ee5a43..827247988 100644
--- a/options/options.go
+++ b/options/options.go
@@ -235,6 +235,9 @@ type TerragruntOptions struct {
// The file which hclfmt should be specifically run on
HclFile string
+ // If True then HCL from StdIn must should be formatted.
+ HclFromStdin bool
+
// The file path that terragrunt should use when rendering the terragrunt.hcl config as json.
JSONOut string
diff --git a/test/fixture-hclfmt-stdin/expected.hcl b/test/fixture-hclfmt-stdin/expected.hcl
new file mode 100644
index 000000000..a9d035a9e
--- /dev/null
+++ b/test/fixture-hclfmt-stdin/expected.hcl
@@ -0,0 +1,13 @@
+inputs = {
+ # comments
+ foo = "bar"
+ bar = "baz"
+
+ inputs = "disjoint"
+ disjoint = true
+
+ listInput = [
+ "foo",
+ "bar",
+ ]
+}
diff --git a/test/fixture-hclfmt-stdin/terragrunt.hcl b/test/fixture-hclfmt-stdin/terragrunt.hcl
new file mode 100644
index 000000000..e7727b806
--- /dev/null
+++ b/test/fixture-hclfmt-stdin/terragrunt.hcl
@@ -0,0 +1,13 @@
+inputs = {
+# comments
+ foo = "bar"
+ bar="baz"
+
+ inputs = "disjoint"
+ disjoint = true
+
+ listInput = [
+"foo",
+"bar",
+]
+}