Versioning & Releases
Nametag follows Semantic Versioning 2.0.0.
Version format
Section titled “Version format”MAJOR.MINOR.PATCH (for example, 1.2.3).
- MAJOR: breaking changes (incompatible API changes, database migrations requiring manual intervention).
- MINOR: new features, backward-compatible.
- PATCH: bug fixes, backward-compatible.
Pre-release versions may use suffixes: 1.0.0-beta.1, 1.0.0-rc.2.
Conventional commits
Section titled “Conventional commits”Nametag uses Conventional Commits to automatically determine version bumps.
Format:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Types:
feat:new feature (triggers a MINOR bump)fix:bug fix (triggers a PATCH bump)perf:performance improvement (triggers a PATCH bump)docs:documentation changes onlystyle:code style changes (formatting, semicolons, and so on)refactor:code restructuring without feature changestest:adding or updating testschore:maintenance tasks, dependencies, and so onci:CI/CD configuration changes
Breaking changes:
Add BREAKING CHANGE: in the footer, or ! after the type, to trigger a MAJOR bump:
feat!: redesign authentication system
BREAKING CHANGE: Users must re-authenticate after upgradeThe whole message has to parse, not just the header
Section titled “The whole message has to parse, not just the header”release-please runs the entire commit message through a strict grammar. On a squash merge that message is the pull request title with the number appended, followed by the pull request description, so the body counts too.
If the parse fails, release-please skips the commit and still exits green. That commit then contributes nothing at all: no changelog entry, and no version bump either. Nothing turns red, the change simply goes missing from the release.
The usual cause is nested parentheses, because the grammar uses them for the commit scope:
fix(dates): keep year-unknown dates on the day they were saved
Asserts formatDateWithoutYear(parseCalendarDate(stored)) across five zones. ^ second "(" before the first closesBackticks and code fences do not exempt it. Rewrite the nesting as two flat calls, for example formatDateWithoutYear() over parseCalendarDate().
Whether a given nesting actually trips the grammar depends on where in the line it sits, so a nested call mid-sentence sometimes slips through. Avoid it everywhere rather than trying to predict which ones are safe.
The Commit Message workflow checks this on every pull request, using the same parser version release-please uses, and re-runs when the title or description is edited. scripts/check-pr-commit-message.ts prints the offending line and column.
How releases work
Section titled “How releases work”Nametag uses release-please for automated, PR-based releases.
- Commits land on
masterusing conventional commit format. - release-please automatically maintains an open Release PR that accumulates all unreleased changes, auto-suggests the next version based on commit types, updates
CHANGELOG.mdwith grouped entries, and bumps thepackage.jsonversion. - A maintainer reviews and edits the PR: adjusting the version, rewriting the notes, or accepting it as-is.
- Merging the PR creates the release: a git tag and a GitHub Release.
- An AI step rewrites the GitHub Release notes into a human-readable summary for end users and self-hosters, based on the pull requests included in the release.
- The release triggers Docker image builds and publishing automatically.
The summary step calls the Gemini API and needs a GEMINI_API_KEY repository secret. It only runs on the mattogodoy/nametag repository, so forks are unaffected. It can also be re-run by hand from the Actions tab, using the “Release Please” workflow’s manual trigger and passing an existing tag.
Controlling versions
Section titled “Controlling versions”Auto-determined: release-please picks the version from commit types, using the same rules as the table below.
Override the version: add a commit with this footer to force a specific version:
chore: prepare for v1.0.0 release
Release-As: 1.0.0Skip a release: simply don’t merge the Release PR. It keeps accumulating changes until it’s merged.
Version bumping rules
Section titled “Version bumping rules”| Commit type | Version bump | Example |
|---|---|---|
fix: | PATCH | 1.0.0 to 1.0.1 |
feat: | MINOR | 1.0.0 to 1.1.0 |
feat!: or BREAKING CHANGE: | MAJOR | 1.0.0 to 2.0.0 |
docs:, style:, refactor:, test:, chore: | No bump | (none) |
While the version is 0.x.y (pre-1.0), breaking changes bump MINOR instead of MAJOR.
Version history
Section titled “Version history”Versions are tracked in:
package.json, the npm package version..release-please-manifest.json, the release-please version tracker.- Git tags,
v1.2.3. - GitHub Releases, with release notes and changelog.
- Docker tags,
ghcr.io/mattogodoy/nametag:1.2.3andlatest.
Where the version is displayed
Section titled “Where the version is displayed”The current version is shown in:
- The app footer, on every page.
- Settings > About.
- Docker image tags.
- The GitHub Releases page.
Changelog
Section titled “Changelog”CHANGELOG.md is maintained automatically by release-please from commit messages, updated as part of the Release PR.
Best practices
Section titled “Best practices”- Write good commit messages. They become your changelog.
- Use conventional commits, and keep the description parseable too. Avoid nested parentheses.
- Tag breaking changes explicitly, with
!orBREAKING CHANGE:. - Don’t commit directly to
master. Use PRs. - Squash related commits, one feature per commit.
- Test before releasing:
npm run verifyruns all the checks.