Rewrite docs/RELEASE.md from scratch: a terms list, what is needed, and six numbered steps, each with its check. Every statement is checked against the Makefile, script/, build.js, the two workflows and the tests. The step that described distribution routes not built is cut; installing from the archives replaces it. The reproducibility claim now names the build date that build.js compiles in, so it holds only within one UTC day. Model: fable-5-1
6.9 KiB
Releasing AutistMask
A release is a tagged commit on main and the two archives that make package
writes from that commit. This file is the procedure, in order.
Nothing in this repository publishes. There is no store upload, no signing and no CRX (a CRX is Chrome's packaged extension file). Anyone can run the build and the packaging. Tagging is the owner's job (@sneak).
Terms
- The release commit is the commit on
mainto be released.mainreceives one pull request per milestone (the tracker's set of issues for one version), fromnext, and releases are tagged frommain(TODO.md, Workflow). - A clean checkout is a working tree at the release commit where
git status --porcelainprints nothing. The build stamps the commit hash into the extension and appends-dirtywhen the tree has local changes. - A tag is a name that git fixes to one commit. Release tags read
vX.Y.Z, such asv0.1.0. - A digest is the sha256 hash of a file (a fixed-length fingerprint of its bytes), written as 64 hex characters.
- A workflow is a list of jobs that the tracker runs on every push, from a file
under
.gitea/workflows/. The tracker lists the runs on the repository's Actions page.
What you need
- A clean checkout of the release commit.
make.- Docker, for
make check.make packageneeds no Docker. - Node and yarn. Both come from the system when present. Otherwise
make setupinstalls Node through a pinned install of nvm (a Node version manager) and yarn through corepack (Node's package manager installer).
Procedure
1. Confirm the release commit is green
The check workflow (.gitea/workflows/check.yml) runs script/cibuild on
every push. script/cibuild runs:
script/bootstrap, which installs the dependencies;script/check, which is whatmake checkruns: the tests, the lint checks and the formatting check. The lint checks are ESLint (a code checker), the prettier check (a formatting check) andscript/check-censored;- the Docker image build.
The e2e workflow (.gitea/workflows/e2e.yml) runs the two browser suites on
every push, as two jobs. A red e2e job does not fail the check run.
Check: on the Actions page, the check run for the release commit succeeded,
and both e2e jobs for that commit succeeded. make check on the clean
checkout gives the same answer as the check run.
2. Confirm the version
Three files declare the version:
package.json;manifest/chrome.json;manifest/firefox.json.
script/lib/version.js fails the build when the three disagree.
tests/version.test.js fails when the version is not three numbers separated by
dots. Nothing compares the version with a tag. That comparison is this step.
Check: all three files read the same X.Y.Z, and vX.Y.Z is the tag that step
5 creates.
3. Build and package
On the clean checkout, run:
make setup
make package
make setup installs two things:
- the dependencies, from the lockfile
yarn.lock, which pins each one's version; - the git pre-commit hook, a script that git runs before each commit. Here the
hook runs
script/check.
make package runs make build, then script/lib/package.js.
make build:
- runs
build.js, which writesdist/chrome/anddist/firefox/, and a build receipt: the list of every file thatbuild.jswrote, with each file's digest. The receipt lives outside the repository and is deleted when the build ends; - runs
script/verify-build --expect releaseagainst the receipt. The check fails when:dist/differs from the receipt;- a bundle (one JavaScript file built from many source files) was compiled
with the build-time constant
DEBUGon; - any file carries the fixed recovery phrase that a debug build hands out;
- runs
script/check-censored --require-distagainst the built files; - removes
dist/when any of those steps fails.
script/lib/package.js:
- empties
release/; - refuses a symbolic link (a file that points at another file) under
dist/; - checks that every file named by the manifest or the popup markup is inside the browser's directory;
- checks that the
versionin eachmanifest.jsonis the tree's version; - writes one archive per browser, reads it back and compares every member (a
file inside the archive) with
dist/byte for byte; - writes
SHA256SUMS: one line per archive with the digest, two spaces and the file name.
make package writes three files:
release/autistmask-chrome-<version>.zip
release/autistmask-firefox-<version>.xpi
release/SHA256SUMS
The .xpi is Firefox's add-on package file. It is not signed. The output line
Not shipped names dist/styles.css. build.js writes the compiled stylesheet
there and copies it into each browser directory. The copy at the root of dist/
is in neither archive. make clean removes dist/ and release/.
Check: release/ holds those three files, and <version> in their names is the
version from step 2.
4. Verify the digests
From release/, run sha256sum -c SHA256SUMS.
The archives are deterministic for a given dist/: script/lib/zip.js sorts
the members, sets every timestamp to 1980-01-01 and fixes the compression level.
dist/ itself carries the build date: build.js compiles the day of the build,
in UTC (universal time), into the extension, with the commit hash and the
version. So two builds of the same commit on the same UTC day give
byte-identical archives. Builds on different days differ.
Check: sha256sum -c prints OK for both archives. A second make package
from another clean checkout of the same commit, on the same UTC day, gives the
same SHA256SUMS.
5. Tag the release commit
Owner only. On the release commit, run:
git tag -a vX.Y.Z -m "AutistMask X.Y.Z"
git push origin vX.Y.Z
-a makes an annotated tag: a tag object with its own message, author and date.
v0.1.0 is one.
Once the tag exists, git describe --tags on the release commit prints
vX.Y.Z. script/cibuild and script/docker pass that value to the Docker
image build as VERSION.
Check: git rev-parse vX.Y.Z^{commit} prints the release commit's hash, and the
tracker lists the tag under the repository's tags.
6. Hand out the archives
The archives in release/ are the release. This repository has no further step.
Chrome loads the extension from a directory:
- unzip
autistmask-chrome-<version>.zip; - open
chrome://extensions/and turn on "Developer mode"; - click "Load unpacked" and pick the unzipped directory.
Chrome then reports the extension id gipbhkogfopeahplcjhipkgpcimdpkip, which
the key in manifest/chrome.json fixes.
Release builds of Firefox refuse to install an unsigned add-on. Desktop Firefox
115 or newer, in any edition, loads the .xpi as a temporary add-on from
about:debugging and unloads it when Firefox exits. The section "Installing on
Firefox" in README.md has the details.
Check: each archive installs on a fresh browser profile by the route above.