fix(release): conventionalcommits preset so semantic-release keeps ! commits

Switch commit-analyzer and release-notes-generator from the angular default
to the conventionalcommits preset so feat!:/fix!: breaking commits are no
longer silently dropped. Add the conventional-changelog-conventionalcommits
devDep and a workflow guard step that fails if a release-worthy feat/fix
commit produces no release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcus Breiden 2026-07-01 13:00:01 +00:00
parent 82c8ed6df2
commit 4619dfb61f
4 changed files with 44 additions and 2 deletions

View file

@ -37,6 +37,23 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
# Catch the silent-drop class where a release-worthy feat/fix commit
# produces no release (e.g. commit-analyzer left on the angular preset,
# whose headerPattern has no '!' and drops feat!:/fix!: commits). If a
# release was cut, the new tag is the most recent reachable one and the
# range below is empty of feat/fix; if not, the dropped commit is still
# in range → fail.
- name: Guard against silently-dropped releases
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
RANGE="${LAST_TAG:+$LAST_TAG..}HEAD"
if git log "$RANGE" --format='%s' | grep -qE '^(feat|fix)(\(.+\))?!?:'; then
echo "::error::Release-worthy feat/fix commit(s) present since ${LAST_TAG:-<root>} but no release was cut — likely a commit-analyzer preset/config drop (angular preset ignores '!')."
git log "$RANGE" --format=' %s' | grep -E '^ (feat|fix)(\(.+\))?!?:'
exit 1
fi
echo "Release guard OK (no un-released feat/fix commits since ${LAST_TAG:-<root>})."
- name: Attest build provenance
if: hashFiles('build/main.js') != ''
uses: actions/attest-build-provenance@v2

View file

@ -2,8 +2,18 @@
"branches": ["main"],
"tagFormat": "${version}",
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits"
}
],
"@semantic-release/changelog",
[
"@semantic-release/npm",

14
package-lock.json generated
View file

@ -22,6 +22,7 @@
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitest/coverage-v8": "^4.1.8",
"conventional-changelog-conventionalcommits": "^9.0.0",
"esbuild": "^0.28.1",
"esbuild-sass-plugin": "3.3.1",
"eslint": "9.39.4",
@ -4513,6 +4514,19 @@
"node": ">=18"
}
},
"node_modules/conventional-changelog-conventionalcommits": {
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.3.1.tgz",
"integrity": "sha512-dTYtpIacRpcZgrvBYvBfArMmK2xvIpv2TaxM0/ZI5CBtNUzvF2x0t15HsbRABWprS6UPmvj+PzHVjSx4qAVKyw==",
"dev": true,
"license": "ISC",
"dependencies": {
"compare-func": "^2.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/conventional-changelog-writer": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.4.0.tgz",

View file

@ -37,6 +37,7 @@
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitest/coverage-v8": "^4.1.8",
"conventional-changelog-conventionalcommits": "^9.0.0",
"esbuild": "^0.28.1",
"esbuild-sass-plugin": "3.3.1",
"eslint": "9.39.4",