diff --git a/cli/args.go b/cli/args.go index 54ccb3a214..9e38a92ca7 100644 --- a/cli/args.go +++ b/cli/args.go @@ -95,6 +95,11 @@ func parseTerragruntOptionsFromArgs(terragruntVersion string, args []string, wri return nil, err } + terraformSourceMap, err := parseMutliStringKeyValueArg(args, OPT_TERRAGRUNT_SOURCE_MAP, nil) + if err != nil { + return nil, err + } + sourceUpdate := parseBooleanArg(args, OPT_TERRAGRUNT_SOURCE_UPDATE, os.Getenv("TERRAGRUNT_SOURCE_UPDATE") == "true" || os.Getenv("TERRAGRUNT_SOURCE_UPDATE") == "1") ignoreDependencyErrors := parseBooleanArg(args, OPT_TERRAGRUNT_IGNORE_DEPENDENCY_ERRORS, false) @@ -166,6 +171,7 @@ func parseTerragruntOptionsFromArgs(terragruntVersion string, args []string, wri opts.Logger.Logger.SetOutput(errWriter) opts.RunTerragrunt = RunTerragrunt opts.Source = terraformSource + opts.SourceMap = terraformSourceMap opts.SourceUpdate = sourceUpdate opts.TerragruntVersion, err = version.NewVersion(terragruntVersion) if err != nil { diff --git a/cli/cli_app.go b/cli/cli_app.go index 96b4685148..c06901ec6f 100644 --- a/cli/cli_app.go +++ b/cli/cli_app.go @@ -32,6 +32,7 @@ const OPT_NON_INTERACTIVE = "terragrunt-non-interactive" const OPT_WORKING_DIR = "terragrunt-working-dir" const OPT_DOWNLOAD_DIR = "terragrunt-download-dir" const OPT_TERRAGRUNT_SOURCE = "terragrunt-source" +const OPT_TERRAGRUNT_SOURCE_MAP = "terragrunt-source-map" const OPT_TERRAGRUNT_SOURCE_UPDATE = "terragrunt-source-update" const OPT_TERRAGRUNT_IAM_ROLE = "terragrunt-iam-role" const OPT_TERRAGRUNT_IGNORE_DEPENDENCY_ERRORS = "terragrunt-ignore-dependency-errors" @@ -67,6 +68,7 @@ var ALL_TERRAGRUNT_STRING_OPTS = []string{ OPT_WORKING_DIR, OPT_DOWNLOAD_DIR, OPT_TERRAGRUNT_SOURCE, + OPT_TERRAGRUNT_SOURCE_MAP, OPT_TERRAGRUNT_IAM_ROLE, OPT_TERRAGRUNT_EXCLUDE_DIR, OPT_TERRAGRUNT_INCLUDE_DIR, @@ -406,7 +408,11 @@ func RunTerragrunt(terragruntOptions *options.TerragruntOptions) error { } updatedTerragruntOptions := terragruntOptions - if sourceUrl := config.GetTerraformSourceUrl(terragruntOptions, terragruntConfig); sourceUrl != "" { + sourceUrl, err := config.GetTerraformSourceUrl(terragruntOptions, terragruntConfig) + if err != nil { + return err + } + if sourceUrl != "" { updatedTerragruntOptions, err = downloadTerraformSource(sourceUrl, terragruntOptions, terragruntConfig) if err != nil { return err diff --git a/config/config.go b/config/config.go index 31f1f4a9ed..4bf34414d9 100644 --- a/config/config.go +++ b/config/config.go @@ -2,14 +2,16 @@ package config import ( "fmt" - "github.com/mitchellh/mapstructure" + "net/url" "os" "path/filepath" "reflect" "strings" + "github.com/hashicorp/go-getter" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclparse" + "github.com/mitchellh/mapstructure" "github.com/sirupsen/logrus" "github.com/zclconf/go-cty/cty" @@ -317,14 +319,79 @@ func (conf *TerraformExtraArguments) GetVarFiles(logger *logrus.Entry) []string // There are two ways a user can tell Terragrunt that it needs to download Terraform configurations from a specific // URL: via a command-line option or via an entry in the Terragrunt configuration. If the user used one of these, this // method returns the source URL or an empty string if there is no source url -func GetTerraformSourceUrl(terragruntOptions *options.TerragruntOptions, terragruntConfig *TerragruntConfig) string { +func GetTerraformSourceUrl(terragruntOptions *options.TerragruntOptions, terragruntConfig *TerragruntConfig) (string, error) { if terragruntOptions.Source != "" { - return terragruntOptions.Source + return terragruntOptions.Source, nil } else if terragruntConfig.Terraform != nil && terragruntConfig.Terraform.Source != nil { - return *terragruntConfig.Terraform.Source + return adjustSourceWithMap(terragruntOptions.SourceMap, *terragruntConfig.Terraform.Source, terragruntOptions.OriginalTerragruntConfigPath) } else { - return "" + return "", nil + } +} + +// adjustSourceWithMap implements the --terragrunt-source-map feature. This function will check if the URL portion of a +// terraform source matches any entry in the provided source map and if it does, replace it with the configured source +// in the map. Note that this only performs literal matches with the URL portion. +// +// Example: +// Suppose terragrunt is called with: +// +// --terragrunt-source-map git::ssh://git@github.com/gruntwork-io/i-dont-exist.git=/path/to/local-modules +// +// and the terraform source is: +// +// git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/app?ref=master +// +// This function will take that source and transform it to: +// +// /path/to/local-modules/fixture-source-map/modules/app +// +func adjustSourceWithMap(sourceMap map[string]string, source string, modulePath string) (string, error) { + // Skip logic if source map is not configured + if len(sourceMap) == 0 { + return source, nil } + + // use go-getter to split the module source string into a valid URL and subdirectory (if // is present) + moduleUrl, moduleSubdir := getter.SourceDirSubdir(source) + + // if both URL and subdir are missing, something went terribly wrong + if moduleUrl == "" && moduleSubdir == "" { + return "", errors.WithStackTrace(InvalidSourceUrlWithMap{ModulePath: modulePath, ModuleSourceUrl: source}) + } + + // If module URL is missing, return the source as is as it will not match anything in the map. + if moduleUrl == "" { + return source, nil + } + + // Before looking up in sourceMap, make sure to drop any query parameters. + moduleUrlParsed, err := url.Parse(moduleUrl) + if err != nil { + return source, err + } + moduleUrlParsed.RawQuery = "" + moduleUrlQuery := moduleUrlParsed.String() + + // Check if there is an entry to replace the URL portion in the map. Return the source as is if there is no entry in + // the map. + sourcePath, hasKey := sourceMap[moduleUrlQuery] + if hasKey == false { + return source, nil + } + + // Since there is a source mapping, replace the module URL portion with the entry in the map, and join with the + // subdir. + // If subdir is missing, check if we can obtain a valid module name from the URL portion. + if moduleSubdir == "" { + moduleSubdirFromUrl, err := getModulePathFromSourceUrl(moduleUrl) + if err != nil { + return moduleSubdirFromUrl, err + } + moduleSubdir = moduleSubdirFromUrl + } + return util.JoinTerraformModulePath(sourcePath, moduleSubdir), nil + } // Return the default hcl path to use for the Terragrunt configuration file in the given directory diff --git a/config/config_helpers.go b/config/config_helpers.go index 323e4888fc..1f554be21a 100644 --- a/config/config_helpers.go +++ b/config/config_helpers.go @@ -657,6 +657,15 @@ func (err InvalidSourceUrl) Error() string { return fmt.Sprintf("The --terragrunt-source parameter is set to '%s', but the source URL in the module at '%s' is invalid: '%s'. Note that the module URL must have a double-slash to separate the repo URL from the path within the repo!", err.TerragruntSource, err.ModulePath, err.ModuleSourceUrl) } +type InvalidSourceUrlWithMap struct { + ModulePath string + ModuleSourceUrl string +} + +func (err InvalidSourceUrlWithMap) Error() string { + return fmt.Sprintf("The --terragrunt-source-map parameter was passed in, but the source URL in the module at '%s' is invalid: '%s'. Note that the module URL must have a double-slash to separate the repo URL from the path within the repo!", err.ModulePath, err.ModuleSourceUrl) +} + type ErrorParsingModulePath struct { ModuleSourceUrl string } diff --git a/config/dependency.go b/config/dependency.go index e252f15034..efa82117d8 100644 --- a/config/dependency.go +++ b/config/dependency.go @@ -452,7 +452,10 @@ func terragruntAlreadyInit(terragruntOptions *options.TerragruntOptions, configP return false, "", err } var workingDir string - sourceUrl := GetTerraformSourceUrl(terragruntOptions, terraformBlockTGConfig) + sourceUrl, err := GetTerraformSourceUrl(terragruntOptions, terraformBlockTGConfig) + if err != nil { + return false, "", err + } if sourceUrl == "" || sourceUrl == "." { // When there is no source URL, there is no download process and the working dir is the same as the directory // where the config is. diff --git a/docs/_docs/04_reference/cli-options.md b/docs/_docs/04_reference/cli-options.md index e28656ffdf..293942bc8b 100644 --- a/docs/_docs/04_reference/cli-options.md +++ b/docs/_docs/04_reference/cli-options.md @@ -389,6 +389,7 @@ prefix `--terragrunt-` (e.g., `--terragrunt-config`). The currently available op - [terragrunt-working-dir](#terragrunt-working-dir) - [terragrunt-download-dir](#terragrunt-download-dir) - [terragrunt-source](#terragrunt-source) +- [terragrunt-source-map](#terragrunt-source-map) - [terragrunt-source-update](#terragrunt-source-update) - [terragrunt-ignore-dependency-errors](#terragrunt-ignore-dependency-errors) - [terragrunt-iam-role](#terragrunt-iam-role) @@ -501,6 +502,35 @@ for all of your Terraform modules, and for each module processed by the `xxx-all append the path of `source` parameter in each module to the `--terragrunt-source` parameter you passed in. +### terragrunt-source-map + +**CLI Arg**: `--terragrunt-source-map`
+**Requires an argument**: `--terragrunt-source-map git::ssh://github.com=/path/to/local-terraform-code` + +Can be supplied multiple times: `--terragrunt-source-map source1=dest1 --terragrunt-source-map source2=dest2` + +The `--terragrunt-source-map source=dest` param replaces any `source` URL (including the source URL of a config pulled +in with `dependency` blocks) that has root `source` with `dest`. + +For example: + +``` +terragrunt apply --terragrunt-source-map github.com/org/modules.git:/local/path/to/modules +``` + +The above would replace `terraform { source = "github.com/org/modules.git//xxx" }` with `terraform { source = /local/path/to/modules//xxx }` regardless of +whether you were running `apply`, or `run-all`, or using a `dependency`. + +**NOTE**: This setting is ignored if you pass in `--terragrunt-source`. + +Note that this only performs literal matches on the URL portion. For example, a map key of +`ssh://git@github.com/gruntwork-io/terragrunt.git` will only match terragrunt configurations with source `source = +"ssh://git@github.com/gruntwork-io/terragrunt.git//xxx"` and not sources of the form `source = +"git::ssh://git@github.com/gruntwork-io/terragrunt.git//xxx"`. The latter requires a map key of +`git::ssh://git@github.com/gruntwork-io/terragrunt.git`. + + + ### terragrunt-source-update **CLI Arg**: `--terragrunt-source-update`
diff --git a/options/options.go b/options/options.go index da471ab93b..b3153ebcbf 100644 --- a/options/options.go +++ b/options/options.go @@ -91,6 +91,10 @@ type TerragruntOptions struct { // Terraform in that temporary folder Source string + // Map to replace terraform source locations. This will replace occurences of the given source with the target + // value. + SourceMap map[string]string + // If set to true, delete the contents of the temporary folder before downloading Terraform source code into it SourceUpdate bool @@ -190,6 +194,7 @@ func NewTerragruntOptions(terragruntConfigPath string) (*TerragruntOptions, erro LogLevel: DEFAULT_LOG_LEVEL, Env: map[string]string{}, Source: "", + SourceMap: map[string]string{}, SourceUpdate: false, DownloadDir: downloadDir, IgnoreDependencyErrors: false, @@ -265,6 +270,7 @@ func (terragruntOptions *TerragruntOptions) Clone(terragruntConfigPath string) * LogLevel: terragruntOptions.LogLevel, Env: util.CloneStringMap(terragruntOptions.Env), Source: terragruntOptions.Source, + SourceMap: terragruntOptions.SourceMap, SourceUpdate: terragruntOptions.SourceUpdate, DownloadDir: terragruntOptions.DownloadDir, Debug: terragruntOptions.Debug, diff --git a/test/fixture-source-map/modules/app/main.tf b/test/fixture-source-map/modules/app/main.tf new file mode 100644 index 0000000000..a4f5a57027 --- /dev/null +++ b/test/fixture-source-map/modules/app/main.tf @@ -0,0 +1,7 @@ +variable "name" {} + +variable "vpc_id" {} + +output "app_url" { + value = "https://${var.name}.${var.vpc_id}.foo.io" +} diff --git a/test/fixture-source-map/modules/vpc/main.tf b/test/fixture-source-map/modules/vpc/main.tf new file mode 100644 index 0000000000..6ee69450e5 --- /dev/null +++ b/test/fixture-source-map/modules/vpc/main.tf @@ -0,0 +1,5 @@ +variable "name" {} + +output "vpc_id" { + value = "vpc-${var.name}-asdf1234" +} diff --git a/test/fixture-source-map/multiple-match/terragrunt-vpc/terragrunt.hcl b/test/fixture-source-map/multiple-match/terragrunt-vpc/terragrunt.hcl new file mode 100644 index 0000000000..78171048d5 --- /dev/null +++ b/test/fixture-source-map/multiple-match/terragrunt-vpc/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/another-dont-exist.git//fixture-source-map/modules/vpc?ref=master" +} + +inputs = { + name = "terragrunt" +} diff --git a/test/fixture-source-map/multiple-match/terratest-vpc/terragrunt.hcl b/test/fixture-source-map/multiple-match/terratest-vpc/terragrunt.hcl new file mode 100644 index 0000000000..de2acedaf7 --- /dev/null +++ b/test/fixture-source-map/multiple-match/terratest-vpc/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/vpc?ref=master" +} + +inputs = { + name = "terratest" +} diff --git a/test/fixture-source-map/multiple-only-one-match/terragrunt-vpc/terragrunt.hcl b/test/fixture-source-map/multiple-only-one-match/terragrunt-vpc/terragrunt.hcl new file mode 100644 index 0000000000..bdaab54e23 --- /dev/null +++ b/test/fixture-source-map/multiple-only-one-match/terragrunt-vpc/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "../../modules/vpc" +} + +inputs = { + name = "terragrunt" +} diff --git a/test/fixture-source-map/multiple-only-one-match/terratest-vpc/terragrunt.hcl b/test/fixture-source-map/multiple-only-one-match/terratest-vpc/terragrunt.hcl new file mode 100644 index 0000000000..de2acedaf7 --- /dev/null +++ b/test/fixture-source-map/multiple-only-one-match/terratest-vpc/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/vpc?ref=master" +} + +inputs = { + name = "terratest" +} diff --git a/test/fixture-source-map/multiple-with-dependency-same-url/app/terragrunt.hcl b/test/fixture-source-map/multiple-with-dependency-same-url/app/terragrunt.hcl new file mode 100644 index 0000000000..896d24b430 --- /dev/null +++ b/test/fixture-source-map/multiple-with-dependency-same-url/app/terragrunt.hcl @@ -0,0 +1,12 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/app?ref=master" +} + +dependency "vpc" { + config_path = "../vpc" +} + +inputs = { + name = "terragrunt" + vpc_id = dependency.vpc.outputs.vpc_id +} diff --git a/test/fixture-source-map/multiple-with-dependency-same-url/vpc/terragrunt.hcl b/test/fixture-source-map/multiple-with-dependency-same-url/vpc/terragrunt.hcl new file mode 100644 index 0000000000..8c9c5d9e0c --- /dev/null +++ b/test/fixture-source-map/multiple-with-dependency-same-url/vpc/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/vpc?ref=master" +} + +inputs = { + name = "terragrunt" +} diff --git a/test/fixture-source-map/multiple-with-dependency/app/terragrunt.hcl b/test/fixture-source-map/multiple-with-dependency/app/terragrunt.hcl new file mode 100644 index 0000000000..de8a689074 --- /dev/null +++ b/test/fixture-source-map/multiple-with-dependency/app/terragrunt.hcl @@ -0,0 +1,12 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/another-dont-exist.git//fixture-source-map/modules/app?ref=master" +} + +dependency "vpc" { + config_path = "../vpc" +} + +inputs = { + name = "terragrunt" + vpc_id = dependency.vpc.outputs.vpc_id +} diff --git a/test/fixture-source-map/multiple-with-dependency/vpc/terragrunt.hcl b/test/fixture-source-map/multiple-with-dependency/vpc/terragrunt.hcl new file mode 100644 index 0000000000..8c9c5d9e0c --- /dev/null +++ b/test/fixture-source-map/multiple-with-dependency/vpc/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/vpc?ref=master" +} + +inputs = { + name = "terragrunt" +} diff --git a/test/fixture-source-map/single/terragrunt.hcl b/test/fixture-source-map/single/terragrunt.hcl new file mode 100644 index 0000000000..8c9c5d9e0c --- /dev/null +++ b/test/fixture-source-map/single/terragrunt.hcl @@ -0,0 +1,7 @@ +terraform { + source = "git::ssh://git@github.com/gruntwork-io/i-dont-exist.git//fixture-source-map/modules/vpc?ref=master" +} + +inputs = { + name = "terragrunt" +} diff --git a/test/integration_local_dev_test.go b/test/integration_local_dev_test.go new file mode 100644 index 0000000000..66a8909dd7 --- /dev/null +++ b/test/integration_local_dev_test.go @@ -0,0 +1,120 @@ +package test + +import ( + "bytes" + "encoding/json" + "fmt" + "path/filepath" + "testing" + + "github.com/gruntwork-io/terragrunt/util" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTerragruntSourceMap(t *testing.T) { + t.Parallel() + + fixtureSourceMapPath := "fixture-source-map" + cleanupTerraformFolder(t, fixtureSourceMapPath) + tmpEnvPath := copyEnvironment(t, fixtureSourceMapPath) + rootPath := filepath.Join(tmpEnvPath, fixtureSourceMapPath) + sourceMapArgs := fmt.Sprintf( + "--terragrunt-source-map %s --terragrunt-source-map %s", + fmt.Sprintf("git::ssh://git@github.com/gruntwork-io/i-dont-exist.git=%s", tmpEnvPath), + fmt.Sprintf("git::ssh://git@github.com/gruntwork-io/another-dont-exist.git=%s", tmpEnvPath), + ) + + testCases := []struct { + name string + applyAll bool + }{ + { + name: "multiple-match", + applyAll: true, + }, + { + name: "multiple-only-one-match", + applyAll: true, + }, + { + name: "multiple-with-dependency", + applyAll: true, + }, + { + name: "multiple-with-dependency-same-url", + applyAll: true, + }, + { + name: "single", + applyAll: false, + }, + } + + for _, testCase := range testCases { + // capture range variable to avoid it changing across for loop runs during goroutine transitions. + testCase := testCase + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + tgPath := filepath.Join(rootPath, testCase.name) + + action := "apply" + if testCase.applyAll { + action = "run-all apply" + } + + tgArgs := fmt.Sprintf("terragrunt %s -auto-approve --terragrunt-log-level debug --terragrunt-non-interactive --terragrunt-working-dir %s %s", action, tgPath, sourceMapArgs) + runTerragrunt(t, tgArgs) + }) + } +} + +func TestGetTerragruntSourceHCL(t *testing.T) { + t.Parallel() + + cleanupTerraformFolder(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_HCL) + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_HCL) + rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_HCL) + terraformSource := "" // get_terragrunt_source_cli_flag() only returns the source when it is passed in via the CLI + + runTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath)) + + // verify expected outputs are not empty + stdout := bytes.Buffer{} + stderr := bytes.Buffer{} + + require.NoError( + t, + runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr), + ) + + outputs := map[string]TerraformOutput{} + + require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) + assert.Equal(t, fmt.Sprintf("HCL: %s", terraformSource), outputs["terragrunt_source"].Value) +} + +func TestGetTerragruntSourceCLI(t *testing.T) { + t.Parallel() + + cleanupTerraformFolder(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_CLI) + tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_CLI) + rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_CLI) + terraformSource := "terraform_config_cli" + + runTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-source %s", rootPath, terraformSource)) + + // verify expected outputs are not empty + stdout := bytes.Buffer{} + stderr := bytes.Buffer{} + + require.NoError( + t, + runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-source %s", rootPath, terraformSource), &stdout, &stderr), + ) + + outputs := map[string]TerraformOutput{} + + require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) + assert.Equal(t, fmt.Sprintf("CLI: %s", terraformSource), outputs["terragrunt_source"].Value) +} diff --git a/test/integration_test.go b/test/integration_test.go index 938aa0e4f3..d5e61085f3 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -2767,56 +2767,6 @@ func TestAWSGetCallerIdentityFunctions(t *testing.T) { assert.Equal(t, outputs["user_id"].Value, *identity.UserId) } -func TestGetTerragruntSourceHCL(t *testing.T) { - t.Parallel() - - cleanupTerraformFolder(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_HCL) - tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_HCL) - rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_HCL) - terraformSource := "" // get_terragrunt_source_cli_flag() only returns the source when it is passed in via the CLI - - runTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath)) - - // verify expected outputs are not empty - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - require.NoError( - t, - runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &stdout, &stderr), - ) - - outputs := map[string]TerraformOutput{} - - require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) - assert.Equal(t, fmt.Sprintf("HCL: %s", terraformSource), outputs["terragrunt_source"].Value) -} - -func TestGetTerragruntSourceCLI(t *testing.T) { - t.Parallel() - - cleanupTerraformFolder(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_CLI) - tmpEnvPath := copyEnvironment(t, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_CLI) - rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_GET_TERRAGRUNT_SOURCE_CLI) - terraformSource := "terraform_config_cli" - - runTerragrunt(t, fmt.Sprintf("terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-source %s", rootPath, terraformSource)) - - // verify expected outputs are not empty - stdout := bytes.Buffer{} - stderr := bytes.Buffer{} - - require.NoError( - t, - runTerragruntCommand(t, fmt.Sprintf("terragrunt output -no-color -json --terragrunt-non-interactive --terragrunt-working-dir %s --terragrunt-source %s", rootPath, terraformSource), &stdout, &stderr), - ) - - outputs := map[string]TerraformOutput{} - - require.NoError(t, json.Unmarshal([]byte(stdout.String()), &outputs)) - assert.Equal(t, fmt.Sprintf("CLI: %s", terraformSource), outputs["terragrunt_source"].Value) -} - func TestGetPlatform(t *testing.T) { t.Parallel()