Repository navigation
160 lines (135 loc) · 5.78 KB
/
Copy pathci.yml
File metadata and controls
160 lines (135 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
name: ci
# Lint + validate every module on PRs and pushes to main.
# No cloud credentials needed — validation runs with the backend disabled.
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
# Derive the component list from the filesystem (every dir with a terraform/ subdir) so a new
# component is validated automatically — no hand-maintained matrix to forget (see issue #21).
discover:
runs-on: ubuntu-latest
outputs:
components: ${{ steps.list.outputs.components }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- id: list
name: enumerate changed components (dirs containing terraform/)
run: |
# Full component list — filesystem truth, same logic as before.
ALL="$(find . -mindepth 2 -maxdepth 2 -type d -name terraform -not -path './.*' \
-printf '%h\n' | sed 's|^\./||' | sort | jq -R . | jq -cs .)"
# Resolve diff range for PR vs push.
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
else
BASE="${{ github.event.before }}"
HEAD="${{ github.sha }}"
fi
# Force-push, initial branch push, or unreachable base — no valid range, run all.
if [[ "$BASE" == "0000000000000000000000000000000000000000" ]] || \
! git cat-file -t "$BASE" > /dev/null 2>&1; then
echo "components=$ALL" >> "$GITHUB_OUTPUT"
echo "No valid base SHA — running all components: $ALL"
exit 0
fi
# Any change to shared Terraform config affects every component — run all.
if git diff --name-only "$BASE" "$HEAD" -- \
.tflint.hcl .terraform-version .github/workflows/ci.yml | grep -q .; then
echo "components=$ALL" >> "$GITHUB_OUTPUT"
echo "Shared config changed — running all components: $ALL"
exit 0
fi
# Emit only the components that contain changed Terraform files.
COMPONENTS="$(
git diff --name-only "$BASE" "$HEAD" \
-- '*/terraform/*.tf' '*/terraform/*.tofu' '*/terraform/*.tfvars' \
| sed -n 's|^\([^/]*\)/terraform/.*|\1|p' \
| sort -u \
| jq -R . | jq -cs .
)"
echo "components=$COMPONENTS" >> "$GITHUB_OUTPUT"
if [[ "$COMPONENTS" == "[]" ]]; then
echo "No Terraform files changed — validate will be skipped."
else
echo "Changed components: $COMPONENTS"
fi
validate:
needs: discover
if: needs.discover.outputs.components != '[]'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
component: ${{ fromJSON(needs.discover.outputs.components) }}
steps:
- uses: actions/checkout@v6
- uses: hashicorp/setup-terraform@v4
with:
terraform_version: 1.15.5
- name: terraform fmt
run: terraform -chdir=${{ matrix.component }}/terraform fmt -check -recursive
- name: terraform init (no backend)
run: terraform -chdir=${{ matrix.component }}/terraform init -backend=false -input=false
- name: terraform validate
run: terraform -chdir=${{ matrix.component }}/terraform validate
# Components with a tests/ directory carry mocked-provider tests (no credentials needed).
- name: terraform test
run: |
if compgen -G "${{ matrix.component }}/terraform/tests/*.tftest.hcl" > /dev/null; then
terraform -chdir=${{ matrix.component }}/terraform test
fi
- uses: terraform-linters/setup-tflint@v6
with:
tflint_version: latest
- name: tflint
run: |
cd ${{ matrix.component }}/terraform
tflint --init --config="$GITHUB_WORKSPACE/.tflint.hcl"
tflint --config="$GITHUB_WORKSPACE/.tflint.hcl"
# Docs: component README Inputs/Outputs tables are up to date (terraform-docs), the required README
# structure is present, and markdown style holds. Mirrors the local pre-commit docs hooks.
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: install terraform-docs
run: |
curl -sSfL -o td.tgz \
https://github.com/terraform-docs/terraform-docs/releases/download/v0.24.0/terraform-docs-v0.24.0-linux-amd64.tar.gz
tar -xzf td.tgz terraform-docs
sudo install -m 0755 terraform-docs /usr/local/bin/terraform-docs
terraform-docs version
- name: README tables up to date (terraform-docs)
run: bash scripts/gen-docs.sh --check
- name: README structure
run: bash scripts/check-readme-structure.sh
- uses: DavidAnson/markdownlint-cli2-action@v23.2.0
with:
globs: |
README.md
AGENTS.md
*/README.md
# Canary for issue #21: the local pre-commit Terraform hooks once reported "(no files to check)" on a
# brand-new component, so its fmt/validate/tflint silently never ran on commit (false confidence). Re-run
# the fmt hook over the PR's changed range and fail loudly if it skips changed Terraform.
precommit-coverage:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: hashicorp/setup-terraform@v4
with:
terraform_version: 1.15.5
- name: install pre-commit
run: pipx install pre-commit
- name: assert Terraform hooks cover the PR's changed .tf
run: scripts/check-precommit-tf-coverage.sh "${{ github.event.pull_request.base.sha }}" "${{ github.event.pull_request.head.sha }}"