Releasing Test Fixtures¶
This page covers the mechanics of cutting a test fixture release. For the release types, their versioning, and consumption guidance, see EELS Fixture Releases.
Fixture releases are produced by manually dispatching the release_fixtures.yaml workflow. There is no tag to push by hand. The workflow builds the fixtures and, only on success, drafts the GitHub release; publishing the draft creates the tag.
Inputs¶
| Input | Required | Description |
|---|---|---|
feature |
yes | Feature name, e.g. tests, benchmark, or a <feat>-devnet name. |
version |
yes | Release version vX.Y.Z (validated against ^v[0-9]+\.[0-9]+\.[0-9]+$). Tagged as tests-<feature>@<version> (the tests feature tags as tests@<version>). |
branch |
for *-devnet |
Branch to build and release from (any branch). Defaults to the dispatch ref for other fresh fills; must be empty for cached releases. |
evm |
no | Override the evm impl (e.g. geth, evmone). Defaults to the feature's evm-type in feature.yaml. |
evm_repo |
no | Override the t8n tool repo (e.g. ethereum/go-ethereum). |
evm_ref |
no | Override the t8n tool branch / tag / commit. |
cached |
no | Draft from the newest nightly artifact instead of refilling (tests only): build and combine are skipped and the tag targets the nightly's commit. See Cached releases. |
commit |
no | Release the nightly built at this commit (7+ hex chars) instead of the newest one; implies cached. |
<feature> must be a key in .github/configs/feature.yaml (e.g. tests, benchmark), or a <feat>-devnet name that resolves to the shared devnet feature.
Input validation runs in generate_build_matrix.py (unit-tested) before any fixtures are built, and fails fast on:
- an empty
featureor aversionthat is notvX.Y.Z; - an
evmoverride that is not a key in.github/configs/evm.yaml; - a bare
devnetfeature name (must carry a<feat>-prefix, e.g.bal-devnet); - a
<feat>-devnet-<n>feature name — the devnet index belongs in theversionmajor, not the feature name (sofeature=bal-devnet-7is rejected in favour offeature=bal-devnet version=v7.0.0); - a
*-devnetrelease missing abranch; abranchunderdevnets/that does not followdevnets/<feat>/<n>(e.g.devnets/bal/7-benchmark); or adevnets/<feat>/<n>branch whose devnet number<n>does not equal theversionmajor (sofeature=bal-devnet branch=devnets/bal/7must useversion=v7.*.*). A branch outsidedevnets/(e.g.eips/amsterdam/eip-8141) carries no number to check and is accepted as-is.
Devnet releases¶
Devnet releases must use a <feat>-devnet feature name (e.g. feature=bal-devnet) and must specify the branch to release from. Any branch works: a dedicated devnets/<feat>/<n> branch (e.g. devnets/bal/7), or the EIP feature branch itself (e.g. eips/amsterdam/eip-8141) when the devnet tracks it one-to-one.
The version major is the devnet number (see the Versioning Scheme): the <n> of the <feat>-devnet-<n> the fixtures target, so a frames-devnet-0 release is v0.*.*. A devnets/<feat>/<n> branch encodes that number and a mismatched major is rejected, so branch=devnets/bal/7 must use version=v7.*.*. Any other branch is not checked, so take the major from the devnet name yourself:
gh workflow run release_fixtures.yaml -f feature=bal-devnet -f version=v7.0.0 -f branch=devnets/bal/7
gh workflow run release_fixtures.yaml -f feature=frames-devnet -f version=v0.1.0 -f branch=eips/amsterdam/eip-8141
The selected branch supplies the release scripts
The setup job checks out branch first and runs the input validation and build-matrix script from that tree, so gh workflow run --ref only selects the workflow file. The selected branch must itself contain the current release scripts: rebase it onto its forks/<fork> base (or cherry-pick the scripts onto it) before releasing. A stale branch also fills without whatever landed on the base since.
What the workflow produces¶
On success the workflow:
- Builds
fixtures_<feature>.tar.gz(thetestsfeature buildsfixtures.tar.gz) for the resolved feature (per itsevm-typeandfill-paramsinfeature.yaml). - Drafts a pre-release to
ethereum/execution-specswith the fixture tarball(s) attached, titled and taggedtests-<feature>@vX.Y.Z(thetestsfeature tags astests@vX.Y.Z, no doubled prefix). - Targets the tag at the released commit (the SHA resolved once from the
branchHEAD when given, otherwise the dispatch commit). The tag name and target are stored as draft metadata; the git tag itself is only created when the draft is published, so an unpublished draft can be edited or deleted without leaving a tag behind.
| Example dispatch | Git tag | Release title | Artifact |
|---|---|---|---|
feature=tests version=v24.0.0 |
tests@v24.0.0 |
tests@v24.0.0 |
fixtures.tar.gz |
feature=bal-devnet version=v7.0.0 branch=devnets/bal/7 |
tests-bal-devnet@v7.0.0 |
tests-bal-devnet@v7.0.0 |
fixtures_bal-devnet.tar.gz |
feature=frames-devnet version=v0.1.0 branch=eips/amsterdam/eip-8141 |
tests-frames-devnet@v0.1.0 |
tests-frames-devnet@v0.1.0 |
fixtures_frames-devnet.tar.gz |
The release is created as a draft; review and publish it from the GitHub releases page.
Cutting a release¶
- Pick the next version per the Versioning Scheme for the feature you're releasing (e.g. the next
testsrelease aftertests@v24.1.0istests@v24.1.1for a non-breaking/new-tests bump, ortests@v24.2.0for a consensus-breaking spec change). - Dispatch the workflow from the Actions tab or via the CLI:
gh workflow run release_fixtures.yaml -f feature=tests -f version=v24.1.1
# devnet releases additionally require the branch (any branch; the major
# must match the devnet number of a devnets/<feat>/<n> branch):
gh workflow run release_fixtures.yaml -f feature=bal-devnet -f version=v7.0.0 -f branch=devnets/bal/7
gh workflow run release_fixtures.yaml -f feature=frames-devnet -f version=v0.1.0 -f branch=eips/amsterdam/eip-8141
- Wait for the build to succeed. On success the workflow drafts the GitHub release with the fixture tarball attached. If any job fails, no release is drafted: fix the cause and re-dispatch.
- Review and publish the draft. Open the draft on the releases page, check the auto-generated notes (anchored at the prior release on the same feature via
--notes-start-tag), and click Publish release when ready. Publishing creates thetests-<feature>@vX.Y.Ztag on the target commit; until then a mispicked version can be fixed by editing the draft, with no stray tag to delete. Publishing also triggers the hive simulator images workflow, which builds the release's fixture, tests and simulator images and moves the channel tags the release owns.
Release features opt into all fixture formats via feature.yaml
Tarball output (.tar.gz) does not by itself include the pre-allocation group formats (BlockchainEngineXFixture, BlockchainEngineStatefulFixture). A release feature requests them by adding --generate-all-formats to its fill-params in .github/configs/feature.yaml:
Nightly fill¶
The same workflow also runs on a nightly schedule (02:00 UTC) as a release rehearsal: it fills the tests feature (all tests, slow included, all fixture formats, per its fill-params in feature.yaml) through the exact release pipeline, but stops after combine, so no tag or release is created. Each run uploads a fixtures_<commit> workflow artifact (short hash of the built commit, containing fixtures.tar.gz) with a 5-day retention: a rotating, always-available build of the tests fixtures, effectively a tests@ release candidate on demand. A scheduled run skips itself when there are no new commits since the last nightly that actually filled — a skipped or failed nightly never advances that baseline, so no commit slips through unfilled. A quiet stretch without commits still re-fills once the last fill is four days old, or its artifact is gone, so a live artifact always exists within the five-day retention.
Cached releases¶
A tests@ release can reuse the newest nightly artifact instead of refilling: tick the cached checkbox in the dispatch UI, or pass the flag on the CLI:
gh workflow run release_fixtures.yaml -f feature=tests -f version=vX.Y.Z -f cached=true
# or release the nightly built at a specific commit (implies cached):
gh workflow run release_fixtures.yaml -f feature=tests -f version=vX.Y.Z -f commit=<hash>
The build and combine jobs are skipped; the release job downloads the fixtures_<commit> artifact from the newest nightly run that actually filled — or, with the commit input, from the nightly built at that commit — and drafts the same release a fresh fill would produce, targeted at the exact commit the nightly built, so publishing it creates the tests@vX.Y.Z tag on that commit. The whole run takes minutes on a hosted runner. Review and publish the draft exactly as in Cutting a release.
The cached path's validation (unit-tested in resolve_cached_release.py) fails fast when:
- the
featureis nottests, or abranchis given (the nightly fills the default branch); - the
versionis notvX.Y.Zor does not exceed the newest existingtests@tag; - no nightly run with a live
fixtures_<commit>artifact exists — or none matching thecommitinput; the error lists the reusable nightlies (artifacts are retained for five days: past that, dispatch a fresh fill); - the resolved nightly does not contain the newest existing
tests@release (a cached release must never regress content; re-releasing the identical commit is allowed); - the nightly's commit is not an ancestor of the current default branch head.
A cached release contains exactly what the resolved nightly filled: commits that landed after it are not included, and the run's step summary lists them so the releaser can decide between the cached artifact and a fresh fill.