docs: second rework of the release procedure after review
check / check (push) Canceled after 0s
e2e / e2e-chrome (push) Canceled after 0s
e2e / e2e-firefox (push) Canceled after 0s

Apply the five wording findings of the second review verbatim: the owner's
rule as one lead-in with three acts, the yarn source without a pronoun, the
workflow definition with its file first, the two e2e jobs named with their
scripts, and the manifest version tied to step 2. The same three faults
were fixed elsewhere: pronouns with two candidates, phrases that arrive
after the words they belong to, and terms used before they were defined.

Model: fable-5-1
This commit is contained in:
2026-11-02 03:34:38 +00:00
parent c45cf628a9
commit fd53737403
+41 -34
View File
@@ -1,13 +1,13 @@
# Releasing AutistMask # Releasing AutistMask
A release is a tagged commit on `main` and the two archives that `make package` A release is a tagged commit on the `main` branch and the two archives that
writes from that commit. This file is the procedure, in order. `make package` writes from that commit. This file is the procedure, in order.
The owner ([@sneak](https://sneak.berlin)) alone decides three things: Only the owner ([@sneak](https://sneak.berlin)):
- whether and when a release is tagged; - decides whether and when a release is tagged;
- the tags: only the owner creates, moves or deletes a tag; - creates, moves or deletes a tag;
- where the archives are published. - decides where the archives are published.
Anyone can run steps 1 to 4. No script in this repository uploads or publishes Anyone can run steps 1 to 4. No script in this repository uploads or publishes
the archives. None signs them, and none packs a CRX (Chrome's packaged extension the archives. None signs them, and none packs a CRX (Chrome's packaged extension
@@ -16,16 +16,17 @@ file).
## Terms ## Terms
- The tracker is the repository's Gitea site (Gitea is the software that hosts - The tracker is the repository's Gitea site (Gitea is the software that hosts
the repository): https://git.eeqj.de/sneak/AutistMask. Its Actions page, the repository): https://git.eeqj.de/sneak/AutistMask. The tracker's Actions
https://git.eeqj.de/sneak/AutistMask/actions, lists the workflow runs. page, https://git.eeqj.de/sneak/AutistMask/actions, lists the workflow runs.
- A workflow is a list of jobs that the tracker runs on every push, from a file - A workflow is a file under `.gitea/workflows/` that lists jobs. The tracker
under `.gitea/workflows/`. Each job runs one script on the tracker's runner runs every workflow on each push. Each job runs one script on the tracker's
(the machine that runs jobs). runner (the machine that runs jobs).
- The release commit is a commit on `main`. Releases are tagged from `main` only - The release commit is a commit on `main`. Releases are tagged from `main` only
(`TODO.md`, Workflow). (`TODO.md`, Workflow).
- A clean checkout is a working tree at the release commit where - A clean checkout is a working tree (the checked-out files) at the release
`git status --porcelain` prints nothing. The build stamps the commit hash into commit where `git status --porcelain` prints nothing. The build stamps the
the extension and appends `-dirty` when the tree has local changes. commit hash (the commit's id) into the extension and appends `-dirty` when the
tree has local changes.
- A tag is a name that git attaches to one commit. Release tags read `vX.Y.Z`, - A tag is a name that git attaches to one commit. Release tags read `vX.Y.Z`,
such as `v0.1.0`. such as `v0.1.0`.
- A digest is the sha256 hash of a file (a fixed-length fingerprint of its - A digest is the sha256 hash of a file (a fixed-length fingerprint of its
@@ -39,8 +40,9 @@ file).
step 1. `make package` needs no Docker. step 1. `make package` needs no Docker.
- Node and yarn. Both come from the system when present. Otherwise - Node and yarn. Both come from the system when present. Otherwise
`script/bootstrap` installs Node through a pinned (fixed-version) install of `script/bootstrap` installs Node through a pinned (fixed-version) install of
nvm, a Node version manager. It installs yarn through corepack (Node's package nvm, a Node version manager. `script/bootstrap` installs yarn through corepack
manager installer) or, failing that, through `npm` (Node's package manager). (Node's package manager installer). When no corepack is found,
`script/bootstrap` installs yarn through `npm` (Node's package manager).
## Procedure ## Procedure
@@ -51,23 +53,25 @@ every push. `script/cibuild` runs:
- `script/bootstrap`, which installs the dependencies; - `script/bootstrap`, which installs the dependencies;
- `script/check`, which is what `make check` runs; - `script/check`, which is what `make check` runs;
- the Docker image build. - the Docker image build (an image is Docker's packaged form of a program).
`script/check` runs: `script/check` runs:
- `script/test`: the tests, in Docker; - `script/test`: the tests, in Docker;
- `script/lint`, in Docker, which runs three checks: - `script/lint`, which runs three checks in Docker:
- ESLint, a code checker; - ESLint, a code checker;
- `prettier --check .`, the formatting check; - `prettier --check .`, the formatting check;
- `script/check-censored`, which fails when the name that `RULES.md` bars - `script/check-censored`, which fails when the name that `RULES.md` bars
appears outside its allowed places; appears outside its allowed places;
- `script/fmt-check`: `prettier --check .` again, on the host. - `script/fmt-check`: `prettier --check .` again, on the host.
The `e2e` workflow (`.gitea/workflows/e2e.yml`) runs the two browser suites on The `e2e` workflow (`.gitea/workflows/e2e.yml`) has two jobs. One runs
every push, as two jobs. A red `e2e` job does not fail the `check` run. `script/test-e2e`, the browser tests in Chrome. The other runs
`script/test-e2e-firefox`, the browser tests in Firefox. A red `e2e` job does
not fail the `check` run.
Run `script/cibuild` on the clean checkout. It runs the same steps as the Run `script/cibuild` on the clean checkout. `script/cibuild` runs the same steps
`check` run, and it must exit 0. as the `check` run, and must exit 0.
Check: on the Actions page, the `check` run for the release commit succeeded, Check: on the Actions page, the `check` run for the release commit succeeded,
and both `e2e` jobs for that commit succeeded. `script/cibuild` exited 0 on the and both `e2e` jobs for that commit succeeded. `script/cibuild` exited 0 on the
@@ -108,7 +112,7 @@ make package
`make build`: `make build`:
- runs `build.js`. It writes `dist/chrome/`, `dist/firefox/` and a build - runs `build.js`. `build.js` writes `dist/chrome/`, `dist/firefox/` and a build
receipt. The receipt lists every file that `build.js` wrote, with each file's receipt. The receipt lists every file that `build.js` wrote, with each file's
digest. The receipt lives outside the repository and is deleted when the build digest. The receipt lives outside the repository and is deleted when the build
ends; ends;
@@ -127,9 +131,11 @@ make package
- empties `release/`; - empties `release/`;
- refuses a symbolic link (a file that points at another file) under `dist/`; - refuses a symbolic link (a file that points at another file) under `dist/`;
- checks that the archive is self-contained: every file that the manifest or the - checks that the archive is self-contained: every file that the manifest or the
popup's HTML page names is inside the browser's directory. The manifest is popup's HTML page names is inside the browser's directory (`dist/chrome/` or
`manifest.json`, the file that describes the extension to the browser; `dist/firefox/`). The manifest is `manifest.json`, the file that describes the
- checks that the `version` in each `manifest.json` is the tree's version; extension to the browser. The popup is the window that the toolbar button
opens;
- checks that the `version` in each `manifest.json` is the version from step 2;
- writes one archive per browser; - writes one archive per browser;
- reads each archive back; - reads each archive back;
- compares every member (a file inside the archive) with `dist/` byte for byte; - compares every member (a file inside the archive) with `dist/` byte for byte;
@@ -147,7 +153,7 @@ release/SHA256SUMS
``` ```
The `.xpi` is Firefox's add-on package file (an add-on is Firefox's word for an The `.xpi` is Firefox's add-on package file (an add-on is Firefox's word for an
extension). It is not signed. extension). The `.xpi` is not signed.
`make package` prints a line that starts `Not shipped` and names `styles.css`. `make package` prints a line that starts `Not shipped` and names `styles.css`.
This is expected: each archive holds its own copy of the stylesheet. This is expected: each archive holds its own copy of the stylesheet.
@@ -159,18 +165,19 @@ version from step 2.
From `release/`, run `sha256sum -c SHA256SUMS`. From `release/`, run `sha256sum -c SHA256SUMS`.
The archives are deterministic for a given `dist/`. `script/lib/zip.js`: The archives are deterministic for a given `dist/`: the same `dist/` always
gives the same bytes. `script/lib/zip.js`:
- sorts the members; - sorts the members;
- sets every timestamp to 1980-01-01; - sets every member's timestamp (its recorded date) to 1980-01-01;
- compresses each member the same way every time. - compresses each member the same way every time.
`dist/` itself carries the build date. `build.js` compiles the build date, a UTC `dist/` itself carries the build date. `build.js` compiles the build date, a UTC
(universal time) day, into the extension. So two builds of the same commit on (universal time) day, into the extension. So two builds of the same commit on
the same UTC day give byte-identical archives. Builds on different days differ. 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` Check: `sha256sum -c` prints `OK` for both archives. On the same UTC day, a
from another clean checkout of the same commit, on the same UTC day, gives the second `make package` from another clean checkout of the same commit gives the
same `SHA256SUMS`. same `SHA256SUMS`.
### 5. Tag the release commit ### 5. Tag the release commit
@@ -185,7 +192,7 @@ git push origin vX.Y.Z
``` ```
`-a` makes an annotated tag: a tag that carries a message and records who made `-a` makes an annotated tag: a tag that carries a message and records who made
it and when. `v0.1.0` is one. the tag and when. `v0.1.0` is one.
Once the tag exists, `git describe --tags` on the release commit prints 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 `vX.Y.Z`. `script/cibuild` and `script/docker` pass that value to the Docker
@@ -210,10 +217,10 @@ Chrome loads the extension from a directory:
Chrome then reports the extension id `gipbhkogfopeahplcjhipkgpcimdpkip`. The id Chrome then reports the extension id `gipbhkogfopeahplcjhipkgpcimdpkip`. The id
is the fixed string that identifies the extension to Chrome; the `key` in is the fixed string that identifies the extension to Chrome; the `key` in
`manifest/chrome.json` sets it. `manifest/chrome.json` sets the id.
Release builds of Firefox refuse to install an unsigned add-on. Desktop Firefox 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 its 115 or newer, in any edition, loads the `.xpi` as a temporary add-on from the
`about:debugging` page. Firefox unloads a temporary add-on when Firefox exits. `about:debugging` page. Firefox unloads a temporary add-on when Firefox exits.
The section "Installing on Firefox" in `README.md` has the details. The section "Installing on Firefox" in `README.md` has the details.