diff --git a/cli/args.go b/cli/args.go
index 9e38a92ca7..8baca4df88 100644
--- a/cli/args.go
+++ b/cli/args.go
@@ -95,7 +95,11 @@ func parseTerragruntOptionsFromArgs(terragruntVersion string, args []string, wri
return nil, err
}
- terraformSourceMap, err := parseMutliStringKeyValueArg(args, OPT_TERRAGRUNT_SOURCE_MAP, nil)
+ terraformSourceMapEnvVar, err := parseMultiStringKeyValueEnvVar("TERRAGRUNT_SOURCE_MAP")
+ if err != nil {
+ return nil, err
+ }
+ terraformSourceMap, err := parseMutliStringKeyValueArg(args, OPT_TERRAGRUNT_SOURCE_MAP, terraformSourceMapEnvVar)
if err != nil {
return nil, err
}
@@ -400,25 +404,22 @@ func parseMutliStringKeyValueArg(args []string, argName string, defaultValue map
if err != nil {
return nil, err
}
-
if asList == nil {
return defaultValue, nil
}
+ return util.KeyValuePairStringListToMap(asList)
+}
- asMap := map[string]string{}
- for _, arg := range asList {
- parts := strings.Split(arg, "=")
- if len(parts) != 2 {
- return nil, errors.WithStackTrace(InvalidKeyValue(arg))
- }
-
- key := parts[0]
- value := parts[1]
-
- asMap[key] = value
+// Parses an environment variable that is encoded as a comma separated kv pair (e.g.,
+// `key1=value1,key2=value2,key3=value3`) and converts it to a map. Returns empty map if the environnment variable is
+// not set, and error if the environment variable is not encoded as a comma separated kv pair.
+func parseMultiStringKeyValueEnvVar(envVarName string) (map[string]string, error) {
+ rawEnvVarVal := os.Getenv(envVarName)
+ if rawEnvVarVal == "" {
+ return map[string]string{}, nil
}
-
- return asMap, nil
+ mappingsAsList := strings.Split(rawEnvVarVal, ",")
+ return util.KeyValuePairStringListToMap(mappingsAsList)
}
// Convert the given variables to a map of environment variables that will expose those variables to Terraform. The
@@ -465,9 +466,3 @@ type ArgMissingValue string
func (err ArgMissingValue) Error() string {
return fmt.Sprintf("You must specify a value for the --%s option", string(err))
}
-
-type InvalidKeyValue string
-
-func (err InvalidKeyValue) Error() string {
- return fmt.Sprintf("Invalid key-value pair. Expected format KEY=VALUE, got %s.", string(err))
-}
diff --git a/cli/args_test.go b/cli/args_test.go
index 199bad0150..c6b51dd124 100644
--- a/cli/args_test.go
+++ b/cli/args_test.go
@@ -283,7 +283,7 @@ func TestParseMutliStringKeyValueArg(t *testing.T) {
{[]string{"aws-provider-patch", "--other", "arg"}, "foo", map[string]string{"default": "value"}, map[string]string{"default": "value"}, nil},
{[]string{"aws-provider-patch", "--foo", "key=value"}, "foo", map[string]string{"default": "value"}, map[string]string{"key": "value"}, nil},
{[]string{"aws-provider-patch", "--foo", "key1=value1", "--foo", "key2=value2", "--foo", "key3=value3"}, "foo", map[string]string{"default": "value"}, map[string]string{"key1": "value1", "key2": "value2", "key3": "value3"}, nil},
- {[]string{"aws-provider-patch", "--foo", "invalidvalue"}, "foo", map[string]string{"default": "value"}, nil, InvalidKeyValue("invalidvalue")},
+ {[]string{"aws-provider-patch", "--foo", "invalidvalue"}, "foo", map[string]string{"default": "value"}, nil, util.InvalidKeyValue("invalidvalue")},
}
for _, testCase := range testCases {
diff --git a/docs/_docs/04_reference/cli-options.md b/docs/_docs/04_reference/cli-options.md
index 293942bc8b..2cc26bd9b7 100644
--- a/docs/_docs/04_reference/cli-options.md
+++ b/docs/_docs/04_reference/cli-options.md
@@ -505,6 +505,7 @@ append the path of `source` parameter in each module to the `--terragrunt-source
### terragrunt-source-map
**CLI Arg**: `--terragrunt-source-map`
+**Environment Variable**: `TERRAGRUNT_SOURCE_MAP` (encoded as comma separated value, e.g., `source1=dest1,source2=dest2`)
**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`
diff --git a/test/integration_serial_test.go b/test/integration_serial_test.go
index be25cabc92..50e90a607c 100644
--- a/test/integration_serial_test.go
+++ b/test/integration_serial_test.go
@@ -207,3 +207,24 @@ func TestTerragruntValidateInputsWithUnusedEnvVar(t *testing.T) {
moduleDir := filepath.Join("fixture-validate-inputs", "success-inputs-only")
runTerragruntValidateInputs(t, moduleDir, nil, false)
}
+
+func TestTerragruntSourceMapEnvArg(t *testing.T) {
+ fixtureSourceMapPath := "fixture-source-map"
+ cleanupTerraformFolder(t, fixtureSourceMapPath)
+ tmpEnvPath := copyEnvironment(t, fixtureSourceMapPath)
+ rootPath := filepath.Join(tmpEnvPath, fixtureSourceMapPath)
+
+ os.Setenv(
+ "TERRAGRUNT_SOURCE_MAP",
+ strings.Join(
+ []string{
+ 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),
+ },
+ ",",
+ ),
+ )
+ tgPath := filepath.Join(rootPath, "multiple-match")
+ tgArgs := fmt.Sprintf("terragrunt run-all apply -auto-approve --terragrunt-log-level debug --terragrunt-non-interactive --terragrunt-working-dir %s", tgPath)
+ runTerragrunt(t, tgArgs)
+}
diff --git a/util/collections.go b/util/collections.go
index 6f64a40de0..b811bc588c 100644
--- a/util/collections.go
+++ b/util/collections.go
@@ -4,6 +4,8 @@ import (
"fmt"
"regexp"
"strings"
+
+ "github.com/gruntwork-io/terragrunt/errors"
)
func MatchesAny(regExps []string, s string) bool {
@@ -166,3 +168,29 @@ func StringListInsert(list []string, element string, index int) []string {
tail := append([]string{element}, list[index:]...)
return append(list[:index], tail...)
}
+
+// KeyValuePairListToMap converts a list of key value pair encoded as `key=value` strings into a map.
+func KeyValuePairStringListToMap(asList []string) (map[string]string, error) {
+ asMap := map[string]string{}
+ for _, arg := range asList {
+ parts := strings.Split(arg, "=")
+ if len(parts) != 2 {
+ return nil, errors.WithStackTrace(InvalidKeyValue(arg))
+ }
+
+ key := parts[0]
+ value := parts[1]
+
+ asMap[key] = value
+ }
+
+ return asMap, nil
+}
+
+// custom error types
+
+type InvalidKeyValue string
+
+func (err InvalidKeyValue) Error() string {
+ return fmt.Sprintf("Invalid key-value pair. Expected format KEY=VALUE, got %s.", string(err))
+}
diff --git a/util/collections_test.go b/util/collections_test.go
index 0d2ab83ad7..11bc1e1c0b 100644
--- a/util/collections_test.go
+++ b/util/collections_test.go
@@ -235,3 +235,44 @@ func TestStringListInsert(t *testing.T) {
t.Logf("%v passed", testCase.list)
}
}
+
+func TestKeyValuePairStringListToMap(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ name string
+ input []string
+ output map[string]string
+ }{
+ {
+ "base",
+ []string{"foo=bar", "baz=carol"},
+ map[string]string{
+ "foo": "bar",
+ "baz": "carol",
+ },
+ },
+ {
+ "special_chars",
+ []string{"ssh://git@github.com=/path/to/local"},
+ map[string]string{"ssh://git@github.com": "/path/to/local"},
+ },
+ {
+ "empty",
+ []string{},
+ map[string]string{},
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ actualOutput, err := KeyValuePairStringListToMap(testCase.input)
+ assert.NoError(t, err)
+ assert.Equal(
+ t,
+ testCase.output,
+ actualOutput,
+ )
+ })
+ }
+}