Repository: gruntwork-io/terragrunt (language: go)

Issue:
Unable to see CLI options for terragrunt subcommands
If the user ones to find out which options are available for e.g. the `terragrunt render-json` subcommand, there is currently no way to see this in the CLI itself, and they have to go to the docs website to find out. We should make it possible to see the options/flags from the CLI itself.


Discussion / hints:

Fix patch:
diff --git a/cli/aws_provider_patch.go b/cli/aws_provider_patch.go
index c5d536e91e..edb626b944 100644
--- a/cli/aws_provider_patch.go
+++ b/cli/aws_provider_patch.go
@@ -17,6 +17,16 @@ import (
 	"github.com/gruntwork-io/terragrunt/util"
 )
 
+const awsProviderPatchHelp = `
+   Usage: terragrunt aws-provider-patch [OPTIONS]
+
+   Description:
+   Overwrite settings on nested AWS providers to work around a Terraform bug (issue #13018)
+   
+   Options:
+   --terragrunt-override-attr	A key=value attribute to override in a provider block as part of the aws-provider-patch command. May be specified multiple times.
+`
+
 // applyAwsProviderPatch finds all Terraform modules nested in the current code (i.e., in the .terraform/modules
 // folder), looks for provider "aws" { ... } blocks in those modules, and overwrites the attributes in those provider
 // blocks with the attributes specified in terragrntOptions.
diff --git a/cli/cli_app.go b/cli/cli_app.go
index d7221fe56a..de86985057 100644
--- a/cli/cli_app.go
+++ b/cli/cli_app.go
@@ -287,6 +287,13 @@ var TERRAFORM_HELP_FLAGS = []string{
 	"-h",
 }
 
+// map of help functions for each terragrunt command
+var terragruntHelp = map[string]string{
+	CMD_RENDER_JSON:                renderJsonHelp,
+	CMD_AWS_PROVIDER_PATCH:         awsProviderPatchHelp,
+	CMD_TERRAGRUNT_VALIDATE_INPUTS: validateInputsHelp,
+}
+
 // Create the Terragrunt CLI App
 func CreateTerragruntCli(version string, writer io.Writer, errwriter io.Writer) *cli.App {
 	cli.OsExiter = func(exitCode int) {
@@ -364,6 +371,11 @@ func runCommand(command string, terragruntOptions *options.TerragruntOptions) (f
 // Downloads terraform source if necessary, then runs terraform with the given options and CLI args.
 // This will forward all the args and extra_arguments directly to Terraform.
 func RunTerragrunt(terragruntOptions *options.TerragruntOptions) error {
+	if shouldPrintTerragruntHelp(terragruntOptions) {
+		helpMessage, _ := terragruntHelp[terragruntOptions.TerraformCommand]
+		_, err := fmt.Fprintf(terragruntOptions.Writer, "%s\n", helpMessage)
+		return err
+	}
 	if shouldPrintTerraformHelp(terragruntOptions) {
 		return shell.RunTerraformCommand(terragruntOptions, terragruntOptions.TerraformCliArgs...)
 	}
@@ -587,6 +599,21 @@ func shouldPrintTerraformHelp(terragruntOptions *options.TerragruntOptions) bool
 	return false
 }
 
+func shouldPrintTerragruntHelp(terragruntOptions *options.TerragruntOptions) bool {
+	// check if command is in help map
+	_, found := terragruntHelp[terragruntOptions.TerraformCommand]
+	if !found {
+		return false
+	}
+
+	for _, tfHelpFlag := range TERRAFORM_HELP_FLAGS {
+		if util.ListContainsElement(terragruntOptions.TerraformCliArgs, tfHelpFlag) {
+			return true
+		}
+	}
+	return false
+}
+
 func shouldRunGraphDependencies(terragruntOptions *options.TerragruntOptions) bool {
 	return util.ListContainsElement(terragruntOptions.TerraformCliArgs, CMD_TERRAGRUNT_GRAPH_DEPENDENCIES)
 }
diff --git a/cli/render_json.go b/cli/render_json.go
index b2b98631be..a90f63bc38 100644
--- a/cli/render_json.go
+++ b/cli/render_json.go
@@ -17,6 +17,17 @@ import (
 
 const defaultJSONOutName = "terragrunt_rendered.json"
 
+const renderJsonHelp = `
+   Usage: terragrunt render-json [OPTIONS]
+
+   Description:
+   Render the final terragrunt config, with all variables, includes, and functions resolved, as json.
+   
+   Options:
+   --with-metadata 		Add metadata to the rendered JSON file.
+   --terragrunt-json-out 	The file path that terragrunt should use when rendering the terragrunt.hcl config as json.
+`
+
 // runRenderJSON takes the parsed TerragruntConfig struct and renders it out as JSON so that it can be processed by
 // other tools. To make it easier to maintain, this uses the cty representation as an intermediary.
 // NOTE: An unspecified advantage of using the cty representation is that the final block outputs would be a map
diff --git a/cli/validate_inputs.go b/cli/validate_inputs.go
index 2a8ba263d6..49ed27d106 100644
--- a/cli/validate_inputs.go
+++ b/cli/validate_inputs.go
@@ -14,6 +14,16 @@ import (
 	"github.com/gruntwork-io/terragrunt/util"
 )
 
+const validateInputsHelp = `
+   Usage: terragrunt validate-inputs [OPTIONS]
+
+   Description:
+   Checks if the terragrunt configured inputs align with the terraform defined variables.
+   
+   Options:
+   --terragrunt-strict-validate		Enable strict mode for validation. When strict mode is turned on, an error will be returned if required inputs are missing OR if unused variables are passed to Terragrunt.
+`
+
 // validateTerragruntInputs will collect all the terraform variables defined in the target module, and the terragrunt
 // inputs that are configured, and compare the two to determine if there are any unused inputs or undefined required
 // inputs.


Test patch:
diff --git a/test/integration_test.go b/test/integration_test.go
index 9df3b70f5f..495be2c223 100644
--- a/test/integration_test.go
+++ b/test/integration_test.go
@@ -5000,3 +5000,24 @@ func TestRenderJsonMetadataTerraform(t *testing.T) {
 
 	assert.Equal(t, string(serializedExpectedRemoteState), string(serializedRemoteState))
 }
+
+func TestTerragruntRenderJsonHelp(t *testing.T) {
+	t.Parallel()
+
+	cleanupTerraformFolder(t, TEST_FIXTURE_HOOKS_INIT_ONCE_WITH_SOURCE_NO_BACKEND)
+	tmpEnvPath := copyEnvironment(t, "fixture-hooks/init-once")
+	rootPath := util.JoinPath(tmpEnvPath, TEST_FIXTURE_HOOKS_INIT_ONCE_WITH_SOURCE_NO_BACKEND)
+
+	showStdout := bytes.Buffer{}
+	showStderr := bytes.Buffer{}
+
+	err := runTerragruntCommand(t, fmt.Sprintf("terragrunt render-json --help --terragrunt-non-interactive --terragrunt-working-dir %s", rootPath), &showStdout, &showStderr)
+	assert.Nil(t, err)
+
+	logBufferContentsLineByLine(t, showStdout, "show stdout")
+
+	output := showStdout.String()
+
+	assert.Contains(t, output, "Usage: terragrunt render-json [OPTIONS]")
+	assert.Contains(t, output, "--with-metadata")
+}