Skip to content

feat: Adding e2e hook tests#990

Open
pen-pal wants to merge 8 commits into
antonbabenko:masterfrom
pen-pal:feat/823-e2e-hook-tests
Open

feat: Adding e2e hook tests#990
pen-pal wants to merge 8 commits into
antonbabenko:masterfrom
pen-pal:feat/823-e2e-hook-tests

Conversation

@pen-pal
Copy link
Copy Markdown
Contributor

@pen-pal pen-pal commented May 28, 2026

  • This PR introduces breaking change.
  • This PR fixes a bug.
  • This PR adds new functionality.
  • This PR enhances existing functionality.

Description of your changes

Increment toward #823: a behavioral end-to-end test harness for the hooks. It runs each hook the way a user would - through pre-commit against fixture files — and compares the result against a committed "golden" output tree.

Addresses #823 (lays the foundation and seeds it with two hooks). It does not close the issue, since most hooks still need cases.

Harness - tests/e2e/run_e2e_tests.sh

  • Auto-discovers tests/e2e/cases/<hook_id>/<case_name>/. Adding a hook is just adding a dir — no runner changes.
  • Per case: builds a temp git repo from input/, renders the case's .pre-commit-config.yaml (__PCT_REPO__ → checkout root), runs the hook via
    pre-commit run --all-files.
  • A case passes when the exit code matches expected_returncode (default 0) and the working tree is byte-identical to expected/.
  • Optional requires file skips a case when a needed CLI tool is absent.

Seed cases

Hook Case Asserts
terraform_fmt reformats-misaligned-hcl misaligned HCL is reformatted; pre-commit exits 1 (hook modifies a tracked file)
terraform_wrapper_module_for_each generates-wrapper-for-root-module wrappers/{main,outputs,variables,versions}.tf + README.md generated for a

CI - .github/workflows/e2e-tests.yaml
Runs the suite on every PR inside the published multi-tool image (ghcr.io/antonbabenko/pre-commit-terraform:latest). The image supplies the tooling (terraform, hcledit, …); the hook and test code come from the checkout, so the image tag need not be in sync.

How can we test changes

Locally (needs pre-commit, git, and the hooks' tools — terraform, hcledit):

bash tests/e2e/run_e2e_tests.sh
# => 2 passed, 0 failed, 0 skipped

Inside the project image (matches CI):

docker build -t pct:e2e --build-arg INSTALL_ALL=true .
docker run --rm -v "$PWD:/lint" -w /lint --entrypoint bash pct:e2e \
  tests/e2e/run_e2e_tests.sh

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e112f457-6c1f-4c81-8670-832deb443e1f

📥 Commits

Reviewing files that changed from the base of the PR and between 235410e and a6052ac.

📒 Files selected for processing (18)
  • .github/workflows/e2e-tests.yaml
  • tests/e2e/README.md
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/.pre-commit-config.yaml
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/expected/main.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/expected_returncode
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/input/main.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/requires
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/.pre-commit-config.yaml
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/versions.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/README.md
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/outputs.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/variables.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/versions.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/input/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/input/versions.tf
  • tests/e2e/run_e2e_tests.sh
✅ Files skipped from review due to trivial changes (7)
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/input/versions.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/main.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/requires
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/expected_returncode
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/versions.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/main.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/.pre-commit-config.yaml
🚧 Files skipped from review as they are similar to previous changes (10)
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/expected/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/.pre-commit-config.yaml
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/outputs.tf
  • tests/e2e/README.md
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/versions.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/input/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/README.md
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/input/main.tf
  • .github/workflows/e2e-tests.yaml
  • tests/e2e/run_e2e_tests.sh

📝 Walkthrough

Summary by CodeRabbit

  • Tests

    • Added comprehensive end-to-end test suite for Terraform hooks with automated test case discovery and validation.
    • Added new test cases for Terraform formatting and module wrapper generation.
  • Chores

    • Added GitHub Actions workflow to run end-to-end tests on pull requests, pushes, and merge groups.
    • Added documentation for the end-to-end testing framework and how to add new test cases.

Walkthrough

Adds end-to-end test infrastructure: a bash test runner, README, GitHub Actions workflow, and two terraform-focused e2e cases (terraform_fmt and terraform_wrapper_module_for_each) with inputs, expected outputs, and requires files.

Changes

End-to-End Test Infrastructure

Layer / File(s) Summary
E2E Test Framework Documentation
tests/e2e/README.md
Documents case layout (.pre-commit-config.yaml, input/, expected/, expected_returncode, requires), execution/validation rules (exit code + byte-identical output), skip behavior for missing tools, and how to add cases.
Runner: init and setup
tests/e2e/run_e2e_tests.sh
Script header, strict mode, path resolution, TTY-aware colors, and test counters/summary initialization.
Runner: per-case execution
tests/e2e/run_e2e_tests.sh
Implements run_case: renders per-case config, creates isolated temp git fixture from input/, runs pre-commit run --all-files, captures output, validates exit code vs expected_returncode, compares produced tree vs expected/ via git diff --no-index, reports PASS/FAIL/SKIP, and cleans up.
Runner: discovery and orchestration
tests/e2e/run_e2e_tests.sh
Implements main: discovers case directories, iterates cases, aggregates summary, and invokes the script entrypoint.
CI Execution Workflow
.github/workflows/e2e-tests.yaml
GitHub Actions workflow triggered on merge_group/pull_request/push (with branch exclusions), pulls a pinned Docker image, mounts the repo at /lint, runs the e2e runner with permissions.contents: read, concurrency cancellation, and a 10-minute timeout.
terraform_fmt Test Case
tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/
Adds .pre-commit-config.yaml, input/main.tf, expected/main.tf, expected_returncode (1), and requires (terraform) to validate terraform_fmt reformatting behavior.
terraform_wrapper_module_for_each Test Case
tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/
Adds .pre-commit-config.yaml, input/main.tf, input/versions.tf, and expected outputs including main.tf, versions.tf, and wrappers/ (README, main.tf, outputs.tf, variables.tf, versions.tf) to validate wrapper-module generation with provided args.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • antonbabenko
  • MaxymVlasov
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main change: adding end-to-end hook tests infrastructure and seed cases, which is the primary focus of this changeset.
Description check ✅ Passed The description is detailed and directly related to the changeset, explaining the test harness implementation, seed cases, CI integration, and testing instructions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e-tests.yaml:
- Around line 31-33: The workflow uses env.IMAGE set to
ghcr.io/antonbabenko/pre-commit-terraform:latest which allows image drift;
change the IMAGE value to a digest-pinned reference
(ghcr.io/antonbabenko/pre-commit-terraform@sha256:<digest>) so the e2e runner
always pulls an immutable artifact, updating any references to IMAGE used in the
workflow (the env block and any docker pull/docker run invocations); obtain the
exact sha256 digest for the desired image tag via a docker registry query or
docker pull + docker inspect (or GHCR API) and replace :latest with
`@sha256`:<digest>.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0f0b0b52-8698-431c-922f-5536c499b88a

📥 Commits

Reviewing files that changed from the base of the PR and between c838f02 and cdebf54.

📒 Files selected for processing (18)
  • .github/workflows/e2e-tests.yaml
  • tests/e2e/README.md
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/.pre-commit-config.yaml
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/expected/main.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/expected_returncode
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/input/main.tf
  • tests/e2e/cases/terraform_fmt/reformats-misaligned-hcl/requires
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/.pre-commit-config.yaml
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/versions.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/README.md
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/outputs.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/variables.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/expected/wrappers/versions.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/input/main.tf
  • tests/e2e/cases/terraform_wrapper_module_for_each/generates-wrapper-for-root-module/input/versions.tf
  • tests/e2e/run_e2e_tests.sh

Comment thread .github/workflows/e2e-tests.yaml
@pen-pal pen-pal changed the title e2e hook tests feat: Adding e2e hook tests May 28, 2026
Copy link
Copy Markdown
Collaborator

@yermulnik yermulnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution.
I'm out of context around tests and therefore I've added solely tech comments around Bash code.

Comment thread tests/e2e/run_e2e_tests.sh Outdated
Comment thread tests/e2e/run_e2e_tests.sh Outdated
Comment thread tests/e2e/run_e2e_tests.sh Outdated
Comment thread tests/e2e/run_e2e_tests.sh Outdated
Comment thread tests/e2e/run_e2e_tests.sh Outdated
Comment thread tests/e2e/run_e2e_tests.sh Outdated
pen-pal added a commit to pen-pal/pre-commit-terraform that referenced this pull request May 29, 2026
Per review on antonbabenko#990:
- replace the `RETURN` trap with explicit cleanup at the function's single
  exit (the `RETURN` trap is Bash-only and confused reviewers);
- read the expected return code with `$(< file)` instead of `$(cat file)`;
- quote the `true`/`false` flag values to avoid confusion with the builtins;
- use `&>` instead of `> ... 2>&1`;
- drop the redundant trailing slash on the copy destination;
- print the summary with `printf` instead of a loop.

No behavior change; the suite still passes natively and inside the image.

Signed-off-by: penpal <unameme@proton.me>
pen-pal added a commit to pen-pal/pre-commit-terraform that referenced this pull request May 29, 2026
Per review on antonbabenko#990, pin `ghcr.io/antonbabenko/pre-commit-terraform` by
`sha256` digest instead of the floating `:latest` tag, so the bundled
toolchain can't drift between runs. A Renovate annotation keeps the digest
updated.

Signed-off-by: penpal <unameme@proton.me>
Copy link
Copy Markdown
Collaborator

@yermulnik yermulnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MaxymVlasov Shell code looks good to me, though I'm not really good with the rest of the tests logic — could you please have a look when you've got a moment? Thank you.

pen-pal added 8 commits May 30, 2026 10:55
Introduce `tests/e2e/run_e2e_tests.sh`, a behavioral test runner that
exercises each hook the way a user would -- through `pre-commit` against
fixture files -- and compares the result against a committed golden tree.

It auto-discovers `cases/<hook>/<case>/`, builds a temp git repo from
`input/`, renders the case's `.pre-commit-config.yaml` (`__PCT_REPO__` ->
checkout root), runs the hook via `pre-commit run --all-files`, then
asserts the exit code matches `expected_returncode` (default 0) and the
working tree is byte-identical to `expected/`. The tree compare uses
`git diff --no-index` so it works with the BusyBox `diff` shipped in the
project image. A `requires` file skips a case when a needed CLI tool is
absent.

Part of antonbabenko#823.

Signed-off-by: penpal <unameme@proton.me>
Add `generates-wrapper-for-root-module`: a root module (with no
`provider_meta`) is wrapped, and the generated
`wrappers/{main,outputs,variables,versions}.tf` plus `README.md` are
checked against the golden tree. Exits 0 (only new files are created).

Part of antonbabenko#823.

Signed-off-by: penpal <unameme@proton.me>
Add `reformats-misaligned-hcl`: misaligned HCL is rewritten to canonical
style. The hook modifies a tracked file, so `pre-commit` exits 1
(`expected_returncode=1`). The case requires `terraform`.

Part of antonbabenko#823.

Signed-off-by: penpal <unameme@proton.me>
Add `.github/workflows/e2e-tests.yaml`. Checkout runs on the host (the JS
action needs Node), then the suite runs inside the published multi-tool
image (`ghcr.io/antonbabenko/pre-commit-terraform:latest`), which supplies
terraform/hcledit/pre-commit while the hook and test code come from the
checkout -- so the image tag need not be in sync.

Part of antonbabenko#823.

Signed-off-by: penpal <unameme@proton.me>
Add `tests/e2e/README.md` describing the case layout, how to run the suite
natively and inside the project image, and how to add a new case.

Part of antonbabenko#823.

Signed-off-by: penpal <unameme@proton.me>
Per review on antonbabenko#990:
- replace the `RETURN` trap with explicit cleanup at the function's single
  exit (the `RETURN` trap is Bash-only and confused reviewers);
- read the expected return code with `$(< file)` instead of `$(cat file)`;
- quote the `true`/`false` flag values to avoid confusion with the builtins;
- use `&>` instead of `> ... 2>&1`;
- drop the redundant trailing slash on the copy destination;
- print the summary with `printf` instead of a loop.

No behavior change; the suite still passes natively and inside the image.

Signed-off-by: penpal <unameme@proton.me>
Per review on antonbabenko#990, pin `ghcr.io/antonbabenko/pre-commit-terraform` by
`sha256` digest instead of the floating `:latest` tag, so the bundled
toolchain can't drift between runs. A Renovate annotation keeps the digest
updated.

Signed-off-by: penpal <unameme@proton.me>
Signed-off-by: penpal <unameme@proton.me>
@pen-pal pen-pal force-pushed the feat/823-e2e-hook-tests branch from 235410e to a6052ac Compare May 30, 2026 05:10
Copy link
Copy Markdown
Collaborator

@MaxymVlasov MaxymVlasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for introducing this simple but powerful e2e test strategy!

I have a few requests for you before we proceed.

env:
# renovate: datasource=docker depName=ghcr.io/antonbabenko/pre-commit-terraform
# yamllint disable-line rule:line-length
IMAGE: ghcr.io/antonbabenko/pre-commit-terraform:latest@sha256:4ef4b8323b27fc263535ad88c9d2f20488fcb3b520258e5e7f0553ed5f6692b5
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we pin it to hash, then there's no sense to use the latest at all, which contradicts the main idea - test againt latest tool set & against the latest stable hook version.

In other words, we need 2 tests: against latest w/o pinning and against the latest available hook version, which can be bumped by renovate, but I'd like to have it as part of the release process.

Comment thread tests/e2e/README.md

Behavioral tests that run the hooks the same way a user would — through
`pre-commit` against real fixture files — and compare the result against a
committed "golden" output. See [issue #823][issue-823].
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never understand the idea of complicating things like this. It is used only in 1 place.

Suggested change
committed "golden" output. See [issue #823][issue-823].
committed "golden" output. For details see [issue #823](https://github.com/antonbabenko/pre-commit-terraform/issues/823).

Comment thread tests/e2e/README.md
&& tar -xzf hcledit.tar.gz hcledit && rm hcledit.tar.gz && sudo mv hcledit /usr/bin/
```

See the repo [README "How to install"](../../README.md#how-to-install) for the
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
See the repo [README "How to install"](../../README.md#how-to-install) for the
See the repo [README "How to install"](/README.md#how-to-install) for the

Comment thread tests/e2e/README.md
Comment on lines +71 to +72
docker build -t pct:e2e --build-arg INSTALL_ALL=true .
docker run --rm -v "$PWD:/lint" -w /lint --entrypoint bash pct:e2e \
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And what's the reason to build a separate image?

Just use a exisitng one https://github.com/antonbabenko/pre-commit-terraform#1-install-dependencies

Comment thread tests/e2e/README.md
Comment on lines +87 to +88

[issue-823]: https://github.com/antonbabenko/pre-commit-terraform/issues/823
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[issue-823]: https://github.com/antonbabenko/pre-commit-terraform/issues/823

Comment thread tests/e2e/README.md
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a section about requesting the addition of e2e hooks to https://github.com/antonbabenko/pre-commit-terraform/blob/master/.github/CONTRIBUTING.md#add-new-hook

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants