Skip to content
Closed
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
96 changes: 75 additions & 21 deletions scripts/enhance-release-pr.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -183,28 +183,8 @@ async function getPrForCommit(commitSha) {
// --- Parse .server-changes/ files ---

async function parseServerChanges() {
const dir = join(ROOT_DIR, ".server-changes");
const entries = [];

let files;
try {
files = await fs.readdir(dir);
} catch {
return entries;
}

// Collect file info and look up commits in parallel
const fileData = [];
for (const file of files) {
if (!file.endsWith(".md") || file === "README.md") continue;

const filePath = join(".server-changes", file);
const content = await fs.readFile(join(dir, file), "utf-8");
const parsed = parseFrontmatter(content);
if (!parsed.body.trim()) continue;

fileData.push({ filePath, parsed });
}
const fileData = await getServerChangeFileData();

// Look up commits for all files in parallel
const commits = await Promise.all(fileData.map((f) => getCommitForFile(f.filePath)));
Expand Down Expand Up @@ -232,6 +212,80 @@ async function parseServerChanges() {
return entries;
}

async function getServerChangeFileData() {
const liveFileData = await getLiveServerChangeFileData();
if (liveFileData.length > 0) return liveFileData;

// The changesets version command deletes .server-changes before this script
// enhances the release PR body. Recover those consumed files from the release
// branch diff so they still make it into the release notes handoff.
return getDeletedServerChangeFileDataFromReleaseBranch();
}

async function getLiveServerChangeFileData() {
const dir = join(ROOT_DIR, ".server-changes");

let files;
try {
files = await fs.readdir(dir);
} catch {
return [];
}

const fileData = [];
for (const file of files.sort()) {
if (!file.endsWith(".md") || file === "README.md") continue;

const filePath = join(".server-changes", file);
const content = await fs.readFile(join(dir, file), "utf-8");
const parsed = parseFrontmatter(content);
if (!parsed.body.trim()) continue;

fileData.push({ filePath, parsed });
}

return fileData;
}

async function getDeletedServerChangeFileDataFromReleaseBranch() {
const baseRef = process.env.SERVER_CHANGES_BASE_REF || "origin/main";
const releaseRef = process.env.SERVER_CHANGES_RELEASE_REF || "origin/changeset-release/main";

let mergeBase;
let deletedFiles;
try {
mergeBase = await gitExec(["merge-base", baseRef, releaseRef]);
deletedFiles = await gitExec([
"diff",
"--name-only",
"--diff-filter=D",
`${mergeBase}..${releaseRef}`,
"--",
".server-changes",
]);
} catch {
return [];
}

const fileData = [];
for (const filePath of deletedFiles.split("\n").filter(Boolean).sort()) {
const file = filePath.split("/").pop();
if (!file?.endsWith(".md") || file === "README.md") continue;

try {
const content = await gitExec(["show", `${mergeBase}:${filePath}`]);
const parsed = parseFrontmatter(content);
if (!parsed.body.trim()) continue;
fileData.push({ filePath, parsed });
} catch {
// If an individual file cannot be recovered, skip it rather than hiding
// all other server changes.
}
}

return fileData;
}

function parseFrontmatter(content) {
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
if (!match) return { frontmatter: {}, body: content };
Expand Down