Skip to content

Commit 44eb0fc

Browse files
Merge pull request #20 from craftech-io/feature/pre-commit-terraform-fmt-validate
feat: Add Terraform pre-commit hooks (fmt --check & validate), skip examples, improve output, update README
2 parents 9e3a499 + e42aa8b commit 44eb0fc

4 files changed

Lines changed: 147 additions & 21 deletions

File tree

.pre-commit-hooks.yaml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,22 @@
66
entry: hooks/terraform-fmt.sh
77
language: script
88
files: \.tf$
9-
exclude: \.+.terraform\/.*$
9+
exclude: '(^|.*/)(\.terraform|examples)/'
10+
require_serial: true
11+
12+
- id: terraform-validate
13+
name: Terraform validate
14+
description: Runs 'terraform validate'
15+
entry: hooks/terraform-validate.sh
16+
language: script
17+
files: \.tf$
18+
exclude: '(^|.*/)(\.terraform|examples)/'
1019
require_serial: true
1120

1221
- id: pipeline-generator
1322
name: pipeline-generator
1423
description: Generate ci config automatically.
1524
entry: hooks/pipeline-generator.sh
1625
language: script
17-
pass_filenames: false
26+
pass_filenames: false
27+

README.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,55 @@
11
# Pre-commit hooks
22

3-
This repo defines Git pre-commit hooks intended for use with [pre-commit](http://pre-commit.com/). The currently
3+
This repo defines Git pre-commit hooks intended for use with [pre-commit](https://pre-commit.com/). The currently
44
supported hooks are:
55

6-
* **terraform-fmt**: Automatically run `terraform fmt` on all Terraform code (`*.tf` files).
6+
* **terraform-fmt**: Checks that all Terraform files (`*.tf`) are properly formatted (`terraform fmt --check -diff`).
7+
* **terraform-validate**: Runs `terraform init -backend=false` and then `terraform validate`.
8+
> Notes: directories requiring a private registry and lacking credentials are marked as **skipped** (do not fail the commit). Both hooks ignore `.terraform/` and `examples/`.
79
810
## General Usage
911

1012
In each of your repos, add a file called `.pre-commit-config.yaml` with the following contents:
1113

1214
```yaml
1315
repos:
14-
- repo: https://github.com/craftech-io/pre-commit
15-
rev: <VERSION> # Get the latest from: https://github.com/craftech-io/pre-commit/releases
16+
- repo: [email protected]:craftech-io/pre-commit.git # or https://github.com/craftech-io/pre-commit.git
17+
rev: <VERSION>
1618
hooks:
1719
- id: terraform-fmt
20+
- id: terraform-validate
21+
verbose: true
1822
```
1923
20-
Next, have every developer:
24+
Next, have every developer:
2125
22-
1. Install [pre-commit](http://pre-commit.com/). E.g. `brew install pre-commit`.
23-
1. Run `pre-commit install` in the repo.
26+
1. Install [pre-commit](https://pre-commit.com/#install).
27+
- macOS: `brew install pre-commit`
28+
- Linux: `pipx install pre-commit` (or `pip install --user pre-commit`)
29+
2. Run `pre-commit install` in the repo.
2430

25-
That’s it! Now every time you commit a code change (`.tf` file), the hooks in the `hooks:` config will execute.
31+
That's it! Now every time you commit a code change (`.tf` file), the hooks in the `hooks:` config will execute.
32+
If any hook fails, the commit is aborted; if all pass, the commit succeeds.
2633

2734
## Running Against All Files At Once
2835

36+
### Example: Formatting and validating all files
2937

30-
### Example: Formatting all files
31-
32-
If you'd like to format all of your code at once (rather than one file at a time), you can run:
38+
If you'd like to run the hooks across the whole repo (useful the first time), you can run:
3339

3440
```bash
41+
# Check formatting for all Terraform files
3542
pre-commit run terraform-fmt --all-files
43+
44+
# Validate all Terraform directories
45+
pre-commit run terraform-validate --all-files
46+
47+
# Or run every configured hook across the repo
48+
pre-commit run --all-files
3649
```
3750

38-
## License
51+
> Tip: for detailed output on demand, use `-v`, e.g. `pre-commit run -v terraform-validate --all-files`.
3952

40-
This code is released under the Apache 2.0 License. Please see [LICENSE](LICENSE) for more details.
53+
## License
4154

55+
This code is released under the Apache 2.0 License. Please see [LICENSE](LICENSE) for more details.

hooks/terraform-fmt.sh

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
2+
set -uo pipefail
3+
IFS=$'\n\t'
24

3-
set -e
5+
RED='\033[31m'; GRN='\033[32m'; YLW='\033[33m'; BLD='\033[1m'; RST='\033[0m'
6+
if [[ "${PRE_COMMIT_COLOR:-}" == "never" ]]; then RED=''; GRN=''; YLW=''; BLD=''; RST=''; fi
47

5-
for file in "$@"; do
6-
pushd "$(dirname "$file")" >/dev/null
7-
terraform fmt -write=true "$(basename "$file")"
8+
exit_code=0
9+
10+
for f in "$@"; do
11+
dir="$(dirname "$f")"
12+
base="$(basename "$f")"
13+
14+
echo -e "${BLD}${f}${RST}"
15+
16+
pushd "$dir" >/dev/null
17+
out="$(terraform fmt -check -diff -no-color "$base" 2>&1)"
18+
status=$?
819
popd >/dev/null
9-
done
20+
21+
if [[ $status -eq 0 ]]; then
22+
echo -e " ${GRN}✓ Formato correcto${RST}"
23+
else
24+
if grep -q "^Error:" <<<"$out"; then
25+
echo -e " ${RED}✗ Error de sintaxis (terraform fmt)${RST}"
26+
echo "$out" | sed 's/^/ /'
27+
else
28+
echo -e " ${RED}✗ No está formateado${RST} (aplicá 'terraform fmt')"
29+
echo "$out" | sed 's/^/ /'
30+
fi
31+
exit_code=1
32+
fi
33+
34+
echo
35+
done
36+
37+
exit "$exit_code"

hooks/terraform-validate.sh

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env bash
2+
set -uo pipefail
3+
IFS=$'\n\t'
4+
5+
RED='\033[31m'; GRN='\033[32m'; YLW='\033[33m'; BLD='\033[1m'; RST='\033[0m'
6+
if [[ "${PRE_COMMIT_COLOR:-}" == "never" ]]; then RED=''; GRN=''; YLW=''; BLD=''; RST=''; fi
7+
8+
VALIDATE_ARGS=()
9+
[[ "${PRE_COMMIT_COLOR:-}" == "never" ]] && VALIDATE_ARGS+=("-no-color")
10+
11+
if [[ "$#" -gt 0 ]]; then
12+
mapfile -t DIRS < <(for f in "$@"; do dirname "$f"; done | sort -u)
13+
else
14+
mapfile -t DIRS < <(git ls-files '*.tf' | xargs -n1 dirname | sort -u)
15+
fi
16+
17+
exit_code=0
18+
19+
for d in "${DIRS[@]}"; do
20+
mapfile -t TFFILES < <(find "$d" -maxdepth 1 -type f -name '*.tf' | sort)
21+
[[ "${#TFFILES[@]}" -gt 0 ]] || continue
22+
23+
echo -e "${BLD}>> Validando Terraform en: ${d}${RST}"
24+
pushd "${d}" >/dev/null
25+
26+
set +e
27+
out_init="$(terraform init -backend=false -input=false 2>&1)"
28+
st_init=$?
29+
set -e
30+
31+
if [[ $st_init -ne 0 ]]; then
32+
if grep -Eq "Error accessing remote module registry|401 Unauthorized|403 Forbidden|Failed to retrieve available versions" <<<"$out_init"; then
33+
echo -e " ${YLW}! skipped${RST} (requires private registry auth)"
34+
echo "$out_init" | sed 's/^/ /'
35+
for f in "${TFFILES[@]}"; do
36+
echo -e "${f}"
37+
echo -e " ${YLW}! skipped${RST}"
38+
done
39+
popd >/dev/null
40+
echo
41+
continue
42+
fi
43+
44+
echo -e " ${RED}✗ init failed${RST}"
45+
echo "$out_init" | sed 's/^/ /'
46+
exit_code=1
47+
popd >/dev/null
48+
echo
49+
continue
50+
fi
51+
52+
# ---------- VALIDATE ----------
53+
set +e
54+
out_val="$(terraform validate "${VALIDATE_ARGS[@]}" 2>&1)"
55+
st_val=$?
56+
set -e
57+
58+
if [[ $st_val -eq 0 ]]; then
59+
for f in "${TFFILES[@]}"; do
60+
echo -e "${f}"
61+
echo -e " ${GRN}✓ Válido${RST}"
62+
echo
63+
done
64+
else
65+
echo -e " ${RED}✗ validate failed${RST}"
66+
echo "$out_val" | sed 's/^/ /'
67+
exit_code=1
68+
echo
69+
fi
70+
71+
popd >/dev/null
72+
done
73+
74+
exit "$exit_code"

0 commit comments

Comments
 (0)