Skip to content

Commit fe19341

Browse files
authored
chore(repo) auto-link server change entries to their PRs via GitHub API (#3129)
1 parent e9fb8e3 commit fe19341

File tree

1 file changed

+88
-1
lines changed

1 file changed

+88
-1
lines changed

scripts/enhance-release-pr.mjs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
import { promises as fs } from "fs";
21+
import { execFile } from "child_process";
2122
import { join } from "path";
2223

2324
const version = process.argv[2];
@@ -83,6 +84,68 @@ function parsePrBody(body) {
8384
return entries;
8485
}
8586

87+
// --- Git + GitHub helpers for finding PR numbers ---
88+
89+
const REPO = "triggerdotdev/trigger.dev";
90+
91+
function gitExec(args) {
92+
return new Promise((resolve, reject) => {
93+
execFile("git", args, { cwd: ROOT_DIR, maxBuffer: 1024 * 1024 }, (err, stdout) => {
94+
if (err) reject(err);
95+
else resolve(stdout.trim());
96+
});
97+
});
98+
}
99+
100+
async function getCommitForFile(filePath) {
101+
try {
102+
// Find the commit that added this file
103+
const sha = await gitExec([
104+
"log",
105+
"--diff-filter=A",
106+
"--format=%H",
107+
"--",
108+
filePath,
109+
]);
110+
return sha.split("\n")[0] || null;
111+
} catch {
112+
return null;
113+
}
114+
}
115+
116+
async function getPrForCommit(commitSha) {
117+
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
118+
if (!token || !commitSha) return null;
119+
120+
try {
121+
const res = await fetch(
122+
`https://api.github.com/repos/${REPO}/commits/${commitSha}/pulls`,
123+
{
124+
headers: {
125+
Authorization: `token ${token}`,
126+
Accept: "application/vnd.github.v3+json",
127+
},
128+
}
129+
);
130+
if (!res.ok) return null;
131+
132+
const pulls = await res.json();
133+
if (!pulls.length) return null;
134+
135+
// Prefer merged PRs, earliest merge first (same logic as @changesets/get-github-info)
136+
const sorted = pulls.sort((a, b) => {
137+
if (!a.merged_at && !b.merged_at) return 0;
138+
if (!a.merged_at) return 1;
139+
if (!b.merged_at) return -1;
140+
return new Date(a.merged_at) - new Date(b.merged_at);
141+
});
142+
143+
return sorted[0].number;
144+
} catch {
145+
return null;
146+
}
147+
}
148+
86149
// --- Parse .server-changes/ files ---
87150

88151
async function parseServerChanges() {
@@ -96,15 +159,39 @@ async function parseServerChanges() {
96159
return entries;
97160
}
98161

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

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

172+
fileData.push({ filePath, parsed });
173+
}
174+
175+
// Look up commits for all files in parallel
176+
const commits = await Promise.all(
177+
fileData.map((f) => getCommitForFile(f.filePath))
178+
);
179+
180+
// Look up PRs for all commits in parallel
181+
const prNumbers = await Promise.all(commits.map((sha) => getPrForCommit(sha)));
182+
183+
for (let i = 0; i < fileData.length; i++) {
184+
const { parsed } = fileData[i];
185+
let text = parsed.body.trim();
186+
const pr = prNumbers[i];
187+
188+
// Append PR link if we found one and it's not already in the text
189+
if (pr && !text.includes(`#${pr}`)) {
190+
text += ` ([#${pr}](https://github.com/${REPO}/pull/${pr}))`;
191+
}
192+
106193
entries.push({
107-
text: parsed.body.trim(),
194+
text,
108195
type: parsed.frontmatter.type || "improvement",
109196
area: parsed.frontmatter.area || "webapp",
110197
});

0 commit comments

Comments
 (0)