feat(tests): add per-test runtime pinning to the integration matrix - #405
Open
jsteinich wants to merge 2 commits into
Open
feat(tests): add per-test runtime pinning to the integration matrix#405jsteinich wants to merge 2 commits into
jsteinich wants to merge 2 commits into
Conversation
Implements the mechanism from open-constructs#337. A test can opt out of the default `tested` Terraform cross-product and declare the runtimes it needs instead, via `pinnedRuntimes` in tools/build-test-matrix.mjs. This is what lets OpenTofu into CI incrementally. Until now the only way to run anything against tofu was a full matrix leg across all 60+ targets, which requires open-constructs#208, open-constructs#301, open-constructs#392 and open-constructs#393 all resolved first. A pin runs one target against one CLI, so each of those can now be fixed and verified on its own, and coverage grows a test at a time. It also gives tests access to a newer Terraform than `tested` without moving the floor for everything. Matrix entries gain a `binary` field - the version-suffixed binary the CI image installs - and the workflow sets TERRAFORM_BINARY_NAME from it rather than string-concatenating "terraform" with a version. `terraform` stays the bare version for TERRAFORM_VERSION and remains what the terraform-cloud test reads (open-constructs#392). The plugin cache is now keyed by binary rather than version: OpenTofu resolves providers from registry.opentofu.org into the same TF_PLUGIN_CACHE_DIR, so a tofu run must not share an entry with a terraform run. Pins are validated against `.terraform.versions.json` at matrix-build time, so a typo fails the prepare job with a clear message instead of a "binary not found" deep inside a test run. First consumer: test/typescript/provider-features, pinned to Terraform 1.16.1 and OpenTofu 1.12.6 - the first OpenTofu job in this repo's CI. It covers the provider-defined functions binding end to end, which needs a CLI that emits `functions` in provider schemas (Terraform/OpenTofu >= 1.8) and so could not run at the old 1.6.5 ceiling. It uses hashicorp/time, which is mirrored on registry.opentofu.org and installs cleanly under both CLIs - deliberately not kreuzwerker/docker, which hits the signing problem in open-constructs#301. The disabled windows_integration job consumes the same matrix and would try to install Terraform for a tofu-pinned entry; noted in place rather than building OpenTofu support for a job that does not run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jsteinich
commented
Sep 9, 2026
Addresses review feedback on open-constructs#405: dropped the cache-key comment in integration.yml, shortened the pinnedRuntimes docblock to what the reader needs at the declaration, and removed the `binary` paragraph from the include docblock. The rationale lives in the PR and commit history. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jsteinich
marked this pull request as ready for review
September 9, 2026 19:42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issue
Implements the mechanism from #337. First step toward OpenTofu coverage.
Description
A test can now opt out of the default
testedTerraform cross-product and declare the runtimes it needs, viapinnedRuntimesintools/build-test-matrix.mjs:Why this first. Until now the only way to run anything against OpenTofu was a full matrix leg across all 60+ targets, which needs #208, #301, #392 and #393 all resolved before a single tofu job can be green. A pin runs one target against one CLI, so each of those blockers can now be fixed and verified independently and tofu coverage grows a test at a time. It also gives an individual test a newer Terraform than
testedwithout moving the floor for everything — which is what #312 needs.To be clear about what this does and does not do: it does not fix any of the four blockers. It makes them separately fixable.
Mechanism
Matrix entries gain a
binaryfield — the version-suffixed binary the CI image installs — and the workflow setsTERRAFORM_BINARY_NAMEfrom it rather than string-concatenating"terraform"with a version.terraformstays the bare version, soTERRAFORM_VERSIONand the cache-key semantics are unchanged for existing entries.The plugin cache is now keyed by binary rather than version. OpenTofu resolves providers from
registry.opentofu.orginto the sameTF_PLUGIN_CACHE_DIR, so a tofu run must not share a cache entry with a terraform run.Pins are validated against
.terraform.versions.jsonwhen the matrix is built, so a typo fails theprepare-integration-testsjob with a clear message rather than a "binary not found" deep inside a test run.First consumer
test/typescript/provider-features, pinned to Terraform 1.16.1 and OpenTofu 1.12.6 — the first OpenTofu job in this repo's CI. It covers the provider-defined functions binding end to end:provider.functions.rfc3339Parse(...)must synthesize to aprovider::time::rfc3339_parse(...)expression rather than resolving at synth time. That needs a CLI that emitsfunctionsin provider schemas (Terraform/OpenTofu >= 1.8), so it could not have run at the old 1.6.5 ceiling at all.It uses
hashicorp/time, which is mirrored onregistry.opentofu.organd installs cleanly under both CLIs — deliberately notkreuzwerker/docker, which hits the signing problem in #301.Testing
The matrix builder cannot run natively on Windows (pre-existing:
execFileSync("npx")needs.cmd, and thetestDirprefix strip assumes forward slashes), so I verified the pin logic against a stubbed target list:The pinned target gets exactly its two entries and no default cross-product; non-pinned targets are unchanged, including the HCL doubling. Pin validation confirmed to fail fast:
I could not run the new integration test locally — it needs
pnpm packageand the integration harness, andpipenv/rsyncare unavailable on this machine. This PR's own CI run is the verification for the test itself, and it is the interesting part: the tofu job is the first of its kind here.Known gap
The disabled
windows_integrationjob consumes the same matrix and would try to install Terraform for a tofu-pinned entry. Noted in place rather than building OpenTofu support into a job guarded byif: false.Follow-ups this unblocks
🤖 Generated with Claude Code