Add changelog helpers

This commit is contained in:
Michael B. Gale
2026-07-14 12:41:53 +01:00
parent c8ed70e459
commit 639fc5d7ea
2 changed files with 109 additions and 1 deletions

View File

@@ -15,6 +15,9 @@ export const PR_CHECK_EXCLUDED_FILE = path.join(PR_CHECKS_DIR, "excluded.yml");
/** The path of the main `package.json`. */
export const PACKAGE_JSON = path.join(REPO_ROOT, "package.json");
/** THe path of the changelog. */
export const CHANGELOG_FILE = path.join(REPO_ROOT, "CHANGELOG.md");
/** The path to the esbuild metadata file. */
export const BUNDLE_METADATA_FILE = path.join(REPO_ROOT, "meta.json");

View File

@@ -5,7 +5,7 @@ import * as fs from "node:fs";
import { parseArgs } from "node:util";
import { type ApiClient, getApiClient } from "./api-client";
import { PACKAGE_JSON, REPO_ROOT } from "./config";
import { CHANGELOG_FILE, PACKAGE_JSON, REPO_ROOT } from "./config";
/** Placeholder changelog content for a new release. */
const EMPTY_CHANGELOG = `# CodeQL Action Changelog
@@ -148,6 +148,111 @@ export function getCurrentVersion(): string | undefined {
return pkg.version;
}
/** Returns today's date formatted as `DD Mon YYYY`. */
export function getTodayString(): string {
const today = new Date();
return today.toLocaleDateString("en-GB", {
day: "2-digit",
month: "short",
year: "numeric",
});
}
/**
* Updates the `[UNRELEASED]` marker in `CHANGELOG.md` with the given version
* and today's date.
*/
export function updateChangelog(version: string): void {
let content: string;
if (fs.existsSync(CHANGELOG_FILE)) {
content = fs.readFileSync(CHANGELOG_FILE, "utf8");
} else {
content = EMPTY_CHANGELOG;
}
const newContent = content.replace(
"[UNRELEASED]",
`${version} - ${getTodayString()}`,
);
fs.writeFileSync(CHANGELOG_FILE, newContent, "utf8");
}
/**
* Processes changelog entries for a backport, converting version references
* from the source major version to the target major version and filtering
* entries that only apply to newer versions.
*/
export function processChangelogForBackports(
sourceBranchMajorVersion: string,
targetBranchMajorVersion: string,
): void {
const content = fs.readFileSync(CHANGELOG_FILE, "utf8");
const lines = content.split("\n");
const someVersionsOnlyRegex = /\[v(\d+)\+ only\]/;
let output = "";
let i = 0;
// Copy lines until we find the first section heading.
let foundFirstSection = false;
while (!foundFirstSection && i < lines.length) {
let line = lines[i];
if (line.startsWith("## ")) {
line = line.replace(
`## ${sourceBranchMajorVersion}`,
`## ${targetBranchMajorVersion}`,
);
foundFirstSection = true;
}
output += `${line}\n`;
i++;
}
if (!foundFirstSection) {
throw new Error("Could not find any change sections in CHANGELOG.md");
}
// Process remaining lines.
let foundContent = false;
output += "\n";
while (i < lines.length) {
let line = lines[i];
i++;
// Filter out changelog entries that only apply to newer versions.
const match = someVersionsOnlyRegex.exec(line);
if (match) {
if (
Number.parseInt(targetBranchMajorVersion) < Number.parseInt(match[1])
) {
continue;
}
}
if (line.startsWith("## ")) {
line = line.replace(
`## ${sourceBranchMajorVersion}`,
`## ${targetBranchMajorVersion}`,
);
if (!foundContent) {
output += "No user facing changes.\n";
}
foundContent = false;
output += `\n${line}\n\n`;
} else {
if (line.trim() !== "") {
foundContent = true;
output += `${line}\n`;
}
}
}
fs.writeFileSync(CHANGELOG_FILE, output, "utf8");
}
/** Represents commits returned by the GitHub API (relevant fields only). */
export interface GitHubCommit {
sha: string;