Skip to content

Commit d085287

Browse files
authored
Merge pull request #1 from soat-tech-challenge/feat/terraform-workflows
feat: terraform workflows
2 parents 2bbbd9b + 1a403d6 commit d085287

File tree

5 files changed

+257
-0
lines changed

5 files changed

+257
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Terraform API-driven apply run using Terraform Cloud
2+
name: Terraform Apply
3+
4+
on:
5+
workflow_call:
6+
# See https://developer.hashicorp.com/terraform/cli/cloud/settings#environment-variables
7+
inputs:
8+
cloud_organization:
9+
type: string
10+
default: "soat-tech-challenge"
11+
cloud_workspace:
12+
type: string
13+
config_directory:
14+
type: string
15+
default: "./"
16+
secrets:
17+
cloud_token:
18+
required: true
19+
20+
jobs:
21+
apply:
22+
name: Apply
23+
runs-on: ubuntu-latest
24+
25+
outputs:
26+
status: ${{ steps.apply-run.outputs.status }}
27+
payload: ${{ steps.apply-run.outputs.payload }}
28+
run_id: ${{ steps.apply-run.outputs.id }}
29+
run_link: ${{ steps.apply-run.outputs.run_link }}
30+
plan_id: ${{ steps.apply-run.outputs.plan_id }}
31+
32+
env:
33+
TF_CLOUD_ORGANIZATION: ${{ inputs.cloud_organization }}
34+
TF_API_TOKEN: ${{ secrets.cloud_token }}
35+
TF_WORKSPACE: ${{ inputs.cloud_workspace }}
36+
CONFIG_DIRECTORY: ${{ inputs.config_directory }}
37+
38+
steps:
39+
- name: Checkout
40+
uses: actions/checkout@v3
41+
42+
- name: Upload Configuration
43+
uses: hashicorp/tfc-workflows-github/actions/[email protected]
44+
id: apply-upload
45+
with:
46+
workspace: ${{ env.TF_WORKSPACE }}
47+
directory: ${{ env.CONFIG_DIRECTORY }}
48+
49+
- name: Create Apply Run
50+
uses: hashicorp/tfc-workflows-github/actions/[email protected]
51+
id: apply-run
52+
with:
53+
workspace: ${{ env.TF_WORKSPACE }}
54+
configuration_version: ${{ steps.apply-upload.outputs.configuration_version_id }}
55+
56+
- name: Apply
57+
uses: hashicorp/tfc-workflows-github/actions/[email protected]
58+
if: fromJSON(steps.apply-run.outputs.payload).data.attributes.actions.IsConfirmable
59+
with:
60+
run: ${{ steps.apply-run.outputs.run_id }}
61+
comment: "Apply Run from GitHub Actions CI ${{ github.sha }}"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Terraform CLI-driven destroy run using Remote Host
2+
name: Terraform Destroy
3+
4+
on:
5+
workflow_call:
6+
inputs:
7+
workspace:
8+
type: string
9+
secrets:
10+
token:
11+
required: true
12+
13+
jobs:
14+
terraform_destroy:
15+
name: Terraform Destroy
16+
17+
runs-on: ubuntu-latest
18+
19+
env:
20+
TF_IN_AUTOMATION: true
21+
TF_INPUT: false
22+
TF_WORKSPACE: ${{ inputs.workspace }}
23+
24+
steps:
25+
- name: Checkout
26+
uses: actions/checkout@v3
27+
28+
- name: Setup Terraform
29+
uses: hashicorp/setup-terraform@v2
30+
with:
31+
cli_config_credentials_token: ${{ secrets.token }}
32+
33+
- name: Terraform Init
34+
run: terraform init
35+
36+
- name: Terraform Plan
37+
run: terraform plan -destroy
38+
39+
- name: Terraform Destroy
40+
run: terraform destroy -auto-approve
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Terraform API-driven speculative plan run using Terraform Cloud
2+
name: Terraform Speculative Plan
3+
4+
on:
5+
workflow_call:
6+
# See https://developer.hashicorp.com/terraform/cli/cloud/settings#environment-variables
7+
inputs:
8+
cloud_organization:
9+
type: string
10+
default: "soat-tech-challenge"
11+
cloud_workspace:
12+
type: string
13+
config_directory:
14+
type: string
15+
default: "./"
16+
secrets:
17+
cloud_token:
18+
required: true
19+
20+
jobs:
21+
terraform-cloud-speculative-plan:
22+
name: Terraform Cloud Speculative Plan
23+
runs-on: ubuntu-latest
24+
25+
outputs:
26+
status: ${{ steps.apply-run.outputs.status }}
27+
payload: ${{ steps.apply-run.outputs.payload }}
28+
run_id: ${{ steps.apply-run.outputs.id }}
29+
run_link: ${{ steps.apply-run.outputs.run_link }}
30+
plan_id: ${{ steps.apply-run.outputs.plan_id }}
31+
32+
env:
33+
TF_CLOUD_ORGANIZATION: ${{ inputs.cloud_organization }}
34+
TF_API_TOKEN: ${{ secrets.cloud_token }}
35+
TF_WORKSPACE: ${{ inputs.cloud_workspace }}
36+
CONFIG_DIRECTORY: ${{ inputs.config_directory }}
37+
38+
steps:
39+
- name: Checkout
40+
uses: actions/checkout@v3
41+
42+
- name: Upload Configuration
43+
uses: hashicorp/tfc-workflows-github/actions/[email protected]
44+
id: plan-upload
45+
with:
46+
workspace: ${{ env.TF_WORKSPACE }}
47+
directory: ${{ env.CONFIG_DIRECTORY }}
48+
speculative: true
49+
50+
- name: Create Plan Run
51+
uses: hashicorp/tfc-workflows-github/actions/[email protected]
52+
id: plan-run
53+
## run may fail, if so continue to output PR comment
54+
## step.terraform-cloud-check-run-status will fail job after pr comment is created/updated.
55+
continue-on-error: true
56+
with:
57+
workspace: ${{ env.TF_WORKSPACE }}
58+
configuration_version: ${{ steps.plan-upload.outputs.configuration_version_id }}
59+
plan_only: true
60+
61+
- name: Get Plan Output
62+
uses: hashicorp/tfc-workflows-github/actions/[email protected]
63+
id: plan-output
64+
with:
65+
plan: ${{ steps.plan-run.outputs.plan_id }}
66+
67+
- name: Update PR with Plan comment
68+
uses: actions/github-script@v6
69+
if: github.event_name == 'pull_request'
70+
with:
71+
github-token: ${{ secrets.GITHUB_TOKEN }}
72+
script: |
73+
// 1. Retrieve existing bot comments for the PR
74+
const { data: comments } = await github.rest.issues.listComments({
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
issue_number: context.issue.number,
78+
})
79+
const botComment = comments.find(comment => {
80+
return comment.user.type === 'Bot' && comment.body.includes('Terraform Cloud Plan Output')
81+
})
82+
const output = `#### Terraform Cloud Plan Output
83+
\`\`\`
84+
Plan: ${{ steps.plan-output.outputs.add }} to add, ${{ steps.plan-output.outputs.change }} to change, ${{ steps.plan-output.outputs.destroy }} to destroy.
85+
\`\`\`
86+
[Terraform Cloud Plan](${{ steps.plan-run.outputs.run_link }})
87+
`
88+
// 3. If we have a comment, update it, otherwise create a new one
89+
if (botComment) {
90+
github.rest.issues.updateComment({
91+
owner: context.repo.owner,
92+
repo: context.repo.repo,
93+
comment_id: botComment.id,
94+
body: output
95+
})
96+
} else {
97+
github.rest.issues.createComment({
98+
issue_number: context.issue.number,
99+
owner: context.repo.owner,
100+
repo: context.repo.repo,
101+
body: output
102+
})
103+
}
104+
105+
## Check Run Status, if not planned_and_finished fail the job
106+
- id: terraform-cloud-check-run-status
107+
if: ${{ steps.plan-run.outputs.run_status != 'planned_and_finished'}}
108+
run: |
109+
echo "Terraform Cloud Run Failed or Requires Further Attention"
110+
echo "Run Status: '${{ steps.plan-run.outputs.run_status }}'"
111+
echo "${{ steps.plan-run.outputs.run_link }}"
112+
exit 1

.github/workflows/tflint.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: TFLint
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
tflint:
8+
name: TFLint
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v3
14+
15+
- name: Setup TFLint
16+
uses: terraform-linters/setup-tflint@v3
17+
18+
- name: Init TFLint
19+
run: tflint --init
20+
env:
21+
# https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting
22+
GITHUB_TOKEN: ${{ github.token }}
23+
24+
- name: Run TFLint
25+
run: tflint -f compact

.github/workflows/tfsec.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: tfsec
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
tfsec:
8+
name: tfsec
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v3
14+
15+
- name: tfsec
16+
uses: aquasecurity/[email protected]
17+
with:
18+
tfsec_args: --soft-fail
19+
github_token: ${{ github.token }}

0 commit comments

Comments
 (0)