Skip to main content

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

  1. Review the patterns and examples below
  2. Apply the relevant patterns to your implementation
  3. 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-PatternProblemSolution
Inconsistent commit formatSome commits follow convention, others don'tEnforce with pre-commit hook (husky + commitlint)
Manual changelog editingDefeats automation purposeUse generated changelog, add notes in commit body
Skipping hooks with --no-verifyBypasses validationOnly use --no-verify for emergencies, fix commits properly
Breaking changes without BREAKING CHANGE footerPATCH bump instead of MAJORUse BREAKING CHANGE: in commit body or ! in type (feat!)
Too many commit typesCustom types break toolingStick to conventional types (feat, fix, docs, etc.)
No dry-run testingProduction release mistakesAlways test with --dry-run flag first
Editing release PRs manuallyConflicts with automationLet release-please manage version/changelog PRs
Multiple release toolsConflicting version bumpsChoose 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: