| name | make-release |
| description | Use when cutting a new TinyUSB release — version bump, regenerated files, the per-release changelog, and validation before the maintainer commits and tags. |
Cut a TinyUSB Release
Don't commit or tag during prep — leave changes unstaged for the maintainer (step 4). Work in a worktree. Agree the version X.Y.Z with the maintainer first (their call, not derivable from the diff).
1. Bump + regenerate
python3 tools/make_release.py
Refreshes tusb_option.h, repository.yml, library.json, sonar-project.properties, and (via gen_doc/gen_presets) docs/reference/{boards,dependencies}.rst + preset JSONs (presets/docs change only if boards/deps changed).
Gotchas: gen_doc needs pandas+tabulate (not in requirements) → pip install pandas tabulate; boards.rst lands with no trailing newline → let pre-commit fix it (step 3).
2. Changelog — docs/changelog/ (the hard part)
New file docs/changelog/X.Y.Z.md, listed first in docs/changelog/index.rst. Get the PR set by commit reachability, not merge date (a date query wrongly pulls in the prior release's changelog PR at the boundary):
PREV=0.20.0
git merge-base --is-ancestor $PREV HEAD && echo OK
git log --first-parent $PREV..HEAD --pretty=%s > /tmp/fp.txt
{ sed -nE 's/^Merge pull request #([0-9]+).*/\1/p' /tmp/fp.txt
sed -nE 's/.*\(#([0-9]+)\)$/\1/p' /tmp/fp.txt ; } | sort -un > /tmp/prs.txt
grep -vE '^Merge pull request #[0-9]+|\(#[0-9]+\)$' /tmp/fp.txt
xargs -P8 -I{} gh pr view {} --json number,title,labels \
--jq '"#\(.number)\t\(.title)\t[\(.labels|map(.name)|join(","))]"' < /tmp/prs.txt
--first-parent skips dev-merges; the two seds catch merge-button + squash. A PR merged into a feature branch folds into its parent (won't appear alone) — reflect its final state in the parent's bullet.
Curate into the prior file's exact Markdown (MyST) style:
- Title = version (
# X.Y.Z), then italic date (ask if unknown). Add to top of index.rst.
- Section order: General (New MCUs and Boards / Code Quality and Build / Documentation) → API Changes → Device Stack (per class) → Host Stack → Controller Driver (DCD & HCD) (per driver) → Testing → Contributors. Sections are
##; each class/driver group is a ### sub-heading, not a bullet.
- Single backticks for symbols; group related PRs into one bullet (don't dump).
Port */driver labels help bucket DCD/HCD.
- Contributors: unique non-bot PR authors, alphabetical (the only contributor credit — no separate page):
xargs -P8 -I{} gh pr view {} --json author --jq '.author.login' < /tmp/prs.txt \
| grep -viE '\[bot\]$|^(copilot|claude|dependabot|github-actions)$' | sort -uf | sed 's/^/@/' | paste -sd, - | sed 's/,/, /g'
3. Validate (leave unstaged)
pre-commit run --files docs/changelog/X.Y.Z.md docs/changelog/index.rst \
docs/reference/boards.rst docs/reference/dependencies.rst \
library.json repository.yml sonar-project.properties src/tusb_option.h tools/make_release.py
python3 tools/build_doc.py -c
( cd test/unit-test && ceedling test:all )
( cd examples/device/cdc_msc && rm -rf build && mkdir build && cd build && \
cmake -DBOARD=stm32f407disco -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel .. && cmake --build . )
git diff --stat -- ':!.idea'
Confirm the version matches across tusb_option.h / library.json / repository.yml / sonar-project.properties.
4. Finalize (maintainer)
git add -A -- ':!.idea' && git commit -m "Bump version to X.Y.Z"
git tag -a X.Y.Z -m "Release X.Y.Z"
git push origin <branch> X.Y.Z
Then create the GitHub release from the tag.
5. Code size (automatic)
On the release event, CI's code-metrics job diffs against the previous tag's metrics.json and uploads metrics.json + a compare to the release — only if the previous release has a metrics.json asset. Confirm both appeared.