Skip to content

Commit f2bd58b

Browse files
committed
Initial commit
0 parents  commit f2bd58b

18 files changed

+1068
-0
lines changed

LICENSE

Lines changed: 373 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
# Terraform GitHub Actions
2+
These official Terraform GitHub Actions allow you to run `terraform fmt`, `validate` and `plan` on your pull requests to help you review and validate Terraform changes.
3+
4+
* [Actions](#actions)
5+
* [Fmt Action](#fmt-action)
6+
* [Validate Action](#validate-action)
7+
* [Plan Action](#plan-action)
8+
* [Usage](#usage)
9+
* [Recommended Workflow](#recommended-workflow)
10+
* [Step 1 - Create the initial workflow](#step-1---create-the-initial-workflow)
11+
* [Step 2 - Customize it for your use-case](#step-2---customize-it-for-your-use-case)
12+
* [Compose Your Own Workflow](#compose-your-own-workflow)
13+
* [Directories](#directories)
14+
* [Workspaces](#workspaces)
15+
16+
## Actions
17+
18+
### Fmt Action
19+
Runs `terraform fmt` and comments back if any files are not formatted correctly.
20+
<img src="./assets/fmt.png" alt="Terraform Fmt Action" width="80%" />
21+
22+
### Validate Action
23+
Runs `terraform validate` and comments back on error.
24+
<img src="./assets/validate.png" alt="Terraform Validate Action" width="80%" />
25+
26+
### Plan Action
27+
Runs `terraform plan` and comments back with the output.
28+
<img src="./assets/plan.png" alt="Terraform Plan Action" width="80%" />
29+
30+
## Usage
31+
To add these actions to your pull requests, you can copy our [recommended workflow](#recommended-workflow) into your `.github/main.workflow` file or you can [write your own workflow](#compose-your-own-workflow).
32+
33+
### Recommended Workflow
34+
This workflow will run `terraform fmt`, `init`, `validate` and `plan`. To use it:
35+
36+
#### Step 1 - Create the initial workflow
37+
1. Open up your repository in GitHub and click on the **Actions** tab
38+
1. Click **Create a new workflow**
39+
1. Click **<> Edit new file**
40+
1. Paste the contents below into the file
41+
<details><summary>Show</summary>
42+
43+
```workflow
44+
workflow "Terraform" {
45+
resolves = "terraform-plan"
46+
on = "pull_request"
47+
}
48+
49+
action "filter-to-pr-open-synced" {
50+
uses = "docker://superbbears/filter:0.2.0"
51+
args = ["action", "opened|synchronize"]
52+
}
53+
54+
action "terraform-fmt" {
55+
uses = "hashicorp/terraform-github-actions/[email protected]"
56+
needs = "filter-to-pr-open-synced"
57+
secrets = ["GITHUB_TOKEN"]
58+
env = {
59+
TF_ACTION_WORKING_DIR = "."
60+
}
61+
}
62+
63+
action "terraform-init" {
64+
uses = "hashicorp/terraform-github-actions/[email protected]"
65+
needs = "terraform-fmt"
66+
secrets = ["GITHUB_TOKEN"]
67+
env = {
68+
TF_ACTION_WORKING_DIR = "."
69+
}
70+
}
71+
72+
action "terraform-validate" {
73+
uses = "hashicorp/terraform-github-actions/[email protected]"
74+
needs = "terraform-init"
75+
secrets = ["GITHUB_TOKEN"]
76+
env = {
77+
TF_ACTION_WORKING_DIR = "."
78+
}
79+
}
80+
81+
action "terraform-plan" {
82+
uses = "hashicorp/terraform-github-actions/[email protected]"
83+
needs = "terraform-validate"
84+
secrets = ["GITHUB_TOKEN"]
85+
env = {
86+
TF_ACTION_WORKING_DIR = "."
87+
# If you're using Terraform workspaces, set this to the workspace name.
88+
TF_ACTION_WORKSPACE = "default"
89+
}
90+
}
91+
```
92+
</details>
93+
94+
#### Step 2 - Customize it for your use-case
95+
1. If your Terraform is in a different directory that the root of your repo, replace all instances of
96+
```
97+
TF_ACTION_WORKING_DIR = "."
98+
```
99+
With your directory, relative to the root of the repo, ex.
100+
```
101+
TF_ACTION_WORKING_DIR = "./terraform"
102+
```
103+
If you have multiple directories of Terraform code see [Directories](#directories)
104+
1. If your Terraform runs in a different [workspace](https://www.terraform.io/docs/state/workspaces.html) than `default`, also change the `TF_ACTION_WORKSPACE` environment variable in the `terraform-plan` action.
105+
106+
If you have multiple workspaces, see [Workspaces](#workspaces).
107+
1. If you're using a Terraform provider that requires credentials to run `terraform plan` (like AWS or Google Cloud Platform) then you need to add those credentials as Secrets to the `terraform-plan` action. Secrets can only be added from the **Visual Editor** so click back to that tab.
108+
1. Scroll down to the `terraform-plan` action and click **Edit**. This will open up the action editor on the right side where you'll be able to add your secrets, ex. `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. See your [Provider Documentation](https://www.terraform.io/docs/providers/) for how to use environment variables with your provider.
109+
110+
⚠️ WARNING ⚠️ These secrets could be exposed if the plan action is run on a malicious Terraform file. As a result, we recommend you do not use this action on public repos or repos where untrusted users can submit pull requests.
111+
112+
113+
## Compose Your Own Workflow
114+
If you'd like to compose your own workflow, you can use each action separately. Each action is documented:
115+
* [fmt](fmt/)
116+
* [init](init/)
117+
* [validate](validate/)
118+
* [plan](plan/)
119+
120+
## Directories
121+
Currently, these actions only support running in a single directory. If you'd like to run them in multiple directories, you'll have to create separate workflows for each directory:
122+
123+
<details><summary>Show</summary>
124+
125+
```workflow
126+
workflow "terraform-dir1" {
127+
resolves = "terraform-plan-dir1"
128+
on = "pull_request"
129+
}
130+
131+
action "filter-to-pr-open-synced" {
132+
uses = "docker://superbbears/filter:0.2.0"
133+
args = ["action", "opened|synchronize"]
134+
}
135+
136+
action "terraform-fmt-dir1" {
137+
uses = "hashicorp/terraform-github-actions/[email protected]"
138+
needs = "filter-to-pr-open-synced"
139+
secrets = ["GITHUB_TOKEN"]
140+
141+
env = {
142+
TF_ACTION_WORKING_DIR = "dir1"
143+
}
144+
}
145+
146+
action "terraform-init-dir1" {
147+
uses = "hashicorp/terraform-github-actions/[email protected]"
148+
secrets = ["GITHUB_TOKEN"]
149+
needs = "terraform-fmt-dir1"
150+
151+
env = {
152+
TF_ACTION_WORKING_DIR = "dir1"
153+
}
154+
}
155+
156+
action "terraform-validate-dir1" {
157+
uses = "hashicorp/terraform-github-actions/[email protected]"
158+
secrets = ["GITHUB_TOKEN"]
159+
needs = "terraform-init-dir1"
160+
161+
env = {
162+
TF_ACTION_WORKING_DIR = "dir1"
163+
}
164+
}
165+
166+
action "terraform-plan-dir1" {
167+
uses = "hashicorp/terraform-github-actions/[email protected]"
168+
needs = "terraform-validate-dir1"
169+
secrets = ["GITHUB_TOKEN"]
170+
171+
env = {
172+
TF_ACTION_WORKING_DIR = "dir1"
173+
}
174+
}
175+
176+
workflow "terraform-dir2" {
177+
resolves = "terraform-plan-dir2"
178+
on = "pull_request"
179+
}
180+
181+
action "terraform-fmt-dir2" {
182+
uses = "hashicorp/terraform-github-actions/[email protected]"
183+
needs = "filter-to-pr-open-synced"
184+
secrets = ["GITHUB_TOKEN"]
185+
186+
env = {
187+
TF_ACTION_WORKING_DIR = "dir2"
188+
}
189+
}
190+
191+
action "terraform-init-dir2" {
192+
uses = "hashicorp/terraform-github-actions/[email protected]"
193+
secrets = ["GITHUB_TOKEN"]
194+
needs = "terraform-fmt-dir2"
195+
196+
env = {
197+
TF_ACTION_WORKING_DIR = "dir2"
198+
}
199+
}
200+
201+
action "terraform-validate-dir2" {
202+
uses = "hashicorp/terraform-github-actions/[email protected]"
203+
secrets = ["GITHUB_TOKEN"]
204+
needs = "terraform-init-dir2"
205+
206+
env = {
207+
TF_ACTION_WORKING_DIR = "dir2"
208+
}
209+
}
210+
211+
action "terraform-plan-dir2" {
212+
uses = "hashicorp/terraform-github-actions/[email protected]"
213+
needs = "terraform-validate-dir2"
214+
secrets = ["GITHUB_TOKEN"]
215+
216+
env = {
217+
TF_ACTION_WORKING_DIR = "dir2"
218+
}
219+
}
220+
```
221+
</details>
222+
223+
## Workspaces
224+
Currently, these actions only support running in a single [Terraform workspace](https://www.terraform.io/docs/state/workspaces.html).
225+
226+
NOTE: The only action workspaces affect is `plan`.
227+
228+
If you'd like to run in multiple workspaces, you need to create separate workflows for each workspace. Since the only action that uses workspaces is `plan`, you can share the rest of the `fmt`, `init` and `validate` actions between the two workflows:
229+
230+
<details><summary>Show</summary>
231+
232+
```workflow
233+
workflow "terraform-workspace1" {
234+
resolves = "terraform-plan-workspace1"
235+
on = "pull_request"
236+
}
237+
238+
workflow "terraform-workspace2" {
239+
resolves = "terraform-plan-workspace2"
240+
on = "pull_request"
241+
}
242+
243+
action "filter-to-pr-open-synced" {
244+
uses = "docker://superbbears/filter:0.2.0"
245+
args = ["action", "opened|synchronize"]
246+
}
247+
248+
action "terraform-fmt" {
249+
uses = "hashicorp/terraform-github-actions/[email protected]"
250+
needs = "filter-to-pr-open-synced"
251+
secrets = ["GITHUB_TOKEN"]
252+
}
253+
254+
action "terraform-init" {
255+
uses = "hashicorp/terraform-github-actions/[email protected]"
256+
secrets = ["GITHUB_TOKEN"]
257+
needs = "terraform-fmt"
258+
}
259+
260+
action "terraform-validate" {
261+
uses = "hashicorp/terraform-github-actions/[email protected]"
262+
secrets = ["GITHUB_TOKEN"]
263+
needs = "terraform-init"
264+
}
265+
266+
action "terraform-plan-workspace1" {
267+
uses = "hashicorp/terraform-github-actions/[email protected]"
268+
needs = "terraform-validate"
269+
secrets = ["GITHUB_TOKEN"]
270+
271+
env = {
272+
TF_ACTION_WORKSPACE = "workspace1"
273+
}
274+
}
275+
276+
action "terraform-plan-workspace2" {
277+
uses = "hashicorp/terraform-github-actions/[email protected]"
278+
needs = "terraform-validate"
279+
secrets = ["GITHUB_TOKEN"]
280+
281+
env = {
282+
TF_ACTION_WORKSPACE = "workspace2"
283+
}
284+
}
285+
```
286+
</details>

assets/fmt.png

73.8 KB
Loading

assets/plan.png

133 KB
Loading

assets/validate.png

51.5 KB
Loading

fmt/Dockerfile

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM hashicorp/terraform:0.11.8
2+
3+
LABEL "com.github.actions.name"="terraform fmt"
4+
LABEL "com.github.actions.description"="Validate terraform files are formatted"
5+
LABEL "com.github.actions.icon"="terminal"
6+
LABEL "com.github.actions.color"="purple"
7+
8+
LABEL "repository"="https://github.com/hashicorp/terraform-github-actions"
9+
LABEL "homepage"="http://github.com/hashicorp/terraform-github-actions"
10+
LABEL "maintainer"="HashiCorp Terraform Team <[email protected]>"
11+
12+
RUN apk --no-cache add jq
13+
14+
COPY entrypoint.sh /entrypoint.sh
15+
ENTRYPOINT ["/entrypoint.sh"]

fmt/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Terraform Fmt Action
2+
Runs `terraform fmt` to validate all Terraform files in a directory are in the canonical format.
3+
If any files differ, this action will comment back on the pull request with the diffs of each file.
4+
5+
## Success Criteria
6+
This action succeeds if `terraform fmt` runs without error.
7+
8+
## Usage
9+
To use the `fmt` action, add it to your workflow file.
10+
11+
```workflow
12+
action "terraform fmt" {
13+
# Replace <latest tag> with the latest tag from https://github.com/hashicorp/terraform-github-actions/releases.
14+
uses = "hashicorp/terraform-github-actions/fmt@<latest tag>"
15+
16+
# See Environment Variables below for details.
17+
env = {
18+
TF_ACTION_WORKING_DIR = "."
19+
}
20+
21+
# We need the GitHub token to be able to comment back on the pull request.
22+
secrets = ["GITHUB_TOKEN"]
23+
}
24+
```
25+
26+
## Environment Variables
27+
| Name | Default | Description |
28+
|-------------------------|-----------|----------------------------------------------------------------------------------|
29+
| `TF_ACTION_WORKING_DIR` | `"."` | Which directory `fmt` runs in. Relative to the root of the repo. |
30+
| `TF_ACTION_COMMENT` | `"true"` | Set to `"false"` to disable commenting back on pull request with the diffs of unformatted files. |
31+
32+
33+
## Secrets
34+
The `GITHUB_TOKEN` secret is required for posting a comment back to the pull request if `fmt` fails.
35+
36+
If you have set `TF_ACTION_COMMENT = "false"`, then `GITHUB_TOKEN` is not required.
37+
38+
## Arguments
39+
Any arguments will be appended to the `terraform fmt` command however we do not anticipate that this will be needed.

fmt/entrypoint.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/sh
2+
set -e
3+
cd "${TF_ACTION_WORKING_DIR:-.}"
4+
5+
set +e
6+
UNFMT_FILES=$(sh -c "terraform fmt -check=true -write=false $*" 2>&1)
7+
SUCCESS=$?
8+
echo "$UNFMT_FILES"
9+
set -e
10+
11+
if [ $SUCCESS -eq 0 ]; then
12+
exit 0
13+
fi
14+
15+
if [ "$TF_ACTION_COMMENT" = "1" ] || [ "$TF_ACTION_COMMENT" = "false" ]; then
16+
exit $SUCCESS
17+
fi
18+
19+
# Iterate through each unformatted file and build up a comment.
20+
FMT_OUTPUT=""
21+
for file in $UNFMT_FILES; do
22+
FILE_DIFF=$(terraform fmt -write=false -diff=true "$file" | sed -n '/@@.*/,//{/@@.*/d;p}')
23+
FMT_OUTPUT="$FMT_OUTPUT
24+
<details><summary><code>$file</code></summary>
25+
26+
\`\`\`diff
27+
$FILE_DIFF
28+
\`\`\`
29+
</details>
30+
"
31+
done
32+
33+
COMMENT="#### \`terraform fmt\` Failed
34+
$FMT_OUTPUT
35+
"
36+
PAYLOAD=$(echo '{}' | jq --arg body "$COMMENT" '.body = $body')
37+
COMMENTS_URL=$(cat /github/workflow/event.json | jq -r .pull_request.comments_url)
38+
curl -s -S -H "Authorization: token $GITHUB_TOKEN" --header "Content-Type: application/json" --data "$PAYLOAD" "$COMMENTS_URL" > /dev/null
39+
40+
exit $SUCCESS
41+

0 commit comments

Comments
 (0)