Skip to content

Commit

Permalink
Add handling of empty feature blocks (#3580)
Browse files Browse the repository at this point in the history
* Add handling of empty feature blocks

* partial config cleanup

* Documentation update
  • Loading branch information
denis256 authored Nov 19, 2024
1 parent e8f09ca commit 533bc11
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 5 deletions.
13 changes: 13 additions & 0 deletions config/config_partial.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,19 @@ func DecodeBaseBlocks(ctx *ParsingContext, file *hclparse.File, includeFromChild
if err := file.Decode(&tgFlags, evalParsingContext); err != nil {
return nil, err
}
// validate flags to have default value, collect errors
flagErrs := &errors.MultiError{}

for _, flag := range tgFlags.FeatureFlags {
if flag.Default == nil {
flagErr := fmt.Errorf("feature flag %s does not have a default value in %s", flag.Name, file.ConfigPath)
flagErrs = flagErrs.Append(flagErr)
}
}

if flagErrs.ErrorOrNil() != nil {
return nil, flagErrs
}

flagsAsCtyVal, err := flagsAsCty(ctx, tgFlags.FeatureFlags)
if err != nil {
Expand Down
5 changes: 3 additions & 2 deletions docs/_docs/04_reference/config-blocks-and-attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1173,8 +1173,9 @@ More details in [engine section](https://terragrunt.gruntwork.io/docs/features/e

### feature

The `feature` block is used to configure feature flags in HCL for a particular Terragrunt Unit.
Feature flags can have default values, and they can be set through a CLI flag (`--feature`) or an environment variable (`TERRAGRUNT_FEATURE`).
The `feature` block is used to configure feature flags in HCL for a specific Terragrunt Unit.
Each feature flag must include a default value; failing to specify a default value will result in an error.
Feature flags can be overridden via a CLI flag (`--feature`) or an environment variable (`TERRAGRUNT_FEATURE`).

```hcl
feature "string_flag" {
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions test/fixtures/feature-flags/error-empty-flag/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
feature "test1" {}

feature "test2" {}

feature "test3" {}
23 changes: 20 additions & 3 deletions test/integration_feature_flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import (
)

const (
testSimpleFlag = "fixtures/feature-flags/simple-flag"
testIncludeFlag = "fixtures/feature-flags/include-flag"
testRunAllFlag = "fixtures/feature-flags/run-all"
testSimpleFlag = "fixtures/feature-flags/simple-flag"
testIncludeFlag = "fixtures/feature-flags/include-flag"
testRunAllFlag = "fixtures/feature-flags/run-all"
testErrorEmptyFlag = "fixtures/feature-flags/error-empty-flag"
)

func TestFeatureFlagDefaults(t *testing.T) {
Expand Down Expand Up @@ -105,6 +106,22 @@ func TestFeatureFlagRunAll(t *testing.T) {
validateOutputs(t, app2)
}

func TestFailOnEmptyFeatureFlag(t *testing.T) {
t.Parallel()

cleanupTerraformFolder(t, testErrorEmptyFlag)
tmpEnvPath := helpers.CopyEnvironment(t, testErrorEmptyFlag)
rootPath := util.JoinPath(tmpEnvPath, testErrorEmptyFlag)

_, _, err := helpers.RunTerragruntCommandWithOutput(t, "terragrunt apply -auto-approve --terragrunt-non-interactive --terragrunt-working-dir "+rootPath)
require.Error(t, err)

message := err.Error()
assert.Contains(t, message, "feature flag test1 does not have a default value")
assert.Contains(t, message, "feature flag test2 does not have a default value")
assert.Contains(t, message, "feature flag test3 does not have a default value")
}

func expectedDefaults() map[string]interface{} {
return map[string]interface{}{
"string_feature_flag": "test",
Expand Down

0 comments on commit 533bc11

Please sign in to comment.