Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 68 additions & 29 deletions .release-it.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,71 @@ const types = new Map([
const normalizeRepoUrl = url => url.replace(/^git\+/, "").replace(/\.git$/, "");
const repoUrl = pkg?.repository?.url ? normalizeRepoUrl(pkg.repository.url) : null;

module.exports = () => {
const breakingChangePattern = /\bBREAKING(?: |-)?CHANGE\b/i;

function hasBreakingChange(commit) {
if (commit.breaking) {
return true;
}

const type = String(commit.type || "").trim();

if (type.endsWith("!")) {
return true;
}

if (typeof commit.header === "string" && /^\w+(?:\([^)]+\))?!:/.test(commit.header)) {
return true;
}

if (
commit.notes?.some(note =>
[note.title, note.text].some(value => typeof value === "string" && breakingChangePattern.test(value))
)
) {
return true;
}

return typeof commit.footer === "string" && breakingChangePattern.test(commit.footer);
}

function whatBump(commits, currentVersion = pkg.version) {
let isBreaking = false;
let isMinor = false;
let isPatch = false;

for (const commit of commits) {
if (hasBreakingChange(commit)) {
isBreaking = true;
}

const type = String(commit.type || "")
.trim()
.toLowerCase()
.replace(/!+$/, "");

if (["feat", "revert"].includes(type)) {
isMinor = true;
}

if (["fix", "perf", "refactor", "ci"].includes(type)) {
isPatch = true;
}
}

if (isBreaking) {
const currentMajor = Number.parseInt(String(currentVersion).replace(/^v/i, "").split(".")[0], 10);

return {level: Number.isNaN(currentMajor) || currentMajor >= 1 ? 0 : 1};
}

if (isMinor) return {level: 1};
if (isPatch) return {level: 2};

return null;
}

const createReleaseConfig = () => {
const contributors = getContributors();

return {
Expand Down Expand Up @@ -167,34 +231,7 @@ module.exports = () => {
contributors,
},

whatBump: commits => {
let isMajor = false;
let isMinor = false;
let isPatch = false;

for (const commit of commits) {
if (commit.notes?.some(n => /BREAKING CHANGE/i.test(n.title || n.text || ""))) {
isMajor = true;
break;
}

const type = (commit.type || "").toLowerCase();

if (type === "feat") {
isMinor = true;
}

if (["fix", "perf", "refactor", "ci"].includes(type)) {
isPatch = true;
}
}

if (isMajor) return {level: 0};
if (isMinor) return {level: 1};
if (isPatch) return {level: 2};

return null;
},
whatBump,
writerOpts: {
headerPartial:
"## 🚀 Release {{#if name}}`{{name}}` {{else}}{{#if @root.pkg}}`{{@root.pkg.name}}` {{/if}}{{/if}}v{{version}} ({{date}})\n\n",
Expand Down Expand Up @@ -253,3 +290,5 @@ module.exports = () => {
},
};
};

module.exports = Object.assign(createReleaseConfig, {whatBump});
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,13 @@ Breaking changes:

## What affects versioning (SemVer policy)
Version bumps are derived from commit history via `@release-it/conventional-changelog` and our policy:
- MAJOR (`x.0.0`) — any commit containing `BREAKING CHANGE` notes.
- MINOR (`0.y.0`) — `feat` and `revert` commits.
- MAJOR (`x.0.0`) — a breaking commit when the current version is `1.0.0` or newer.
- MINOR (`0.y.0`) — `feat` and `revert` commits, plus breaking commits while the package is on `0.x`.
- PATCH (`0.0.z`) — `fix`, `perf`, `refactor`, `ci`.
- No bump by default — `docs`, `test`, `chore`, `build` (these do not trigger an automatic release by themselves).

Notes:
- Both the `type!:` syntax and a `BREAKING CHANGE:`/`BREAKING-CHANGE:` footer use the same breaking policy.
- If multiple types are present, the highest applicable level wins.
- Only visible types appear in the generated CHANGELOG; some meta types are hidden from release notes.

Expand Down Expand Up @@ -174,4 +175,4 @@ Review process:
If you discover a security issue, please do not open a public issue. Instead, email the maintainers at
`addonbonedev@gmail.com` with the details. We will coordinate a fix and disclosure.

Thank you for contributing!
Thank you for contributing!
Loading
Loading