Publishing a release¶
Releases are cut from main in ethereumclassic/core-geth. The master branch is gone and the previous etclabscore remote is not this project’s to publish to.
v1.13.0-rc1 is used as the worked example below.
Before the tag¶
-
mainis green.make lint,make testandmake test-coregethall pass. The release artifacts are produced by CI, so a red pipeline means no artifacts rather than a bad release. - Set the release stage. Edit
params/version.gosoVersionMetanames the stage being cut:unstable→RC1,RC2, … →stable. It must never be empty: the archive and version helpers branch on!= "stable", so an empty value produces a malformed1.13.0--<commit>name rather than a clean one. Checkgofmtafter editing; the constant block realigns. - Commit and push it, then let CI finish before tagging. The tag should point at a commit CI has already judged.
Cut the tag¶
1 2 | |
Creating a v* tag is restricted to repository admins by a ruleset, so this push reports a bypass. That restriction is what the build attestation rests on. An attestation binds an archive to the run that produced it, but only the tag rule decides who may start such a run.
A release tag is immutable. Do not move or delete one after artifacts exist: the attestations are written to a public append-only log, so a reused tag name ends up bound to two different artifacts with no way to tell which is which. If a tag is wrong, cut the next one.
What the tag triggers¶
| Workflow | Produces |
|---|---|
release-packages.yml | 18 archives: 9 platforms × (geth, alltools), each with a .sha256 and a build attestation. A single publish job uploads all of them to one draft release once every build has finished |
docker-publish.yml | multi-architecture images for linux/amd64 and linux/arm64, pushed to GHCR, then the images saved as four .tar.gz files, each with a .sha256 and a build attestation, attached to the draft release. It waits for that draft, and stops if more than one release carries the tag |
A tag whose name contains a hyphen is treated as a prerelease: the GitHub release is marked as one, and the container image does not take :latest. Only a full release such as v1.13.0 takes the moving tag.
Before publishing the draft¶
- All 18 archives and the four image tarballs are attached, and each
.sha256matches its file. - The archive names carry the tag, not a commit SHA. A bare SHA means the tag was not present in the build checkout.
-
The attestation verifies against a downloaded archive, which is a different claim from the workflow step having gone green:
1$ gh attestation verify core-geth-linux-v1.13.0-rc1.zip --repo ethereumclassic/core-geth -
Load an image tarball. Its attestation verifies, it loads under the published name, and the config digest its
manifest.jsonnames equals the image ID the release run’s save job logged for that architecture. Compare those two, notdocker image inspect’s ID: a Docker using the containerd image store reports the manifest digest there instead:1 2 3 4
$ gh attestation verify core-geth-docker-amd64-<tag>.tar.gz --repo ethereumclassic/core-geth $ docker load -i core-geth-docker-amd64-<tag>.tar.gz $ docker run --rm ghcr.io/ethereumclassic/core-geth:<tag> version $ tar -xOzf core-geth-docker-amd64-<tag>.tar.gz manifest.json # "Config": "blobs/sha256/<digest>" -
Spot-check a binary. It should report the version you set and a commit date, its glibc floor should be the one the build targets rather than the runner’s, and its Go version should be the patch
build/checksums.txtpins, the same in every archive:1 2 3
$ ./geth version $ objdump -T geth | grep -o 'GLIBC_[0-9.]*' | sort -uV | tail -1 $ go version geth -
Every archive carries
COPYINGbeside its binaries:1$ unzip -l core-geth-linux-<tag>.zip -
The Windows and macOS metadata checks passed. The release run’s Verify the Windows version information and Verify the macOS minimum version steps are green. On Windows, the Details tab of
geth.exe’s Properties shows Core-Geth, the version and Ethereum Classic DAO LLC. -
The published image index carries its annotations: description, source, vendor and documentation:
1$ docker buildx imagetools inspect --raw ghcr.io/ethereumclassic/core-geth:<tag> -
Regenerate the
--helpdump. From a localmake gethat this tag, replace the dump inrun-cli.mdwith this command’s output in full, never by hand.HOME='~'keeps the builder’s real home directory out of the printed defaults:1$ HOME='~' build/bin/geth --help -
Regenerate the JSON-RPC module pages (
docs/JSON-RPC-API/modules/*.md), from the same checkout, never by hand:1$ make docs-generate -
Test the example code on Adding a network. Its five Go files are not in the repository: add them under
params/in the same checkout, run the page’s test command from the repository root, then remove them:1$ go test ./params/ -run 'TestGenesisHashABC|TestABCBootnodes|ExampleDefaultABCGenesisBlock' -count=1 -v -
A second person has reviewed the notes, the artifact list and the fingerprints.
- For a full release, create the archive branch. The migration guide tells readers to clone
archive-release-<version>, and points them at the releases page when that clone fails. Creating the branch is what makes the documented build path work. Not applicable to a release candidate; the branch is cut with the full release.
After publishing¶
- Set
VersionMetato the next stage and push that commit. - For a first-ever image push, confirm the GHCR package visibility. A registry creates new packages private by default, so nothing is pullable until it is made public, and making it public is the moment every tag it carries starts serving real traffic. Check what
:latestpoints at before flipping it.