lesson ── terraform-production ── ~14 мин ── 6 шагов
pre-commit is a Python framework for git hooks. You declare a set of checks
in .pre-commit-config.yaml, run pre-commit install, and now every
git commit runs fmt/validate/tflint before letting your changes into the
repo. The same config, in CI: pre-commit run --all-files.
интерактивный sandbox
Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.
stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя
cd /home/student/tf-precommit
git init -q
git config user.email "student@linuxlab.local"
git config user.name "student"
cat > main.tf <<'EOF'
resource "aws_s3_bucket" "demo" {bucket = "linuxlab-precommit-demo"
tags = {Owner = "student"
}
}
EOF
terraform fmt
git add .
git commit -q -m "init: clean hcl"
git log --oneline
One clean commit in the repo, the baseline.
✓ Git is initialized, a clean baseline is committed.
cat > .pre-commit-config.yaml <<'EOF'
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.95.0
hooks:
- id: terraform_fmt
- id: terraform_validate
- id: terraform_tflint
args:
- --args=--init
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
EOF
Notice: the hook ID is terraform_fmt, not just fmt. That is the
name from the antonbabenko/pre-commit-terraform repo, the de facto
standard for Terraform.
Install the hooks into git:
pre-commit install
ls .git/hooks/pre-commit
The file .git/hooks/pre-commit is now there. It is a wrapper that runs
pre-commit on every commit.
✓ The hook is installed, now git commit goes through pre-commit.
Drop in a deliberately messy file:
cat > badly.tf <<'EOF'
resource "aws_s3_bucket" "another" {bucket="bad-format"
}
EOF
git add badly.tf
set +e
git commit -m "feat: add another bucket"
echo "exit: $?"
set -e
The commit failed because terraform_fmt found a problem. pre-commit
applied the auto-fix itself, but the files stayed unstaged.
Check:
git status
cat badly.tf
badly.tf is now formatted, but git already sees it as "modified":
pre-commit changed it after git add.
✓ The hook auto-fixed the format. Without it the commit would have gone through with dirty HCL.
git add badly.tf
git commit -m "feat: add another bucket"
git log --oneline
Now pre-commit passes, the file is already clean. The commit is accepted.
In real work the cycle is: commit → hook fix → re-add → commit. The cleaner the code the developer wrote, the less re-add you need.
✓ A clean commit passed the pre-commit gate.
Add a reference to a resource that does not exist:
cat >> main.tf <<'EOF'
output "broken" {value = aws_s3_bucket.does_not_exist.arn
}
EOF
git add main.tf
set +e
git commit -m "feat: broken reference"
code=$?
set -e
echo "exit: $code"
It should fail on terraform_validate, a reference to a resource that
does not exist. This is not a format issue that auto-fix handles; it is a
semantic issue that needs a manual fix.
Roll it back:
git restore --staged main.tf
sed -i '/output "broken"/,/^}$/d' main.tf
cat main.tf
✓ validate rejected the broken HCL. Without pre-commit this would have reached plan in CI.
OpenTofu keeps its CLI and state compatible with Terraform for the
commands in this step: migration usually goes through mv .terraform .terraform.bak; tofu init -upgrade. On the first switch, though, back
up the state and run it on a feature branch, the divergences cluster in
the newer features (variables in the backend, state encryption,
OCI registry-backed modules). See tf-opentofu-parity for the full
matrix.
Locally the hooks fire on CHANGED files. In CI you need to run everything, since old files may also break the policy (especially right after you adopt pre-commit in a legacy repo).
pre-commit run --all-files
echo "exit: $?"
It should show passes. If someone committed by bypassing the hook
(--no-verify), --all-files would catch it.
This is the final CI step: pre-commit run --all-files, exit 1 on any
problem.
✓ The pre-commit gate works. Next, functional tests.
What else is in antonbabenko/pre-commit-terraform and why:
terraform_docs, auto-generates README.md with inputs/outputs.
Handy for modules; run it in CI with --args=--output-file so the
README updates when variables change.terraform_checkov, checkov inside pre-commit. Slow; usually
CI only.terraform_trivy, same idea as checkov, but trivy. Pick one of
the two.terraform_tfsec, deprecated, see tf-trivy-tfsec.terragrunt_fmt / terragrunt_validate, if you have a terragrunt
wrapper.infracost_breakdown, cost estimation. Needs an API token.The rule: the slower a hook is, the less of it in local pre-commit and the more in CI. Locally you want checks under 5 seconds.
pre-commit hooks into git via pre-commit install, reads
.pre-commit-config.yaml, and runs the hooks on commit. The Terraform
hooks come from antonbabenko/pre-commit-terraform: terraform_fmt,
terraform_validate, terraform_tflint, terraform_docs.
команды
pre-commit installwire the hooks into .git/hooks. Once, right after clone.pre-commit run --all-filesrun the whole repo. Use this to bootstrap an old project.SKIP=terraform_fmt git commitskip one hook. Only on purpose.pre-commit autoupdatebump the rev: versions in the config.концепции