Releasing (maintainers)
CycleWire uses Semantic Versioning, annotated git tags (vX.Y.Z),
GitHub Releases and npm with trusted publishing. Once trusted publishing works, nothing
is published from a laptop.
Every release
Section titled “Every release”-
Make sure
mainis green in CI. -
Update
versioninpackage.json(npm version <patch|minor|major> --no-git-tag-version). -
Move the “Unreleased” notes in
CHANGELOG.mdunder the new version and date, and update the compare links at the bottom. -
Refresh the README’s size table with
npm run build && npm run size -- --readme, and check the sizes written in the prose (README,docs/performance.md,docs/modules.md,docs/concepts.md); the landing page takes its sizes fromdist/sizes.jsonby itself. -
Commit:
git commit -am "chore(release): X.Y.Z". -
Tag and push:
Terminal window git tag -a vX.Y.Z -m "CycleWire vX.Y.Z"git push origin main --follow-tags
The tag starts .github/workflows/release.yml, which:
- installs, type-checks, runs the unit and browser tests, builds and checks the size budgets;
- checks that the tag matches
package.json; - publishes to npm through OIDC trusted publishing, which attaches provenance, unless that version is already on npm;
- creates the GitHub Release. The notes come from
CHANGELOG.md, and thedist/bundles and their SRI hashes are attached.
The site (the landing page, the documentation and the live examples) redeploys on every
push to main (.github/workflows/pages.yml), the release commit included.
Publishing by hand
Section titled “Publishing by hand”Until trusted publishing works, a maintainer publishes the release commit from a clean checkout, then pushes the tag:
git switch main && git pullnpm cinpx playwright install chromium firefox webkitnpm publish --access public # prepublishOnly builds and tests first; npm asks for the second factorgit tag -a vX.Y.Z -m "CycleWire vX.Y.Z"git push origin vX.Y.ZThe Release workflow still verifies the commit, finds the version already on npm, skips publishing, and creates the GitHub Release with the notes and SRI hashes.
Pre-releases
Section titled “Pre-releases”Use a pre-release version (1.1.0-beta.1) and tag. The workflow publishes it under the
next dist-tag and marks the GitHub Release as a pre-release.
One-time setup
Section titled “One-time setup”These steps need the owner’s npm and GitHub accounts.
-
First publish. npm can only attach a trusted publisher to a package that already exists, so 1.0.0 is published by hand from a clean checkout of the release commit:
Terminal window npm loginnpm publish --access publicprepublishOnlybuilds and tests first. -
Trusted publisher. On npmjs.com, open
cyclewire, then Settings, then Trusted Publisher, then GitHub Actions. Enter organizationCycleChain, repositoryCycleWireand workflowrelease.yml. To check it without releasing anything, run the Release workflow by hand (Actions, then Release, then Run workflow): it asks npm for a publish token the waynpm publishdoes and prints npm’s answer. Once that passes, you can disallow tokens altogether in the package’s publishing access settings. -
GitHub Pages. In the repository settings, set Pages to be deployed by “GitHub Actions”. The
github-pagesenvironment then accepts deployments frommain, which is where the Pages workflow deploys from. -
The site on cyclechain.io. The Pages workflow publishes the site on GitHub Pages until the repository variable
SITE_DEPLOYisserver. From then on it builds the site forhttps://cyclechain.io/labs/cyclewire/, copies it into the server’slabs/cyclewire/folder with rsync over SSH, and only after that turns GitHub Pages into a page that sends every old address to the same page on cyclechain.io. To set it up:-
On the server, give the copy a user of its own that can write to that folder and nowhere else, and make the folder:
Terminal window sudo adduser --disabled-password --gecos '' cyclewire-sitesudo mkdir -p <web root>/labs/cyclewiresudo chown cyclewire-site: <web root>/labs/cyclewire -
On your machine, make a key for the workflow, with no passphrase:
Terminal window ssh-keygen -t ed25519 -N '' -C cyclewire-site -f cyclewire-sitePut
cyclewire-site.pubin the server’s/home/cyclewire-site/.ssh/authorized_keys, preceded byrestrictso the key can copy files but not open a shell with forwarding. -
In the repository settings, under Secrets and variables, then Actions, add these secrets:
Secret Value SITE_DEPLOY_HOSTThe server’s own address, not the cyclechain.io name Cloudflare answers for SITE_DEPLOY_PORTIts SSH port, if not 22 SITE_DEPLOY_USERcyclewire-siteSITE_DEPLOY_KEYThe contents of cyclewire-site, the private keySITE_DEPLOY_KNOWN_HOSTSWhat ssh-keyscan -p <port> <host>printsSITE_DEPLOY_PATH<web root>/labs/cyclewire, the folder from step 1The workflow refuses any path that does not end in
cyclewire: the copy deletes what the build does not have, so it never runs anywhere else. -
Add the variable
SITE_DEPLOYwith the valueserver, then run the Pages workflow by hand (Actions, then Pages, then Run workflow). Removing the variable puts the site back on GitHub Pages at the next run.
The cyclechain.io site is published from its own repository with rsync too, as a mirror of its build: its
deploy/keep.rsynchas to keeplabs/cyclewire/, or its next deploy would delete this site. -
jsDelivr and unpkg serve every npm version automatically; cdnjs needs a one-time listing,
and accepts libraries once they have some adoption. After that, cdnjs imports new versions
from npm by itself. To apply, fork cdnjs/packages,
add packages/c/cyclewire.json and open a pull request:
{ "name": "cyclewire", "description": "Zero-initial-JS selective activation engine. Turn server-rendered HTML into instant interactivity on intent.", "keywords": ["resumability", "event-delegation", "lazy-loading", "progressive-enhancement", "server-rendered", "zero-dependency"], "authors": [{ "name": "CycleChain", "url": "https://cyclechain.io" }], "license": "MIT", "homepage": "https://cyclechain.github.io/CycleWire/", "repository": { "type": "git", "url": "https://github.com/CycleChain/CycleWire.git" }, "filename": "cyclewire.global.min.js", "autoupdate": { "source": "npm", "target": "cyclewire", "fileMap": [{ "basePath": "dist", "files": ["*.min.js", "*.min.js.map"] }] }}cdnjs has no @1-style ranges, so its URLs always name an exact version.
create-cyclewire
Section titled “create-cyclewire”The starter templates are a package of their own, in packages/create-cyclewire/, with
their own version and changelog. CI builds each template and uses it in Chromium on every
change.
-
The first version, by hand. npm can only trust a workflow for a package that exists, so publish 1.0.0 yourself:
cd packages/create-cyclewire && npm publish --access public(npm asks for your second factor). -
Then trust the workflow. In the package’s settings on npmjs.com, add a trusted publisher: GitHub Actions,
CycleChain/CycleWire, workflowcreate-cyclewire.yml. -
Every later version. Update
versionandCHANGELOG.mdinpackages/create-cyclewire/, commit, and push a tag named after it:Terminal window git tag -a create-cyclewire-v1.0.1 -m "create-cyclewire v1.0.1"git push origin main --follow-tags.github/workflows/create-cyclewire.ymltests the templates and publishes it with provenance, skipping a version npm already has.
If something fails
Section titled “If something fails”- Tests or budgets fail: nothing was published. Fix, commit, delete and recreate the
tag (
git tag -d vX.Y.Z && git push origin :refs/tags/vX.Y.Z), push again. - npm publish succeeded, release step failed: re-run the workflow. The publish step skips versions that are already on npm.
- npm refused trusted publishing: nothing was published. The publish step prints the
repository, workflow and environment that GitHub vouched for, and npm’s reason. Make the
trusted publisher settings match them, check again by running the workflow by hand,
then re-run the release. Without that check, npm falls back to a token it does not have
and reports
E404 Not Found. - A bad version reached npm: publish a fixed patch release. Use
npm deprecaterather than unpublishing.