Repository: gruntwork-io/terragrunt

Issue:
Run Terraforms "graph" command via cli-redesign experiments "run" not working
## Describe the bug

I recently came accross an old script stored in a repo whose responsibility I took over which was meant to be used for improve the repo's overall documentation automatically. This script was executing the command 

`terragrunt graph -draw-cycles "${INPUT_DIR}" | dot ... #Convert output to GraphViz and write to SVG file`

It took me a while to understand, that this command was failing with error "-draw-cycles is not a valid option" because that after I upgraded to a newer Terragrunt version (v0.72.2) a few weeks ago, the command was not forwarded to Terraform anymore but instead was resolved by Terragrunt as in a previous release the "graph" command was introduced as well (unfortunately with an entirely different functionality)

But I came accross the quite new and currently active "cli-redesign" experiment and thought "well, that might be exactly what I need to make the script work again as before", so I upgraded to (v0.73.15) and tried to execute the previous mentioned command as follows now:

`terragrunt --experiment cli-redesign run -- graph -draw-cycles "${INPUT_DIR}" | dot ...`

Unfortunately no success, as now I am receiving the following Error Message:

```
ERROR  Terraform has no command named "". To see all of Terraform's top-level commands, run: terraform -help
ERROR  Unable to determine underlying exit code, so Terragrunt will exit with error code 1
```

When trying to use the new "run" command with e.g. "plan" everything works as expected, but looking at the error message I got the feeling, that for some reason Terragrunt seems to not forward the "graph" command to Terraform at all and just swallows it along the way, because in the error message it is looking like I did not provide a Terraform command at all. But when providing an actual invalid-command as a cross-check, that is showing up to be unknown in the error message (as expected):

```
terragrunt --experiment cli-redesign run -- invalid-command
Terraform has no command named "invalid-command". To see all of Terraform's top-level commands, run: terraform -help
Unable to determine underlying exit code, so Terragrunt will exit with error code 1
```

So there seems to be some special (miss)handling in the current experiment when passing either the graph command or maybe even when overall passing commands, which have an equal name in the Terragrunt CLI

## Steps To Reproduce

Just run `terragrunt --experiment cli-redesign run -- graph` against an arbitrary terragrunt.hcl file

## Expected behavior

No matter the command passed over to "run" (esspecially after already seperating it with -- from the terragrunt command flags), it should be forwarded to Terraform as documented

## Versions

- Terragrunt version: v0.73.15
- OpenTofu/Terraform version: Terraform v1.5.7 on linux_amd64
- Environment details (Ubuntu 20.04, Windows 10, etc.): Running in Docker container based on Ubuntu 20.04 image


Hints from issue comments:
@gangstead: I had to update terragrunt from `0.77.22` to `0.80.4` and the command that worked for me was:

```
terragrunt run -- graph -draw-cycles -type=plan | dot -Tsvg > my-plan.svg
```

Note the space between `--` and `graph`.  The [release notes](https://github.com/gruntwork-io/terragrunt/releases/tag/v0.78.0) say `run --graph`@yhakbar: @gangstead ,

I understand the confusion here. The command `terragrunt run -- graph` tells Terragrunt to run the OpenTofu/Terraform command `graph`, whereas the now deprecated Terragrunt command `graph`, which is similar to `run-all`, as been moved to a flag `--graph` for the `terragrunt run` command, along with the `--run` flag replacing `run-all`.

Hopefully that wasn't more confusing. The fact that we originally had a command called `graph` is the cause of this ambiguity, and this kind of confusion is why we added the ability to use `--` to separate Terragrunt flags and arguments from OpenTofu/Terraform flags/arguments.

Solution patch:
diff --git a/cli/app.go b/cli/app.go
index 1bd2bf22..fcc502f7 100644
--- a/cli/app.go
+++ b/cli/app.go
@@ -37,6 +37,10 @@ import (
 	"github.com/gruntwork-io/terragrunt/pkg/log/format/placeholders"
 )
 
+const (
+	AppName = "terragrunt"
+)
+
 func init() {
 	cli.AppVersionTemplate = AppVersionTemplate
 	cli.AppHelpTemplate = AppHelpTemplate
@@ -53,7 +57,7 @@ func NewApp(opts *options.TerragruntOptions) *App {
 	terragruntCommands := commands.New(opts)
 
 	app := cli.NewApp()
-	app.Name = "terragrunt"
+	app.Name = AppName
 	app.Usage = "Terragrunt is a flexible orchestration tool that allows Infrastructure as Code written in OpenTofu/Terraform to scale.\nFor documentation, see https://terragrunt.gruntwork.io/."
 	app.Author = "Gruntwork <www.gruntwork.io>"
 	app.Version = version.GetVersion()
@@ -241,8 +245,12 @@ func initialSetup(cliCtx *cli.Context, opts *options.TerragruntOptions) error {
 	args := cliCtx.Args().WithoutBuiltinCmdSep().Normalize(cli.SingleDashFlag)
 	cmdName := cliCtx.Command.Name
 
-	switch cmdName {
-	case runCmd.CommandName, runall.CommandName, graph.CommandName:
+	switch {
+	case cmdName == runCmd.CommandName:
+		fallthrough
+	case cmdName == runall.CommandName:
+		fallthrough
+	case cmdName == graph.CommandName && cliCtx.Parent().Command.IsRoot:
 		cmdName = args.CommandName()
 	default:
 		args = append([]string{cmdName}, args...)



Test patch:
diff --git a/test/integration_test.go b/test/integration_test.go
index 532c29f4..5010ccca 100644
--- a/test/integration_test.go
+++ b/test/integration_test.go
@@ -1098,6 +1098,11 @@ func TestTerraformCommandCliArgs(t *testing.T) {
 			wrappedBinary() + " version",
 			nil,
 		},
+		{
+			[]string{"--", "graph"},
+			"digraph",
+			nil,
+		},
 		{
 			[]string{"--", "paln"}, //codespell:ignore
 			"",
@@ -1125,7 +1130,7 @@ func TestTerraformCommandCliArgs(t *testing.T) {
 
 		output := stdout.String()
 		errOutput := stderr.String()
-		assert.True(t, strings.Contains(errOutput, testCase.expected) || strings.Contains(output, testCase.expected))
+		assert.Contains(t, output+errOutput, testCase.expected)
 	}
 }