first commit
Copilot Setup Steps / copilot-setup-steps (push) Has been cancelled

This commit is contained in:
2026-04-22 19:51:20 +07:00
commit 93d1b7c3d3
579 changed files with 99797 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env node
'use strict';
const {execSync} = require('node:child_process');
const path = require('node:path');
const ROOT = path.resolve(__dirname, '../..');
const REPO_URL = 'https://github.com/TryGhost/Ghost';
// Emoji priority order (lowest index = lowest priority, sorted descending)
const EMOJI_ORDER = ['💡', '🐛', '🎨', '💄', '✨', '🔒'];
// User-facing emojis — only these are included in release notes
const USER_FACING_EMOJIS = new Set(EMOJI_ORDER);
function getCommitLog(fromTag, toTag) {
const range = `${fromTag}..${toTag}`;
const format = '* %s - %an';
const cmd = `git log --no-merges --pretty=tformat:'${format}' ${range}`;
let log;
try {
log = execSync(cmd, {cwd: ROOT, encoding: 'utf8'}).trim();
} catch {
return [];
}
if (!log) {
return [];
}
return log.split('\n').map(line => line.trim());
}
function extractLeadingEmoji(line) {
// Line format: * <message> - <author>
const match = line.match(/^\* (.)/u);
return match ? match[1] : '';
}
function filterAndSortByEmoji(lines) {
const emojiLines = lines.filter((line) => {
const emoji = extractLeadingEmoji(line);
return USER_FACING_EMOJIS.has(emoji);
});
emojiLines.sort((a, b) => {
const emojiA = extractLeadingEmoji(a);
const emojiB = extractLeadingEmoji(b);
const indexA = EMOJI_ORDER.indexOf(emojiA);
const indexB = EMOJI_ORDER.indexOf(emojiB);
return indexB - indexA;
});
return emojiLines;
}
function generateReleaseNotes(fromTag, toTag) {
const lines = getCommitLog(fromTag, toTag);
const filtered = filterAndSortByEmoji(lines);
let body;
if (filtered.length === 0) {
body = 'This release contains fixes for minor bugs and issues reported by Ghost users.';
} else {
// Deduplicate (preserving order)
body = [...new Set(filtered)].join('\n');
}
body += `\n\n---\n\nView the changelog for full details: ${REPO_URL}/compare/${fromTag}...${toTag}`;
return body;
}
// CLI: node release-notes.js <from-tag> <to-tag>
if (require.main === module) {
const [fromTag, toTag] = process.argv.slice(2);
if (!fromTag || !toTag) {
console.error('Usage: node release-notes.js <from-tag> <to-tag>');
process.exit(1);
}
process.stdout.write(generateReleaseNotes(fromTag, toTag));
}
module.exports = {generateReleaseNotes};
+31
View File
@@ -0,0 +1,31 @@
const semver = require('semver');
const {execSync} = require('node:child_process');
/**
* Resolve the base git tag for diff/log comparisons during release preparation.
*
* For stable versions (e.g. "6.18.0"), returns "v6.18.0" — the tag for that version.
* For prerelease versions (e.g. "6.19.0-rc.0"), the tag "v6.19.0-rc.0" won't exist,
* so we find the most recent stable version tag in HEAD's ancestry using git describe.
*
* @param {string} version - The current Ghost version from package.json
* @param {string} repoDir - Path to the Ghost repo checkout
* @returns {{tag: string, isPrerelease: boolean}}
*/
function resolveBaseTag(version, repoDir) {
if (semver.prerelease(version)) {
const tag = execSync(
`git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' --exclude 'v*-*' HEAD`,
{cwd: repoDir, encoding: 'utf8'}
).trim();
return {tag, isPrerelease: true};
}
return {
tag: `v${version}`,
isPrerelease: false
};
}
module.exports = {resolveBaseTag};