Looking for a Semantic Release and Conventional Changelog configuration that allows for permissive types and scopes to generate nice changelog files with emoji?
This commit convention is based off of the ESLint commit convention with other types I found helpful or commonly used to ease the pain of remembering specific types that contributors use to a specific convention may have.
Chore: Did a thing that is not user-facing
Fix: Fixed a bug
New: Added a feature
Update: Iterated on a feature
Breaking: Changed the default behavior
View CHANGELOG.md to see all of the emojis and sorting of commits in action!
Git commits messages are broken into the following pieces Type(scope): Subject
or Type: Subject
where:
Type
is the category of change you are making- See valid options in Commit Types and Their Release Rules
- Case sensitive (title case)
- If multiple types could apply, either make your commits more focused on a specific change, or pick the type that best encapsulates the entire commit with the highest version bump
(scope)
is an optional declaration of the area of your project that your commit effects- Only affects the release rules for production dependencies (see
Package:
andUpgrade:
types) - Other than production dependencies, you or your project may decide how to to use this. As an example, you can use the kebab-case workspace name in a monorepo.
- Only affects the release rules for production dependencies (see
Subject
is a descriptive message that helps you and your teammates understand what you changed and why- Preferably starting with a capital letter to make scanning through git logs easier. Proper nouns with official
lowercase capitalization like
npm
are an exception. - No limit to the character length is imposed by this convention
- Consider omitting information about trivial related changes that are required to perform the primary change in the commit
- Consider placing the most important information at the beginning of the subject
- Preferably starting with a capital letter to make scanning through git logs easier. Proper nouns with official
lowercase capitalization like
Example Walkthrough
Imagine you maintain the is-number
package, you have this assortment of bunch of uncommitted changes on your machine:
- A new function
isNotNumber()
- A
devDependency
upgrade required for exportingisNotNumber()
- A correction for a typo in the JSDoc comment for
isNumber()
- A fix that makes sure for
isNumber(NaN)
returnsfalse
It would be best to break this out into multiple commits for readability and history, especially since you can make a pull request and release for the new feature separate from the unrelated, potentially breaking change and typo. These would be some excellent individual commit messages:
New: Add negated isNotNumber() function
Upgrade(dev): Update rollup to support exporting multiple functions
Docs: Fix typo in JSDoc comment
Fix: NaN is not a number
if your project deems this fix a regression,Breaking: NaN is not a number
otherwise
If we imagine the fix is not a regression, and we can't easily separate these changes into separate commits, which is the unfortunately the reality of some major implementation discoveries and refactors; we can use one commit focused on the most important information:
Breaking: NaN is not a number, add isNotNumber()
- Uses
Breaking:
because of the breaking change in the bug fix (highest applicable release rule) - Puts the breaking change subject first (since it had the highest release rule)
- Omits the rollup upgrade information since it was an internal required change to export multiple functions. Maybe instead add a comment on the pull request explaining why you needed to do it instead.
- Omits the trivial typo information. This may be confusing to see in git blame, but at least it's not causing mental overload when reading the git log.
Use when your commit includes a breaking change for users of your project. This may include narrowing the range of
supported Node.js
or peerDependency
versions as well. Upgrading non-peer dependencies to their next major version
may not necessitate a breaking change if that breaking change from the dependency only affected your project and not
consumers of your project.
Breaking:
(preferred)Major:
Use when adding a new feature to your project.
If the new feature may change the behavior of your project unexpectedly for some users, consider Breaking
to release a
major bump instead.
Feature:
Feat:
New:
Use when improving features that already exist in your project.
If the improvement may change the behavior of your project unexpectedly for some users, consider Breaking
to release a
major bump instead.
Improvement:
Improve:
Update:
Use when updating documentation including JSDoc comments, the readme, the wiki, or when adding examples.
Documentation:
Docs:
Readme:
Use when fixing any type of bug.
If the fix is a breaking change that isn't a regression hotfix, consider Breaking
to release a major bump instead.
Fix:
Optionally use when applying accessibility-specific bug fixes to call out this fix in the changelog.
Accessibility:
Access:
A11y:
Optionally use when applying performance-specific bug fixes and tuning to call out this fix in the changelog.
Performance:
Perf:
Use when updating production dependencies
to release any fixes they may have to your users.
Package(user):
Package(*-user):
(wildcard)Package(prod):
Package(*-prod):
(wildcard)Upgrade(user):
Upgrade(*-user):
(wildcard)Upgrade(prod):
Upgrade(*-prod):
(wildcard)
Use when updating unspecified dependencies or devDependencies
to prevent releasing when bumping the minium packages
your project only uses internally.
If the upgrade may affect your project's behavior (e.g. updating your build tool), consider Fix
to release a patch
bump instead so if it breaks your project unexpectedly, you can fix it while it's fresh on your mind.
Package:
Package(dev):
Package(*-dev):
(wildcard)Upgrade:
Upgrade(dev):
Upgrade(*-dev):
(wildcard)
Use when you're tinkering with the CI, linter (or trivial errors from the linter), build step, or other project configuration.
If the config change may affect your project's behavior (e.g. building with a different tool), consider Fix
to
release a patch bump instead so if it breaks your project unexpectedly, you can fix it while it's fresh on your mind.
Config:
CI:
Build:
Lint:
Use when adding or modifying tests.
If you are changing the released version of your package or application behavior to make a test pass, consider Fix
to
release a patch bump instead so your users can use the improved behavior.
Test:
Tests:
Use when you're making some other change that will not affect the released version of your package or application.
If the refactor or internal change may affect your project's behavior, consider Fix
to release a patch bump instead
so if it breaks your project unexpectedly, you can fix it while it's fresh on your mind.
Internal:
Refactor:
Cleanup:
Chore:
Use when expecting to squash your commits, in over your head with changes in git, or in case of fire (joke).
WIP:
These typically should not be used as the other types provide many options for expressing the changes, or at very least
simply expressing the desired version bump with Breaking
, Update
, Fix
, and Chore
.
Release:
(used by semantic release)Other:
# Install all of the things
npm install --save-dev @semantic-release/changelog @semantic-release/git commitlint husky semantic-release conventional-changelog-evelyn
To set up commitlint
, add the following to your package.json
file.
package.json
(snippet)
{
"...": "...",
"commitlint": {
"extends": "./node_modules/conventional-changelog-evelyn/commitlint.config.js"
}
}
And make sure commitlint
is run when committing using a git hook via Husky.
npm install --save-dev husky
npx husky init
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg
Now, using git commit
in the CLI or GUI will automatically check your commit message against the commit convention. If
you have trouble, make sure you have a valid git hook setup, especially on Windows where some git clients need to be
told where Git Bash is installed.
Complete commitlint
local setup instructions
To set up semantic-release
, add the following to your package.json
file.
package.json
(snippet)
{
"...": "...",
"release": {
"extends": "conventional-changelog-evelyn/release.config.js"
}
}
You may use this GitHub Actions configuration to have GitHub release automatically in CI.
name: nodejs
on: push
jobs:
release:
needs: testing
runs-on: ubuntu-latest
env:
CI: true
steps:
- uses: actions/checkout@v4
- name: Use Node.js 22.x
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: Install Dependencies
run: npm ci
- name: Release
run: npx semantic-release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
To make sure semantic-release can release, it needs an npm API token as a secret named
NPM_TOKEN
and
a GitHub personal access token named
GH_TOKEN
which has permission to write to repo contents, issues, and pull requests.
When on a maintenance branch (e.g. 2.x.x
) or the main
, master
, beta
, or alpha
branches and there are new
commits that should trigger a release; this will automatically:
- Increment the
package.json
version (whether to bumpMAJOR
,Minor
, orpatch
is chosen based on commits) - Generate or update the
CHANGELOG.md
file with the release notes npm publish
the new version- Add a git tag and GitHub release with the release notes
- Leave comments on referenced GitHub issues and pull requests in the project
- Commit the latest
package.json
version and latestCHANGELOG.md
to the git repository
When on main
or master
, a new release is made that becomes your latest version on npm.
When on beta
or alpha
, a new release is made with prerelease status on npm and GitHub releases, and the version is
suffixed with -beta.x
or -alpha.x
respectfully, where x
is the number of prereleases made on that unreleased version.
When on a maintenance branch, it will release only new versions compatible with that branch name. E.g. 2.1.0
can be
bumped to 2.1.1
by adding a commit that has the Fix:
type in the message on the 2.x.x
branch even if the latest
version on npm is 3.0.0
.
Copyright Evelyn Hathaway, MIT License