Changelog Automation Skill
Changelog Automation Skill
When to Use This Skill
Use this skill when implementing changelog automation patterns in your codebase.
How to Use This Skill
- Review the patterns and examples below
- Apply the relevant patterns to your implementation
- Follow the best practices outlined in this skill
Automated changelog generation and release management using conventional commits and modern release tools.
Conventional Commits
Commit Format
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Commit Types
feat: New feature (MINOR version bump)
fix: Bug fix (PATCH version bump)
docs: Documentation changes
style: Code style (formatting, semicolons)
refactor: Code refactoring
perf: Performance improvements
test: Adding/updating tests
build: Build system changes
ci: CI configuration
chore: Maintenance tasks
revert: Revert previous commit
BREAKING CHANGE: in footer triggers MAJOR version bump
Examples
# Feature with scope
feat(auth): add OAuth2 login support
# Bug fix
fix: resolve null pointer in user service
# Breaking change
feat(api)!: change response format for /users endpoint
BREAKING CHANGE: Response now returns { data: [...] } instead of array
# Multiple footers
fix(database): handle connection timeout
Closes #123
Reviewed-by: John Doe
Commitlint Setup
npm install --save-dev @commitlint/cli @commitlint/config-conventional
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert'
]
],
'scope-enum': [
2,
'always',
['api', 'auth', 'database', 'ui', 'core', 'deps']
],
'subject-case': [2, 'always', 'lower-case'],
'header-max-length': [2, 'always', 72],
'body-max-line-length': [2, 'always', 100]
}
}
Husky Integration
npm install --save-dev husky
npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
Release-Please
GitHub Action Setup
# .github/workflows/release-please.yml
name: Release Please
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
release-please:
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
version: ${{ steps.release.outputs.version }}
steps:
- uses: google-github-actions/release-please-action@v4
id: release
with:
release-type: node
package-name: my-package
changelog-types: |
[
{"type": "feat", "section": "Features", "hidden": false},
{"type": "fix", "section": "Bug Fixes", "hidden": false},
{"type": "perf", "section": "Performance", "hidden": false},
{"type": "docs", "section": "Documentation", "hidden": false},
{"type": "chore", "section": "Maintenance", "hidden": true}
]
publish:
needs: release-please
if: ${{ needs.release-please.outputs.release_created }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Configuration
// release-please-config.json
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"packages": {
".": {
"release-type": "node",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": true,
"draft": false,
"prerelease": false,
"changelog-sections": [
{"type": "feat", "section": "Features"},
{"type": "fix", "section": "Bug Fixes"},
{"type": "perf", "section": "Performance Improvements"},
{"type": "revert", "section": "Reverts"},
{"type": "docs", "section": "Documentation"},
{"type": "build", "section": "Build System"},
{"type": "ci", "section": "Continuous Integration"}
],
"extra-files": [
"src/version.ts",
"docs/version.md"
]
}
}
}
Manifest
// .release-please-manifest.json
{
".": "1.2.3"
}
Semantic Release
Setup
npm install --save-dev semantic-release @semantic-release/changelog @semantic-release/git
Configuration
// release.config.js
module.exports = {
branches: [
'main',
{ name: 'beta', prerelease: true },
{ name: 'alpha', prerelease: true }
],
plugins: [
['@semantic-release/commit-analyzer', {
preset: 'conventionalcommits',
releaseRules: [
{ type: 'feat', release: 'minor' },
{ type: 'fix', release: 'patch' },
{ type: 'perf', release: 'patch' },
{ type: 'revert', release: 'patch' },
{ type: 'docs', scope: 'README', release: 'patch' },
{ breaking: true, release: 'major' }
]
}],
['@semantic-release/release-notes-generator', {
preset: 'conventionalcommits',
presetConfig: {
types: [
{ type: 'feat', section: 'Features' },
{ type: 'fix', section: 'Bug Fixes' },
{ type: 'perf', section: 'Performance' },
{ type: 'revert', section: 'Reverts' },
{ type: 'docs', section: 'Documentation', hidden: true },
{ type: 'chore', hidden: true }
]
}
}],
['@semantic-release/changelog', {
changelogFile: 'CHANGELOG.md'
}],
['@semantic-release/npm', {
npmPublish: true
}],
['@semantic-release/git', {
assets: ['CHANGELOG.md', 'package.json', 'package-lock.json'],
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}'
}],
'@semantic-release/github'
]
}
GitHub Action
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- name: Release
run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Standard Version
Setup
npm install --save-dev standard-version
Configuration
// .versionrc.json
{
"types": [
{"type": "feat", "section": "Features"},
{"type": "fix", "section": "Bug Fixes"},
{"type": "perf", "section": "Performance"},
{"type": "docs", "section": "Documentation"},
{"type": "chore", "hidden": true},
{"type": "style", "hidden": true},
{"type": "refactor", "hidden": true},
{"type": "test", "hidden": true}
],
"commitUrlFormat": "{{host}}/{{owner}}/{{repository}}/commit/{{hash}}",
"compareUrlFormat": "{{host}}/{{owner}}/{{repository}}/compare/{{previousTag}}...{{currentTag}}",
"bumpFiles": [
{
"filename": "package.json",
"type": "json"
},
{
"filename": "src/version.ts",
"updater": "scripts/version-updater.js"
}
],
"skip": {
"changelog": false,
"commit": false,
"tag": false
}
}
npm Scripts
{
"scripts": {
"release": "standard-version",
"release:minor": "standard-version --release-as minor",
"release:major": "standard-version --release-as major",
"release:patch": "standard-version --release-as patch",
"release:dry-run": "standard-version --dry-run",
"release:first": "standard-version --first-release"
}
}
Changelog Format
Keep a Changelog Standard
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- New feature description
### Changed
- Modified behavior description
### Deprecated
- Features to be removed
### Removed
- Removed features
### Fixed
- Bug fix description
### Security
- Security fix description
## [1.2.0] - 2024-01-15
### Added
- OAuth2 authentication support (#123)
- User profile customization
### Fixed
- Memory leak in connection pool (#456)
## [1.1.0] - 2024-01-01
### Added
- Initial release
[Unreleased]: https://github.com/org/repo/compare/v1.2.0...HEAD
[1.2.0]: https://github.com/org/repo/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/org/repo/releases/tag/v1.1.0
Monorepo Support
Changesets
npm install --save-dev @changesets/cli
npx changeset init
# .changeset/config.json
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
Creating Changesets
# Interactive CLI
npx changeset
# Creates .changeset/random-name.md
---
"@scope/package-a": minor
"@scope/package-b": patch
---
Added new feature to package-a that requires update to package-b
Release Workflow
# .github/workflows/changesets.yml
name: Changesets
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- name: Create Release PR or Publish
uses: changesets/action@v1
with:
publish: npm run release
version: npm run version
commit: "chore: version packages"
title: "chore: version packages"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
PR Automation
Auto-Label PRs
# .github/labeler.yml
feature:
- head-branch: ['^feat/', '^feature/']
bugfix:
- head-branch: ['^fix/', '^bugfix/']
documentation:
- changed-files:
- any-glob-to-any-file: ['docs/**', '*.md']
dependencies:
- head-branch: ['^dependabot/', '^renovate/']
Release Drafter
# .github/release-drafter.yml
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
categories:
- title: 'Features'
labels: ['feature', 'enhancement']
- title: 'Bug Fixes'
labels: ['fix', 'bugfix', 'bug']
- title: 'Maintenance'
labels: ['chore', 'dependencies']
- title: 'Documentation'
labels: ['documentation', 'docs']
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&'
version-resolver:
major:
labels: ['major', 'breaking']
minor:
labels: ['minor', 'feature', 'enhancement']
patch:
labels: ['patch', 'fix', 'bugfix']
default: patch
template: |
## Changes
$CHANGES
## Contributors
$CONTRIBUTORS
Usage Examples
Setup Conventional Commits
Apply changelog-automation skill to configure commitlint with husky for commit validation
Implement Release Automation
Apply changelog-automation skill to setup release-please with GitHub Actions for automated releases
Configure Monorepo Releases
Apply changelog-automation skill to implement changesets for managing monorepo package versions
Success Output
When successful, this skill MUST output:
✅ SKILL COMPLETE: changelog-automation
Completed:
- [x] Conventional commits configured (commitlint + husky)
- [x] Release automation setup ({tool}: release-please/semantic-release/standard-version)
- [x] Changelog format configured (Keep a Changelog standard)
- [x] Version bumping strategy defined (MAJOR/MINOR/PATCH)
- [x] GitHub Actions workflow created
- [x] Commit hooks installed and tested
Outputs:
- Configuration files: commitlint.config.js, .versionrc.json, release-please-config.json
- GitHub workflow: .github/workflows/{workflow_name}.yml
- Hooks: .husky/commit-msg
Validation:
- Test commit passed: ✅ feat(scope): test message
- Invalid commit blocked: ✅ bad commit message → rejected
Completion Checklist
Before marking this skill as complete, verify:
- Commitlint installed and configured with conventional commits preset
- Husky hooks installed (.husky/commit-msg)
- Test commit with valid format passes validation
- Test commit with invalid format is rejected
- Release automation tool configured (release-please/semantic-release)
- GitHub Actions workflow file created and pushed
- Changelog format follows Keep a Changelog standard
- Version bump rules defined (feat→MINOR, fix→PATCH, BREAKING→MAJOR)
- Package.json scripts added (release, release:dry-run, etc.)
- Documentation updated with commit message guidelines
Failure Indicators
This skill has FAILED if:
- ❌ Commitlint not blocking invalid commit messages
- ❌ Husky hooks not executing on git commit
- ❌ GitHub Actions workflow has syntax errors
- ❌ Release automation creates invalid version bumps
- ❌ Changelog generation fails or produces empty output
- ❌ Breaking changes don't trigger MAJOR version bump
- ❌ Package.json version not updated after release
- ❌ Git tags not created on release
- ❌ Conventional commit types not recognized (feat, fix, docs, etc.)
When NOT to Use
Do NOT use this skill when:
- Manual versioning required - Legal/compliance dictates version numbers
- Pre-1.0 rapid prototyping - Overhead slows down early iteration
- Non-npm projects without package.json - Tooling assumes Node.js ecosystem
- Single-developer hobby projects - Overhead exceeds benefit for solo work
- Closed-source with no releases - Internal-only code doesn't need changelogs
- Fork with upstream sync - Conflicts with upstream versioning strategy
Use alternative approaches instead:
- Manual versioning → Keep a Changelog manual updates with git tags
- Prototypes → Simple git log and manual notes
- Non-npm → Use language-specific tools (setuptools for Python, Cargo for Rust)
- Solo projects → Manual CHANGELOG.md with notable changes only
- Internal code → Version in project plan docs, not package.json
Anti-Patterns (Avoid)
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Inconsistent commit format | Some commits follow convention, others don't | Enforce with pre-commit hook (husky + commitlint) |
| Manual changelog editing | Defeats automation purpose | Use generated changelog, add notes in commit body |
| Skipping hooks with --no-verify | Bypasses validation | Only use --no-verify for emergencies, fix commits properly |
| Breaking changes without BREAKING CHANGE footer | PATCH bump instead of MAJOR | Use BREAKING CHANGE: in commit body or ! in type (feat!) |
| Too many commit types | Custom types break tooling | Stick to conventional types (feat, fix, docs, etc.) |
| No dry-run testing | Production release mistakes | Always test with --dry-run flag first |
| Editing release PRs manually | Conflicts with automation | Let release-please manage version/changelog PRs |
| Multiple release tools | Conflicting version bumps | Choose ONE tool (release-please OR semantic-release OR standard-version) |
Principles
This skill embodies CODITECT principles:
- #5 Eliminate Ambiguity - Conventional commits enforce consistent format
- #6 Clear, Understandable, Explainable - Changelog clearly shows what changed
- #8 No Assumptions - Commit types explicitly declare intent (feat vs fix)
- First Principles - Version numbers communicate change type (semantic versioning)
- Automation - Eliminate manual version bumping and changelog writing
- Separation of Concerns - Commits describe changes, automation handles release
Related Standards: