Repository: terraform-docs/terraform-docs
Pull request #749 (2024-01-26 15:47:55)

Fix output values with null
## Steps to reproduce
1.  Create an empty dir with terraform file `example.tf`

```hcl
output "foo" {
  value = "foo"
}

output "bar" {
  value = null
}
```
2. Run

```shell
terraform plan
terraform apply
terraform output --json > output.json
```

3. Run
```shell
terraform-docs markdown ./ --output-values --output-values-from ./output.json
```

# Expected
* Successfully generated markdown


# Exists
* Error

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x93e475]

goroutine 1 [running]:
github.com/terraform-docs/terraform-docs/terraform.loadOutputs(0xc000165b80, 0xc000002180)
	/home/runner/work/terraform-docs/terraform-docs/terraform/load.go:298 +0x2d5
github.com/terraform-docs/terraform-docs/terraform.loadModuleItems(0x7ffdd7128646?, 0xc0000022a8?)
	/home/runner/work/terraform-docs/terraform-docs/terraform/load.go:70 +0x106
github.com/terraform-docs/terraform-docs/terraform.LoadWithOptions(0xc000002180)
	/home/runner/work/terraform-docs/terraform-docs/terraform/load.go:41 +0x38
github.com/terraform-docs/terraform-docs/internal/cli.generateContent(0xc000002180)
	/home/runner/work/terraform-docs/terraform-docs/internal/cli/run.go:326 +0x1c
github.com/terraform-docs/terraform-docs/internal/cli.(*Runtime).RunEFunc(0xc00023b540, 0x0?, {0x0?, 0x0?, 0x0?})
	/home/runner/work/terraform-docs/terraform-docs/internal/cli/run.go:134 +0x1e5
github.com/spf13/cobra.(*Command).execute(0xc000005200, {0xc00023b800, 0x4, 0x4})
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:983 +0xabc
github.com/spf13/cobra.(*Command).ExecuteC(0xc000004300)
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1115 +0x3ff
github.com/spf13/cobra.(*Command).Execute(...)
	/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.8.0/command.go:1039
github.com/terraform-docs/terraform-docs/cmd.Execute()
	/home/runner/work/terraform-docs/terraform-docs/cmd/root.go:37 +0x1c
main.main()
	/home/runner/work/terraform-docs/terraform-docs/main.go:20 +0x13
``` 

# Reason
If the output value is `null,`, it would be skipped in `terraform output.`

So `output.json` file will be

```json
{
  "foo": {
    "sensitive": false,
    "type": "string",
    "value": "foo"
  }
}
```

Point in code to fix https://github.com/terraform-docs/terraform-docs/blob/master/terraform/load.go#L298

# Versions

* terraform `v1.2.2`
* terraform docs `v0.17.0 795d369 linux/amd64`

## Reference
 https://github.com/terraform-docs/terraform-docs/issues/748

goruha: @khos2ow may I have a review pls
khos2ow: @goruha thank you for the PR and your patience. Can you please rebase your PR?

Patch:
diff --git a/terraform/load.go b/terraform/load.go
index d6272d6..a8587b4 100644
--- a/terraform/load.go
+++ b/terraform/load.go
@@ -294,11 +294,15 @@ func loadOutputs(tfmodule *tfconfig.Module, config *print.Config) ([]*Output, er
 		}
 
 		if config.OutputValues.Enabled {
-			output.Sensitive = values[output.Name].Sensitive
-			if values[output.Name].Sensitive {
-				output.Value = types.ValueOf(`<sensitive>`)
+			if value, ok := values[output.Name]; ok {
+				output.Sensitive = value.Sensitive
+				output.Value = types.ValueOf(value.Value)
 			} else {
-				output.Value = types.ValueOf(values[output.Name].Value)
+				output.Value = types.ValueOf("null")
+			}
+
+			if output.Sensitive {
+				output.Value = types.ValueOf(`<sensitive>`)
 			}
 		}
 		outputs = append(outputs, output)


Test patch:
diff --git a/format/generator_test.go b/format/generator_test.go
index 38d5bbf..32c9235 100644
--- a/format/generator_test.go
+++ b/format/generator_test.go
@@ -191,7 +191,7 @@ func TestGeneratorFuncModule(t *testing.T) {
 		assert.Equal(expected, generator.module.Header)
 		assert.Equal("", generator.module.Footer)
 		assert.Equal(7, len(generator.module.Inputs))
-		assert.Equal(3, len(generator.module.Outputs))
+		assert.Equal(4, len(generator.module.Outputs))
 	})
 }
 
diff --git a/terraform/load_test.go b/terraform/load_test.go
index 20b79bc..1a5b57c 100644
--- a/terraform/load_test.go
+++ b/terraform/load_test.go
@@ -589,7 +589,7 @@ func TestLoadOutputs(t *testing.T) {
 			name: "load module outputs from path",
 			path: "full-example",
 			expected: expected{
-				outputs: 3,
+				outputs: 4,
 			},
 		},
 		{
@@ -665,7 +665,7 @@ func TestLoadOutputsValues(t *testing.T) {
 			path:       "full-example",
 			outputPath: "output-values.json",
 			expected: expected{
-				outputs: 3,
+				outputs: 4,
 			},
 			wantErr: false,
 		},
@@ -896,7 +896,7 @@ func TestSortItems(t *testing.T) {
 				inputs:    []string{"D", "B", "E", "A", "C", "F", "G"},
 				required:  []string{"A", "F"},
 				optional:  []string{"D", "B", "E", "C", "G"},
-				outputs:   []string{"C", "A", "B"},
+				outputs:   []string{"C", "A", "B", "D"},
 				providers: []string{"tls", "aws", "null"},
 			},
 		},
@@ -909,7 +909,7 @@ func TestSortItems(t *testing.T) {
 				inputs:    []string{"D", "B", "E", "A", "C", "F", "G"},
 				required:  []string{"A", "F"},
 				optional:  []string{"D", "B", "E", "C", "G"},
-				outputs:   []string{"C", "A", "B"},
+				outputs:   []string{"C", "A", "B", "D"},
 				providers: []string{"tls", "aws", "null"},
 			},
 		},
@@ -922,7 +922,7 @@ func TestSortItems(t *testing.T) {
 				inputs:    []string{"D", "B", "E", "A", "C", "F", "G"},
 				required:  []string{"A", "F"},
 				optional:  []string{"D", "B", "E", "C", "G"},
-				outputs:   []string{"C", "A", "B"},
+				outputs:   []string{"C", "A", "B", "D"},
 				providers: []string{"tls", "aws", "null"},
 			},
 		},
@@ -935,7 +935,7 @@ func TestSortItems(t *testing.T) {
 				inputs:    []string{"A", "B", "C", "D", "E", "F", "G"},
 				required:  []string{"A", "F"},
 				optional:  []string{"B", "C", "D", "E", "G"},
-				outputs:   []string{"A", "B", "C"},
+				outputs:   []string{"A", "B", "C", "D"},
 				providers: []string{"aws", "null", "tls"},
 			},
 		},
@@ -948,7 +948,7 @@ func TestSortItems(t *testing.T) {
 				inputs:    []string{"A", "F", "B", "C", "D", "E", "G"},
 				required:  []string{"A", "F"},
 				optional:  []string{"B", "C", "D", "E", "G"},
-				outputs:   []string{"A", "B", "C"},
+				outputs:   []string{"A", "B", "C", "D"},
 				providers: []string{"aws", "null", "tls"},
 			},
 		},
@@ -961,7 +961,7 @@ func TestSortItems(t *testing.T) {
 				inputs:    []string{"A", "F", "G", "B", "C", "D", "E"},
 				required:  []string{"A", "F"},
 				optional:  []string{"G", "B", "C", "D", "E"},
-				outputs:   []string{"A", "B", "C"},
+				outputs:   []string{"A", "B", "C", "D"},
 				providers: []string{"aws", "null", "tls"},
 			},
 		},
diff --git a/terraform/testdata/full-example/outputs.tf b/terraform/testdata/full-example/outputs.tf
index 1024f48..012ffb6 100644
--- a/terraform/testdata/full-example/outputs.tf
+++ b/terraform/testdata/full-example/outputs.tf
@@ -12,3 +12,8 @@ output "A" {
 output "B" {
   value = "b"
 }
+
+// D null result
+output "D" {
+  value = null
+}