Skip to content

Latest commit

 

History

History
110 lines (80 loc) · 7.36 KB

File metadata and controls

110 lines (80 loc) · 7.36 KB

Releasing Patternflow

Patternflow uses one unified semantic version for the public project.

The project version covers firmware, PCB, case files, web, and docs together. Use tags like v2.0.0, not separate public fw-*, hw-*, or web-* release tags.

Version rules

  • PATCH (v2.0.1) -- documentation fixes, small firmware/web bug fixes, no user-facing build change.
  • MINOR (v2.1.0) -- new patterns, new web features, compatible case or PCB improvements.
  • MAJOR (v3.0.0) -- hardware-incompatible changes, major interaction changes, or a new build path.

Two commands

Since 3.9.3 the checklist below is a script. On dev, with a clean tree and the [Unreleased] section of CHANGELOG.md written:

python firmware/toolchain/release.py cut v3.9.4 --audio v0.5.4 --performance v0.2.4

bumps the versions, dates the changelog section, updates AGENTS.md, runs shelf.sh for the core and each named edition, points the flasher manifest and the /editions cards at the new images, runs the web checks, commits release: v3.9.4 and tags it. Name only the editions that should be re-cut; the others keep their image. Then write the release notes and

python firmware/toolchain/release.py publish v3.9.4 --notes notes.md

pushes, opens the dev → main pull request from the changelog section, waits for its checks, merges, creates the GitHub release from the notes, attaches the edition images under their release names, and waits for the workflow that attaches the core images. README.md's Moving fast note is prose and stays yours. cut --no-build --no-commit is the dry run.

An edition on its own

An edition's maintainer ships between core releases, from a pull request, with one command on a clean tree:

python firmware/toolchain/release.py edition performance v0.2.8

It bumps that edition's PF_VARIANT_VERSION, runs shelf.sh for it (a clean build — the image is refused if it carries credentials or the wrong version), points its /editions card at the new folder, updates its clause in AGENTS.md and commits release: performance v0.2.8. No tag, no changelog section, no manifest — those are the core's. Push and open the pull request; CI checks that the six places agree and compiles every composition, and the shelf serves the image once main deploys. The core's maintainer merges and does nothing else. --no-build --no-commit is the dry run.

Only editions in release.py's EDITIONS tuple are on the shelf. A bundle in the tree that is not there (clock, midi) is a composition CI keeps compiling, and nothing more; there is no card to point and nothing to cut.

Release checklist

What the two commands do, step by step - and the way to do it by hand.

  1. Make sure all intended changes are committed, and ./firmware/bundles/build.sh all is green if anything under firmware/ moved.

  2. Bump the version the firmware reports: PF_IMPROV_FW_VERSION in firmware/patternflow/net_config.h (written X.Y.Z, no v). shelf.sh refuses a core image whose define disagrees with the version it is being shelved as.

  3. Turn CHANGELOG.md's [Unreleased] into ## [X.Y.Z] - YYYY-MM-DD and open a fresh [Unreleased] above it.

  4. Update the version the docs claim: the "current" line in AGENTS.md, the Moving fast note in README.md, and any guide that names a release.

  5. If hardware changed: confirm BUILD_GUIDE.md's parts table, hardware/bom/bom_v*.csv and the schematic agree; regenerate the Gerber zip, renders and schematic exports with the recipe in hardware/pcb/README.md; add a ### Hardware entry to the changelog section; update the board table in hardware/README.md and the version line in docs/assembly/README.md; attach the Gerber zip, the BOM CSV and the STLs to the release.

  6. Stage the images the site serves:

    ./firmware/bundles/shelf.sh core vX.Y.Z

    then point web/public/flash/manifest.json at the new folder. An edition that also moved gets its own shelf.sh <edition> vA.B.C and a card update in web/src/app/editions/editions-data.ts. The shelf retires the previous folder of the same name — older images stay on their tags. Try-out images (clock-v0.1.5, midi-v0.1.0, the ones the features page installs) are not part of a release and stay as they are; a fresh one is its own shelf.sh <name> vA.B.C and a row update in web/src/app/features/features-data.ts, done when somebody wants a newer one, not because the core moved.

  7. Regenerate the guide's live console demo, which carries the version, the core image's build id and the manifest version: python firmware/toolchain/console_demo.py (neither release.py nor CI does this; without it the demo on /guide/play keeps presenting the previous release), and confirm python firmware/toolchain/editor_demo.py --check. Then run the web checks from web/: npm run lint && npm run typecheck && npm run check:ci && npm run build.

  8. Commit and tag:

    git commit -m "release: vX.Y.Z"
    git tag -a vX.Y.Z -m "Release vX.Y.Z"
    git push origin dev && git push --tags
  9. Create the GitHub Release from the tag. Publishing it triggers Firmware release assets, which attaches the four flash images from the tag plus a generated FLASHING.md with offsets and hashes.

  10. Confirm it went green before announcing; re-run it with workflow_dispatch if it did not fire.

  11. Redeploy the community host (the Pi: pull main, build, restart the web and worker units) once main has deployed. The Basics pack card and the pattern builds are served from there, so until it is redeployed it hands out the previous pack and the previous build settings. Do it before announcing anything that says "install the pack again".

Branches

Work happens on dev, then lands on main through a pull request. main is protected: nobody pushes to it directly, the maintainer included.

  • Commit freely on dev. Commits are cheap save points; small and frequent is good. Throwaway wip: commits belong here rather than on main.

  • Bigger or riskier work gets its own branch (feat/..., fix/...) off dev.

  • Outside pull requests target main. After one merges, pull main back into dev so the branches don't drift:

    git checkout dev && git merge origin/main && git push origin dev
    
  • A release is dev → main as one pull request, opened by release.py publish from the changelog section; merging it posts the dev-log to Discord.

Current release line

CHANGELOG.md is the record — one section per release, newest first — and the releases page carries the notes and the flashable images. The shape of the line, for orientation:

  • v1.x -- first public buildable release, then the multi-pattern firmware and browser flasher.
  • v2.x -- the v2.0 board (GPIO0 cold-boot fix, cleaned silkscreen), custom pattern workflow, the web platform. v2.1.0 is the last release for v2.x hardware.
  • v3.0.0 -- the v3.0 board; v3.9 (2026-09, unreleased as a tag) removed its USB-C footprint and changed nothing else. Every later v3.x is firmware/web on that hardware: .pfm modules over Wi-Fi (3.2), shows and the Director (3.6), the feature seam (3.7), editions (3.8).
  • Editions on the shelf (audio, performance) carry their own version lines, independent of the project version — see docs/EDITIONS.md. clock and midi are bundles CI builds but the shelf does not carry.