Files
bookorbit/release.config.js
T

168 lines
4.6 KiB
JavaScript

"use strict";
const { spawnSync } = require("child_process");
const DOCKER_IMAGE = "ghcr.io/bookorbit/bookorbit";
// Maps local git author names to GitHub usernames for @-mentions in release notes.
const AUTHOR_MAP = {
neon: "neonsolstice",
};
const TYPES = [
{ type: "feat", section: "Features" },
{ type: "fix", section: "Bug Fixes" },
{ type: "security", section: "Security" },
{ type: "perf", section: "Performance" },
{ type: "db", section: "Database" },
{ type: "style", section: "Visual Changes" },
];
// Uses {{commitUrl}} (pre-computed per-commit in finalizeContext) instead of
// {{commitUrlFormat}} which does not resolve inside Handlebars partials.
const commitPartial = `\
*{{#if scope}} **{{scope}}:**
{{~/if}} {{#if subject}}
{{~subject}}
{{~else}}
{{~header}}
{{~/if}}
{{~!-- commit link --}}{{~#if hash}} {{#if commitUrl~}}
([{{shortHash}}]({{commitUrl}}))
{{~else}}
{{~shortHash}}
{{~/if}}{{~/if}}
{{~#if githubUser}} by @{{githubUser}}{{/if}}
{{~!-- commit references --}}
{{~#if references~}}
, closes
{{~#each references}} {{#if @root.linkReferences~}}
[
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}{{this.prefix}}{{this.issue}}]({{issueUrlFormat}})
{{~else}}
{{~#if this.owner}}
{{~this.owner}}/
{{~/if}}
{{~this.repository}}{{this.prefix}}{{this.issue}}
{{~/if}}{{/each}}
{{~/if}}
`;
// Main template: removes the version header (GitHub Release already shows it),
// strips the warning emoji from breaking-changes headings, and appends a
// Docker pull block after the commit groups.
const mainTemplate = [
"{{#if noteGroups}}",
"{{#each noteGroups}}",
"",
"### {{title}}",
"",
"{{#each notes}}",
"* {{#if commit.scope}}**{{commit.scope}}:** {{/if}}{{text}}",
"{{/each}}",
"{{/each}}",
"{{/if}}",
"{{#each commitGroups}}",
"",
"{{#if title}}",
"### {{title}}",
"",
"{{/if}}",
"{{#each commits}}",
"{{> commit root=@root}}",
"",
"{{/each}}",
"",
"{{/each}}",
"---",
"",
"**Docker**",
"",
"```bash",
`docker pull ${DOCKER_IMAGE}:{{version}}`,
"```",
"",
"Multi-arch: `linux/amd64` and `linux/arm64`.",
].join("\n");
// Runs after the preset transform. Looks up each commit's author via git log,
// maps git name -> GitHub username, and injects githubUser into each commit
// for the commitPartial.
function finalizeContext(ctx) {
try {
const result = spawnSync("git", ["log", "--format=%h %aN", "--max-count=500"], {
encoding: "utf8",
cwd: process.cwd(),
});
const shaToGithubUser = new Map();
if (result.status === 0) {
for (const line of result.stdout.split("\n").filter(Boolean)) {
const spaceIdx = line.indexOf(" ");
const shortSha = line.substring(0, spaceIdx);
const authorName = line.substring(spaceIdx + 1).trim();
if (!authorName || /\[bot\]/i.test(authorName)) continue;
shaToGithubUser.set(shortSha, AUTHOR_MAP[authorName] ?? authorName);
}
}
for (const group of ctx.commitGroups ?? []) {
for (const commit of group.commits ?? []) {
if (commit.shortHash) {
const githubUser = shaToGithubUser.get(commit.shortHash);
if (githubUser) commit.githubUser = githubUser;
}
// Pre-compute commit URL — {{commitUrlFormat}} does not resolve inside
// Handlebars partials because partials don't walk the parent context chain.
if (commit.hash && ctx.host && ctx.owner && ctx.repository) {
commit.commitUrl = `${ctx.host}/${ctx.owner}/${ctx.repository}/commit/${commit.hash}`;
}
}
}
} catch {
// non-fatal: commits render without author attribution
}
return ctx;
}
module.exports = {
branches: ["main"],
repositoryUrl: "https://github.com/bookorbit/bookorbit",
tagFormat: "v${version}",
plugins: [
[
"@semantic-release/commit-analyzer",
{
preset: "conventionalcommits",
releaseRules: [
{ type: "feat", release: "minor" },
{ type: "fix", release: "patch" },
{ type: "perf", release: "patch" },
{ type: "security", release: "patch" },
{ type: "db", release: "patch" },
{ type: "style", release: "patch" },
{ type: "revert", release: false },
],
},
],
[
"@semantic-release/release-notes-generator",
{
preset: "conventionalcommits",
linkReferences: true,
presetConfig: { types: TYPES },
writerOpts: {
commitPartial,
mainTemplate,
finalizeContext,
},
},
],
"@semantic-release/github",
],
};