Automated Versioning & Release Management
TinyKit Pro uses automated semantic versioning with conventional commits to streamline release management and maintain accurate changelogs.
TinyKit Pro uses automated semantic versioning with conventional commits to streamline release management and maintain accurate changelogs.
Overview
The versioning system automatically:
- Analyzes commit messages to determine version bumps
- Updates
CHANGELOG.mdwith categorized changes - Bumps version in
package.json - Creates GitHub releases with release notes
- Tags releases in git
Conventional Commits
All commits must follow the Conventional Commits specification.
Format
<type>(<scope>): <description>
[optional body]
[optional footer(s)]Commit Types & Version Bumps
| Type | Version Impact | Description | Examples |
|---|---|---|---|
feat | Minor (0.X.0) | New feature | feat(auth): add passwordless login |
fix | Patch (0.0.X) | Bug fix | fix(billing): correct proration |
perf | Patch (0.0.X) | Performance improvement | perf(queries): optimize user lookup |
refactor | Patch (0.0.X) | Code restructuring | refactor(utils): simplify helpers |
revert | Patch (0.0.X) | Revert previous commit | revert: feat(auth): add oauth |
docs | None | Documentation changes | docs: update API reference |
style | None | Code formatting (no logic change) | style: format with prettier |
test | None | Test additions/updates | test: add billing tests |
build | None | Build system changes | build: update dependencies |
ci | None | CI configuration | ci: add codecov integration |
chore | None | Maintenance tasks | chore: update gitignore |
Breaking Changes (Major X.0.0)
Breaking changes trigger a major version bump:
# Using ! suffix
feat!: remove deprecated user.email field
# Using BREAKING CHANGE footer
feat(api): redesign authentication endpoints
BREAKING CHANGE: Session tokens are now JWT-based instead of opaque stringsScope Examples
Scopes help categorize changes:
feat(auth): add two-factor authentication
fix(billing): handle failed payment webhooks
docs(api): update stripe integration guide
perf(database): add indexes for faster queries
refactor(email): extract template rendering logicLocal Validation
Commitlint validates commit messages via Husky's commit-msg hook:
# ✅ Valid commits
git commit -m "feat(users): add profile avatars"
git commit -m "fix: resolve navigation bug"
git commit -m "docs: update README"
# ❌ Invalid commits (will be rejected)
git commit -m "Added new feature" # No type
git commit -m "fix bug" # Missing colon
git commit -m "FEAT: new thing" # Uppercase typeTesting Locally
# Test commit message validation
echo "bad message" | npx commitlint # Should fail
echo "feat: good message" | npx commitlint # Should pass
# Dry-run semantic-release
bun release:dry-runRelease Workflow
Automatic Releases (Main Branch)
When changes are merged to main:
- Quality Checks - ESLint and TypeScript validation
- Testing - Backend and frontend tests run in parallel
- Release - If all checks pass:
- Semantic-release analyzes commits since last tag
- Determines version bump based on commit types
- Updates
CHANGELOG.mdwith categorized changes - Bumps version in
package.json - Commits changes with
[skip ci]to prevent loops - Creates git tag (e.g.,
v1.2.0) - Creates GitHub release with auto-generated notes
- Pushes tag and release commit back to repository
No Release Scenarios
Releases are skipped when:
- Branch is not
main - Only non-versioned commits (docs, style, test, etc.)
- Commit messages include
[skip ci] - Quality checks or tests fail
GitHub Workflow Configuration
Release Workflow (.github/workflows/release.yml)
name: Release
on:
push:
branches: [main]
jobs:
check-skip: # Skip if [skip ci] in commit
quality: # Lint & typecheck
test-backend: # Backend unit tests
test-frontend: # Frontend unit tests
release: # Semantic-release (if all pass)Features:
- Concurrency control prevents parallel releases
fetch-depth: 0ensures full git history for analysis- Proper GitHub permissions for creating releases
- Security-safe handling of commit messages via environment variables
Configuration Files
.releaserc.json
Semantic-release configuration:
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer", // Analyze commits
"@semantic-release/release-notes-generator", // Generate notes
"@semantic-release/changelog", // Update CHANGELOG.md
"@semantic-release/npm", // Bump package.json (no publish)
"@semantic-release/github", // Create GitHub release
"@semantic-release/git" // Commit changes back
]
}commitlint.config.js
Commit message validation rules:
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"perf",
"test",
"build",
"ci",
"chore",
"revert",
],
],
"type-case": [2, "always", "lower-case"],
"subject-empty": [2, "never"],
"header-max-length": [2, "always", 100],
},
};CHANGELOG.md Structure
Automatically generated changelog entries:
# Changelog
## [1.2.0] - 2025-01-22
### Features
- **auth**: Add two-factor authentication (#123)
- **billing**: Support annual subscriptions (#124)
### Bug Fixes
- **email**: Fix template rendering issue (#125)
### Performance
- **database**: Add indexes for user queries (#126)
## [1.1.0] - 2025-01-15
...Best Practices
Writing Good Commit Messages
✅ Good Examples:
feat(auth): add OAuth support for Microsoft
fix(billing): prevent duplicate charges on retry
perf(api): cache frequently accessed queries
docs(readme): update installation instructions❌ Bad Examples:
Added stuff # Too vague, no type
fix bug # Missing colon, no description
WIP # Not descriptive
Update files # No type, too genericCommit Message Tips
- Use imperative mood: "add" not "added" or "adds"
- Be specific: Include what and why
- Reference issues: Add
#123for issue/PR references - Keep it concise: Under 100 characters for header
- Add body for complex changes: Explain the "why"
Squash vs. Merge
Recommended: Squash and merge PRs
- Keeps main branch history clean
- Each PR becomes one commit
- Easier to revert features
- Commit message determines version bump
If using merge commits:
- All commits in PR affect versioning
- Ensure each commit follows conventions
- Consider rebasing before merge
Versioning Strategy
Version Numbers
Following Semantic Versioning:
- MAJOR (X.0.0) - Breaking changes
- MINOR (0.X.0) - New features (backward compatible)
- PATCH (0.0.X) - Bug fixes (backward compatible)
Pre-1.0.0 Development
During initial development (0.x.x):
- Breaking changes increment MINOR version
- Features and fixes increment PATCH version
- Release 1.0.0 when production-ready
Baseline Tagging
For existing projects without tags:
# Create baseline tag before first automated release
git tag v1.1.0 -m "Baseline for automated releases"
git push origin v1.1.0This prevents semantic-release from analyzing the entire commit history.
Troubleshooting
Release Not Created
Issue: Merged to main but no release created
Solutions:
- Check if commits trigger releases (feat, fix, etc.)
- Verify quality checks passed in GitHub Actions
- Check if
[skip ci]in commit message - Review release workflow logs
Version Bump Incorrect
Issue: Wrong version number assigned
Solutions:
- Review commit messages for correct types
- Check for breaking change markers (
!orBREAKING CHANGE:) - Verify all commits since last tag
- Use
bun release:dry-runto preview
Commitlint Rejecting Valid Messages
Issue: Local commits rejected despite correct format
Solutions:
- Check
commitlint.config.jsfor custom rules - Verify Husky hooks are installed (
bun prepare) - Test with:
echo "feat: test" | npx commitlint
CHANGELOG.md Conflicts
Issue: Merge conflicts in CHANGELOG.md
Solutions:
- Don't manually edit CHANGELOG.md on main
- Let semantic-release manage it automatically
- If conflicts occur, accept incoming changes
Manual Overrides
Skip Automated Release
Add [skip ci] to commit message:
git commit -m "chore: update dependencies [skip ci]"Force Specific Version
Not recommended, but possible via git tags:
# Not ideal - breaks automation
git tag v2.0.0 -m "Force major version"
git push origin v2.0.0Migration from Manual Versioning
If migrating from manual versioning:
- Create baseline tag with current version
- Update all developers on new commit format
- Enable commitlint in all development environments
- Review first automated release with dry-run
- Monitor releases for first few weeks
Related Documentation
- Git Workflow - Complete git workflow guide
- CLAUDE.md - Quick commit reference
- Conventional Commits - Full specification
- Semantic Versioning - Version numbering guide