Skip to content

Commit b80e08e

Browse files
authored
Merge pull request #403 from dflook/json-outpputs
Add json_output_path
2 parents 403978d + 4d97209 commit b80e08e

File tree

21 files changed

+412
-3
lines changed

21 files changed

+412
-3
lines changed

.github/workflows/test-output.yaml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
MY_OBJECT_FIRST: ${{ fromJson(steps.terraform-output.outputs.my_object).first }}
4242
MY_TUPLE: ${{ join(fromJson(steps.terraform-output.outputs.my_tuple)) }}
4343
MY_SET: ${{ contains(fromJson(steps.terraform-output.outputs.my_set), 'one') }}
44+
JSON_OUTPUT_PATH: ${{ steps.terraform-output.outputs.json_output_path }}
4445
run: |
4546
if [[ "$MY_NUMBER" != "5" ]]; then
4647
echo "::error:: output my_number not set correctly"
@@ -114,3 +115,56 @@ jobs:
114115
echo "::error:: steps.terraform-output.outputs.my_multiline_string not set correctly"
115116
exit 1
116117
fi
118+
119+
## Check if the JSON output file exists and validate its contents
120+
121+
cat "$JSON_OUTPUT_PATH"
122+
123+
if [[ ! -f "$JSON_OUTPUT_PATH" ]]; then
124+
echo "::error:: JSON output file not found at $JSON_OUTPUT_PATH"
125+
exit 1
126+
fi
127+
128+
# Parse JSON and validate primitive types
129+
JSON_MY_NUMBER=$(jq -r '.my_number' "$JSON_OUTPUT_PATH")
130+
if [[ "$JSON_MY_NUMBER" != "5" ]]; then
131+
echo "::error:: JSON my_number should be 5, got: $JSON_MY_NUMBER"
132+
exit 1
133+
fi
134+
135+
JSON_MY_STRING=$(jq -r '.my_string' "$JSON_OUTPUT_PATH")
136+
if [[ "$JSON_MY_STRING" != "hello" ]]; then
137+
echo "::error:: JSON my_string should be 'hello', got: $JSON_MY_STRING"
138+
exit 1
139+
fi
140+
141+
JSON_MY_BOOL=$(jq -r '.my_bool' "$JSON_OUTPUT_PATH")
142+
if [[ "$JSON_MY_BOOL" != "true" ]]; then
143+
echo "::error:: JSON my_bool should be true, got: $JSON_MY_BOOL"
144+
exit 1
145+
fi
146+
147+
# Validate sensitive values are included in JSON
148+
JSON_MY_SENSITIVE_NUMBER=$(jq -r '.my_sensitive_number' "$JSON_OUTPUT_PATH")
149+
if [[ "$JSON_MY_SENSITIVE_NUMBER" != "6" ]]; then
150+
echo "::error:: JSON my_sensitive_number should be 6, got: $JSON_MY_SENSITIVE_NUMBER"
151+
exit 1
152+
fi
153+
154+
# List from tolist(toset()) may have different order, so check elements exist
155+
JSON_MY_LIST_HAS_ONE=$(jq -r '.my_list | contains(["one"])' "$JSON_OUTPUT_PATH")
156+
JSON_MY_LIST_HAS_TWO=$(jq -r '.my_list | contains(["two"])' "$JSON_OUTPUT_PATH")
157+
JSON_MY_LIST_LENGTH=$(jq -r '.my_list | length' "$JSON_OUTPUT_PATH")
158+
if [[ "$JSON_MY_LIST_HAS_ONE" != "true" || "$JSON_MY_LIST_HAS_TWO" != "true" || "$JSON_MY_LIST_LENGTH" != "2" ]]; then
159+
echo "::error:: JSON my_list should contain 'one' and 'two' with length 2"
160+
exit 1
161+
fi
162+
163+
# Validate map/object becomes JSON object
164+
JSON_MY_MAP_FIRST=$(jq -r '.my_map.first' "$JSON_OUTPUT_PATH")
165+
JSON_MY_MAP_SECOND=$(jq -r '.my_map.second' "$JSON_OUTPUT_PATH")
166+
JSON_MY_MAP_THIRD=$(jq -r '.my_map.third' "$JSON_OUTPUT_PATH")
167+
if [[ "$JSON_MY_MAP_FIRST" != "one" || "$JSON_MY_MAP_SECOND" != "two" || "$JSON_MY_MAP_THIRD" != "3" ]]; then
168+
echo "::error:: JSON my_map should have correct key-value pairs"
169+
exit 1
170+
fi

CHANGELOG.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,23 @@ The actions are versioned as a suite. Some actions may have no change in behavio
1111

1212
When using an action you can specify the version as:
1313

14-
- `@v2.1.0` to use an exact release
15-
- `@v2.1` to use the latest patch release for the specific minor version
14+
- `@v2.2.0` to use an exact release
15+
- `@v2.2` to use the latest patch release for the specific minor version
1616
- `@v2` to use the latest patch release for the specific major version
1717

18+
## [2.2.0] - 2025-08-01
19+
20+
### Added
21+
- New `json_output_path` output for [dflook/terraform-apply](https://github.com/dflook/terraform-github-actions/tree/main/terraform-apply),
22+
[dflook/terraform-output](https://github.com/dflook/terraform-github-actions/tree/main/terraform-output),
23+
[dflook/terraform-remote-state](https://github.com/dflook/terraform-github-actions/tree/main/terraform-remote-state),
24+
[dflook/tofu-apply](https://github.com/dflook/terraform-github-actions/tree/main/tofu-apply),
25+
[dflook/tofu-output](https://github.com/dflook/terraform-github-actions/tree/main/tofu-output), and
26+
[dflook/tofu-remote-state](https://github.com/dflook/terraform-github-actions/tree/main/tofu-remote-state) actions.
27+
28+
The `json_output_path` output points to a JSON file containing all root module outputs in a simple key-value format.
29+
This addresses GitHub Actions' output size limitations and enables easier access to all outputs as a single object.
30+
1831
## [2.1.0] - 2025-06-16
1932

2033
### Added
@@ -772,6 +785,7 @@ First release of the GitHub Actions:
772785
- [dflook/terraform-new-workspace](terraform-new-workspace)
773786
- [dflook/terraform-destroy-workspace](terraform-destroy-workspace)
774787

788+
[2.2.0]: https://github.com/dflook/terraform-github-actions/compare/v2.1.0...v2.2.0
775789
[2.1.0]: https://github.com/dflook/terraform-github-actions/compare/v2.0.1...v2.1.0
776790
[2.0.1]: https://github.com/dflook/terraform-github-actions/compare/v2.0.0...v2.0.1
777791
[2.0.0]: https://github.com/dflook/terraform-github-actions/compare/v1.49.0...v2.0.0

docs-gen/action.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def assert_ordering(self):
195195
"terraform",
196196
"tofu",
197197
"Provider Versions",
198+
"json_output_path",
198199
"$ProductName Outputs",
199200
], self.outputs)
200201

docs-gen/actions/apply.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from inputs.var import var
2626
from inputs.workspace import workspace
2727
from outputs.failure_reason import failure_reason
28+
from outputs.json_output_path import json_output_path
2829
from outputs.json_plan_path import json_plan_path
2930
from outputs.lock_info import lock_info
3031
from outputs.run_id import run_id
@@ -112,6 +113,7 @@
112113
),
113114
lock_info,
114115
run_id,
116+
json_output_path,
115117
terraform_outputs
116118
],
117119
environment_variables=[

docs-gen/actions/output.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from inputs.var_file import var_file
1313
from inputs.variables import variables
1414
from inputs.workspace import workspace
15+
from outputs.json_output_path import json_output_path
1516
from outputs.terraform_outputs import terraform_outputs
1617

1718
output = Action(
@@ -39,6 +40,7 @@
3940
TERRAFORM_PRE_RUN
4041
],
4142
outputs=[
43+
json_output_path,
4244
terraform_outputs
4345
],
4446
extra='''

docs-gen/actions/remote_state.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from inputs.backend_config_file import backend_config_file
88
from inputs.backend_type import backend_type
99
from inputs.workspace import workspace
10+
from outputs.json_output_path import json_output_path
1011
from outputs.terraform_outputs import terraform_outputs
1112

1213
remote_state = Action(
@@ -21,6 +22,7 @@
2122
backend_config_file,
2223
],
2324
outputs=[
25+
json_output_path,
2426
terraform_outputs
2527
],
2628
environment_variables=[
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from action import Output
2+
3+
json_output_path = Output(
4+
name='json_output_path',
5+
type='string',
6+
description='''
7+
This is the path to all the root module outputs in a JSON file.
8+
The path is relative to the Actions workspace.
9+
10+
For example, with the $ProductName config:
11+
12+
```hcl
13+
output "service_hostname" {
14+
value = "example.com"
15+
}
16+
```
17+
18+
The file pointed to by this output will contain:
19+
20+
```json
21+
{
22+
"service_hostname": "example.com"
23+
}
24+
```
25+
26+
$ProductName list, set and tuple types are cast to a JSON array, map and object types are cast to a JSON object.
27+
'''
28+
)

image/actions.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,11 @@ function output() {
443443
# shellcheck disable=SC2086
444444
debug_log "$TOOL_COMMAND_NAME" output -json
445445
# shellcheck disable=SC2086
446-
(cd "$INPUT_PATH" && $TOOL_COMMAND_NAME output -json | tee "$STEP_TMP_DIR/terraform_output.json" | convert_output)
446+
(cd "$INPUT_PATH" && $TOOL_COMMAND_NAME output -json | tee "$STEP_TMP_DIR/terraform_output.json" | convert_output "$STEP_TMP_DIR/outputs.json")
447+
448+
mkdir -p "$GITHUB_WORKSPACE/$WORKSPACE_TMP_DIR"
449+
cp "$STEP_TMP_DIR/outputs.json" "$GITHUB_WORKSPACE/$WORKSPACE_TMP_DIR/outputs.json"
450+
set_output json_output_path "$WORKSPACE_TMP_DIR/outputs.json"
447451
}
448452

449453
function random_string() {

image/tools/convert_output.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44
import sys
55
from dataclasses import dataclass
6+
from pathlib import Path
67
from typing import Dict, Iterable, Union
78
from github_actions.commands import output, mask
89

@@ -55,6 +56,15 @@ def read_input(s: str) -> dict:
5556
jstr = '\n'.join(lines)
5657
return json.loads(jstr)
5758

59+
def write_json_outputs(json_output_path: Path, outputs: Dict):
60+
"""
61+
Flatten the terraform json output format to a simple dictionary, and write it to a file.
62+
"""
63+
64+
json_outputs = {name: o['value'] for name, o in outputs.items()}
65+
66+
with open(json_output_path, 'w') as f:
67+
json.dump(json_outputs, f, indent=2, sort_keys=True)
5868

5969
if __name__ == '__main__':
6070

@@ -67,6 +77,8 @@ def read_input(s: str) -> dict:
6777
sys.stderr.write(input_string)
6878
raise
6979

80+
write_json_outputs(Path(sys.argv[1]), outputs)
81+
7082
for command in convert_to_github(outputs):
7183
if isinstance(command, Output):
7284
output(command.name, command.value)

terraform-apply/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,31 @@ These input values must be the same as any [`dflook/terraform-plan`](https://git
269269

270270
- Type: string
271271

272+
* `json_output_path`
273+
274+
This is the path to all the root module outputs in a JSON file.
275+
The path is relative to the Actions workspace.
276+
277+
For example, with the Terraform config:
278+
279+
```hcl
280+
output "service_hostname" {
281+
value = "example.com"
282+
}
283+
```
284+
285+
The file pointed to by this output will contain:
286+
287+
```json
288+
{
289+
"service_hostname": "example.com"
290+
}
291+
```
292+
293+
Terraform list, set and tuple types are cast to a JSON array, map and object types are cast to a JSON object.
294+
295+
- Type: string
296+
272297
* Terraform Outputs
273298

274299
An action output will be created for each output of the Terraform configuration.

0 commit comments

Comments
 (0)