Publishing: branches, releases, docs
このコンテンツはまだ日本語訳がありません。
How Butter’s branching, release, and docs-publishing pipeline fit together. Read this before cutting your first release.
Branches
Section titled “Branches”| Branch | Role |
|---|---|
dev |
Day-to-day work. Every push + PR runs CI (ci.yml). |
main |
Stable. Only advances via “release PR” merges from dev. |
release/v<X.Y.Z> |
Cut by the release workflow on each release. Kept open for hotfixes against that version line. |
Day-to-day: branch off dev, PR back to dev. Release-time: PR dev → main.
Release process
Section titled “Release process”- Open a PR
dev→maintitledRelease vX.Y.Z. CI runs on the PR. Get a review, merge. - Trigger the release workflow. GitHub UI → Actions → Release → “Run workflow” on
main. Inputs:bump_type—patch/minor/majorprerelease_tag—alpha/beta/rc/noneoverride_version— bypass auto-bump (e.g.0.2.0-alpha)tag_prefix—v(default) orauto(inherit from last tag)
- The workflow does the rest: clean test pass on macOS, then
scripts/release.shcomputes the next version fromgit describe, rewritesButter.versioninSources/ButterSwift/Butter.swiftto match the new tag (and commits the bump onmainwith[skip ci]), createsrelease/<tag>branch- an annotated tag pointing at the bump commit, pushes branch + tag + the updated
main. Finallygh release create --generate-notespublishes the GitHub Release targeting the release branch.
- an annotated tag pointing at the bump commit, pushes branch + tag + the updated
- The
release: publishedevent automatically firesnotify-docs.yml, which dispatches the butter-website build against the new tag.
Always run the Release workflow from main (the branch picker in the workflow_dispatch UI). The workflow guards against running off any other branch.
License-header sweep
Section titled “License-header sweep”Before computing the version and creating the tag, the release workflow runs scripts/update-license.sh to prepend the Apache 2.0 header to any source file missing it; the workflow commits the result so the tagged commit provably carries the header on every code + test file. The script is idempotent — a no-op when the pre-commit hook (make install-hooks) already kept headers in sync locally.
What the script does to Butter.version
Section titled “What the script does to Butter.version”There’s exactly one in-code version string, Butter.version, surfaced by butter --version + on every CLI invocation + recorded in bench reports. release.sh keeps it in lockstep with the tag automatically:
- If
Butter.versionalready matches the computedNEW_VERSION(e.g. a contributor manually bumped it in the release PR), the script logsno bump neededand proceeds. - Otherwise it rewrites the string literal, commits the change on the current branch with
chore: bump Butter.version to <tag> [skip ci], andgit push origin <branch>. The release branch + tag are created on the bump commit, so any checkout of the tag carries the matching version string.
Convention for dev between releases: suffix -dev (e.g. "0.2.0-dev" after v0.1.0 ships) so stale dev builds are easy to spot in CLI output and bench logs. This bump is not automated today — open a manual PR on dev after each release.
Dry-running the version bump locally
Section titled “Dry-running the version bump locally”scripts/release.sh honors a PUSH=0 env var for dry-runs:
PUSH=0 BUMP_TYPE=minor PRERELEASE_TAG=alpha ./scripts/release.sh# Butter.version already at 0.1.0 — no bump needed.# (or:)# [dry-run] would bump Butter.version: 0.0.5-dev → 0.1.0-alpha + commit.# tag=v0.1.0-alpha# version=0.1.0-alpha# release_branch=release/v0.1.0-alpha# commit=<sha of HEAD>Dry-run doesn’t write to Butter.swift or make any commits — it only creates the local tag + release branch (which point at unchanged HEAD). Clean up with:
git tag -d v0.1.0-alphagit branch -D release/v0.1.0-alphaEnv vars the script understands:
BUMP_TYPE—major/minor/patch(defaultminor)PRERELEASE_TAG—alpha/beta/rc/none(defaultnone)OVERRIDE_VERSION— bypass auto-bump entirely (e.g.0.2.0-alpha)TAG_PREFIX—v/auto/ empty string (defaultauto, which inherits from the last reachable tag and falls back tov)PUSH—1to push branch + tag,0for dry-run (default1)
Release notes generation
Section titled “Release notes generation”The release workflow passes --generate-notes to gh release create. GitHub generates the notes from PR titles + labels since the previous reachable tag, grouped per .github/release.yml.
Labels get applied automatically by auto-label.yml based on the PR title’s conventional-commit prefix:
| PR title prefix | Label | Section in notes |
|---|---|---|
feat: / feature: |
feature |
✨ Features |
fix: / bugfix: |
bug |
🐛 Bug Fixes |
perf: |
performance |
🚀 Performance |
docs: / doc: |
documentation |
📚 Documentation |
test: / tests: |
test |
🧪 Tests |
chore: / ci: / build: / refactor: / style: |
ignore-for-release |
(hidden) |
Any prefix with ! |
breaking |
💥 Breaking Changes |
So title PRs intentionally — feat: … for features, fix: … for bugs, chore: … for refactors that shouldn’t appear in user-facing notes.
Docs site publishing chain
Section titled “Docs site publishing chain”The user-facing site at https://thewafflehaus.github.io/butter-website/ only rebuilds against immutable Butter release tags — never main HEAD. Unreleased doc changes land on dev → main but stay invisible to the published site until the next release.
Butter release published │ ▼notify-docs.yml (Butter / .github/workflows/) │ │ workflow_dispatch (Actions: write on butter-website) ▼deploy.yml (butter-website / .github/workflows/) │ │ checkouts Butter@<tag>, syncs markdown, builds Astro, │ deploys to GH Pages ▼https://thewafflehaus.github.io/butter-website/Site rebuilds also happen when:
- You push to
mainon butter-website (site source changed — Astro components, CSS, sidebar). Pins to Butter’s latest published release. - You manually trigger butter-website’s
deploy.ymlfrom the Actions tab. Same — pins to latest release.
Either way the docs content stays pinned to a real release; you can iterate on the site itself between Butter releases.
The cross-repo dispatch token
Section titled “The cross-repo dispatch token”notify-docs.yml calls gh workflow run deploy.yml on butter-website, which requires authentication. The WEBSITE_DISPATCH_TOKEN repo secret holds a fine-grained PAT scoped to only butter-website with:
| Permission | Level |
|---|---|
| Actions | Read and write |
| Contents | Read-only |
| Metadata | Read-only |
No Contents: write on butter-website. The dispatch uses workflow_dispatch (not repository_dispatch) so the worst a leaked token could do is spam-trigger the deploy workflow or cancel runs — it can’t modify butter-website’s repo contents.
If the secret is missing the notify workflow logs a warning and exits 0 gracefully (no failed Actions run); the release still gets created, the site just won’t rebuild until you set the token.
Manual rebuild commands
Section titled “Manual rebuild commands”When you need to force a rebuild without cutting a release:
# Re-deploy the site against whatever the latest Butter release is.gh workflow run deploy.yml --repo thewafflehaus/butter-website
# Re-deploy against a specific Butter release (e.g. roll back the docs).gh workflow run deploy.yml --repo thewafflehaus/butter-website \ --field butter_tag=v0.1.0
# Re-run the full notify → dispatch chain (useful to test the token).gh workflow run notify-docs.yml --repo waffuruai/butter \ --field tag=v0.1.0See also
Section titled “See also”- Architecture — where in the pipeline kernel generation, model load, and inference dispatch live.
- Testing — what gets tested, where fixtures live.
planning/roadmap.md— what we’re shipping in upcoming releases.
