Giao diện
Release Engineering - Tags, SemVer & Changelogs 🏷️
ROLE: HPN (Release Management).
AUDIENCE: Engineers shipping production software professionally.
Releasing software không chỉ là push code. Module này dạy bạn cách versioning đúng chuẩn, tagging releases, và auto-generate changelogs từ commit history.
🎯 Mục tiêu
Sau module này, bạn sẽ:
- Hiểu và áp dụng Semantic Versioning (SemVer)
- Tạo Git Tags đúng cách (Annotated vs Lightweight)
- Setup auto-changelog từ Conventional Commits
- Build professional release workflow
📐 Semantic Versioning (SemVer)
The Format
MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD]
Examples:
1.0.0 ← Initial release
1.0.1 ← Patch (bug fix)
1.1.0 ← Minor (new feature)
2.0.0 ← Major (breaking change)
2.0.0-alpha.1 ← Pre-release
2.0.0-rc.1 ← Release candidate
2.0.0+build.42 ← Build metadataWhen to Increment What?
SemVer Rules
| Change Type | Example | Version Change |
|---|---|---|
| Breaking API change | Remove endpoint, change signature | MAJOR |
| Deprecate feature | Mark as deprecated (still works) | MINOR + docs |
| New feature (backward compatible) | Add new endpoint | MINOR |
| Bug fix | Fix null pointer | PATCH |
| Performance improvement | Optimize query | PATCH |
| Documentation only | Update README | No change (or PATCH) |
| Dependency update (compatible) | Update lodash | PATCH |
| Dependency update (breaking) | Major dependency upgrade | MAJOR |
Pre-release Versions
1.0.0-alpha.1 ← Internal testing
1.0.0-alpha.2 ← More alpha testing
1.0.0-beta.1 ← External beta testing
1.0.0-rc.1 ← Release candidate
1.0.0-rc.2 ← Fix issues from rc.1
1.0.0 ← Stable release!Precedence: 1.0.0-alpha < 1.0.0-beta < 1.0.0-rc.1 < 1.0.0
HPN'S VERSIONING RULE
0.x.x = Development, anything can change
1.0.0 = First stable release, public API locked
1.x.x+ = Stable, follow SemVer strictlyĐừng release 1.0.0 quá sớm. Một khi bạn commit 1.0.0, breaking changes = increment MAJOR.
🏷️ Git Tags
Lightweight vs Annotated Tags
| Feature | Lightweight | Annotated |
|---|---|---|
| Storage | Just a pointer | Full Git object |
| Metadata | None | Tagger name, email, date, message |
| Signing | No | Yes (GPG/SSH) |
| Use case | Temporary/private | Releases |
ALWAYS USE ANNOTATED FOR RELEASES
Lightweight tags chỉ là pointer. Annotated tags có metadata và có thể signed. Production releases luôn dùng Annotated Tags.
Creating Tags
bash
# ❌ Lightweight tag (avoid for releases)
git tag v1.0.0
# ✅ Annotated tag (recommended)
git tag -a v1.0.0 -m "Release version 1.0.0"
# ✅ Signed annotated tag (best for production)
git tag -s v1.0.0 -m "Release version 1.0.0"
# Tag a specific commit
git tag -a v1.0.0 abc123 -m "Release version 1.0.0"Managing Tags
bash
# List all tags
git tag
# List tags with pattern
git tag -l "v1.*"
# Show tag details
git show v1.0.0
# Push single tag
git push origin v1.0.0
# Push all tags
git push origin --tags
# Delete local tag
git tag -d v1.0.0
# Delete remote tag
git push origin --delete v1.0.0
# or
git push origin :refs/tags/v1.0.0
# Checkout a tag (detached HEAD)
git checkout v1.0.0
# Create branch from tag
git checkout -b hotfix/v1.0.1 v1.0.0Tag Naming Conventions
bash
# Standard format
v1.0.0 # Production release
v1.0.0-rc.1 # Release candidate
v1.0.0-beta.1 # Beta
v1.0.0-alpha.1 # Alpha
# Alternative (without 'v' prefix)
1.0.0 # Some projects prefer this
# Environment tags (less common)
prod-2024-01-15
staging-abc123📝 Auto-Changelog Generation
The Foundation: Conventional Commits
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
---
Examples:
feat(auth): add OAuth2 login
fix(api): resolve memory leak in connection pool
docs(readme): update installation instructions
BREAKING CHANGE: remove deprecated endpointsTool: standard-version (Node.js)
bash
# Install
npm install --save-dev standard-version
# Add to package.json scripts
{
"scripts": {
"release": "standard-version",
"release:minor": "standard-version --release-as minor",
"release:major": "standard-version --release-as major"
}
}
# Usage
npm run release # Auto-determine version
npm run release:minor # Force minor bump
npm run release:major # Force major bumpWhat it does:
- Analyzes commit messages since last tag
- Determines version bump (based on conventional commits)
- Updates
package.jsonversion - Generates/updates
CHANGELOG.md - Creates commit and tag
Tool: conventional-changelog-cli
bash
# Install
npm install -g conventional-changelog-cli
# Generate changelog
conventional-changelog -p angular -i CHANGELOG.md -s
# First time (full history)
conventional-changelog -p angular -i CHANGELOG.md -s -r 0Tool: git-cliff (Rust - Fast)
bash
# Install
cargo install git-cliff
# Or via package managers
brew install git-cliff # macOS
winget install orhun.git-cliff # Windows
# Generate changelog
git cliff -o CHANGELOG.md
# Generate for specific range
git cliff v1.0.0..v2.0.0 -o CHANGELOG.mdConfiguration (cliff.toml):
toml
[changelog]
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
body = """
{% for group, commits in commits | group_by(attribute="group") %}
## {{ group | upper_first }}
{% for commit in commits %}
- {{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
footer = """
<!-- Generated by git-cliff -->
"""
[git]
conventional_commits = true
filter_unconventional = true
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^doc", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactoring" },
{ message = "^style", group = "Style" },
{ message = "^test", group = "Testing" },
]Example CHANGELOG.md Output
markdown
# Changelog
All notable changes to this project will be documented in this file.
## [2.0.0] - 2024-01-15
### ⚠️ BREAKING CHANGES
- Remove deprecated `/v1/users` endpoint
- Change authentication from API key to OAuth2
### Features
- Add user profile management
- Implement rate limiting per API key
- Add WebSocket support for real-time updates
### Bug Fixes
- Fix memory leak in connection pooling
- Resolve race condition in cache invalidation
## [1.2.0] - 2023-12-01
### Features
- Add bulk user import
- Implement email verification
### Bug Fixes
- Fix pagination offset calculation
## [1.1.0] - 2023-11-15
### Features
- Add user search functionality
- Implement role-based access control🔄 Complete Release Workflow
Manual Release
bash
# 1. Ensure clean state
git checkout main
git pull origin main
git status # Should be clean
# 2. Run tests
npm test
# 3. Update version (nếu không dùng auto-tool)
npm version minor # Updates package.json, creates commit and tag
# 4. Generate changelog (nếu không auto)
conventional-changelog -p angular -i CHANGELOG.md -s
git add CHANGELOG.md
git commit --amend --no-edit
# 5. Push with tags
git push origin main --follow-tagsAutomated Release (CI/CD)
yaml
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-releasesemantic-release Configuration
json
// .releaserc.json
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/github",
["@semantic-release/git", {
"assets": ["package.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]"
}]
]
}📊 Quick Reference
Version Commands
| Command | Effect |
|---|---|
npm version patch | 1.0.0 → 1.0.1 |
npm version minor | 1.0.0 → 1.1.0 |
npm version major | 1.0.0 → 2.0.0 |
npm version prerelease | 1.0.0 → 1.0.1-0 |
npm version 2.0.0-rc.1 | Explicit version |
Tag Commands
| Command | Purpose |
|---|---|
git tag -a v1.0.0 -m "msg" | Create annotated tag |
git tag -s v1.0.0 -m "msg" | Create signed tag |
git push origin v1.0.0 | Push single tag |
git push origin --tags | Push all tags |
git tag -d v1.0.0 | Delete local tag |
git push origin --delete v1.0.0 | Delete remote tag |
Changelog Tools
| Tool | Language | Best For |
|---|---|---|
standard-version | Node.js | npm projects, simple |
semantic-release | Node.js | Full automation, CI/CD |
git-cliff | Rust | Fast, customizable |
conventional-changelog | Node.js | Manual control |
💡 Key Takeaways
HPN'S INSIGHT
"Version numbers are a contract with your users. Breaking that contract (breaking changes without MAJOR bump) destroys trust."
- SemVer is a promise: MAJOR = breaking, MINOR = features, PATCH = fixes
- Tags are immutable: Một khi tag được push, không nên sửa
- Annotated > Lightweight: Always cho releases
- Conventional Commits enable automation: Invest vào commit format, reap benefits in changelog
- Automate releases: Less human error, more consistent
The Release Checklist
□ All tests passing
□ CHANGELOG.md updated
□ Version bumped (package.json, etc.)
□ Annotated tag created
□ Tag signed (production)
□ Pushed to remote with tags
□ GitHub/GitLab Release created
□ Notify stakeholdersDON'T MANUALLY EDIT TAGS
bash
# ❌ Này là anti-pattern
git tag -d v1.0.0
git tag -a v1.0.0 <different-commit> -m "..."
git push --force origin v1.0.0Nếu sai version, release version mới (v1.0.1), không sửa tag cũ.