Add hook scripts to run custom code around OpenTofu commands
What
Adds a hook script mechanism so users can run their own shell code around OpenTofu commands, without having to override a job's script: wholesale — which is currently the only option and is brittle.
Hook points: pre-init/post-init, pre-plan/post-plan, pre-apply/post-apply, pre-destroy/post-destroy.
Configured with a single hooks_dir input (and GITLAB_TOFU_HOOKS_DIR), defaulting to .gitlab/ci/hooks. A missing hook file is a no-op.
Design notes
Hooks are sourced, not executed, so a hook can export variables that affect the following tofu invocation. (For contrast, the equivalent feature in to-be-continuous/terraform executes hooks as subprocesses, which makes exporting impossible.)
post-* only runs on success; errexit means a failing hook fails the job with the hook's exit code. The plan branch was restructured slightly so that post-plan also runs for -detailed-exitcode's exit code 2, since a non-empty plan is not a failure.
gitlab-tofu apply -destroy maps onto the destroy hooks. templates/destroy.yml destroys via gitlab-tofu apply -destroy, so keying hooks on the CLI verb alone would have made pre-destroy/post-destroy unreachable in the actual destroy job.
Backwards compatibility with id_tokens_setup_script
templates/__internal_id_tokens_base_job.yml is byte-for-byte untouched. id_tokens_setup_script keeps working exactly as before and is not deprecated.
The resulting order is id_tokens_setup_script → pre-init → tofu init. Making pre-init run first was considered and rejected: it would require moving the sourcing into gitlab-tofu.sh, where it either stops running for commands that never init (delete-state, fmt, plan-json, bare passthroughs via custom-command) or runs once per gitlab-tofu invocation rather than once per job — and several templates invoke it twice per job (apply + output, plan + show), which would mean a second role assumption.
The chosen order is arguably the better one anyway: a pre-init hook then runs with the cloud credentials the id_tokens script established.
Testing
tests/integration-tests/HookScripts.gitlab-ci.yml(+tests/iac-hooks/fixture), registered on alpine and debian. Asserts the exact hook sequence per command, that a hook'sexportreachestofu, and thatid_tokens_setup_scriptstill works.- 5 new cases in
tests/unit/gitlab-tofu.bats. shellcheckclean;make docsidempotent;go test ./...green.
Known limitation
detect-drift and fetch-mr-plan fire only the init hooks, even though they internally run tofu plan / tofu apply -refresh-only. Deliberate for now — happy to extend if wanted.