Skip to content
Merged
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: 85 additions & 11 deletions .github/scripts/detect-new-endpoints.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ function shellQuote(value) {
return `'${String(value).replace(/'/g, `'\\''`)}'`;
}

function sleep(ms) {
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
}

function loadSpec() {
const raw = readFileSync(SPEC_PATH, 'utf-8');
// OpenAPI descriptions may contain literal control chars (newlines in JSON strings)
Expand Down Expand Up @@ -204,6 +208,43 @@ function openPrExistsForBranchBase(branchBaseName) {
}
}

function getOpenPrUrlForBranch(branchName) {
try {
return run(
[
'gh pr list --state open --limit 100 --json headRefName,url --jq',
shellQuote(`[.[] | select(.headRefName == "${branchName}")][0].url // ""`),
].join(' '),
{ allowInDryRun: true }
);
} catch {
return '';
}
}

function getOpenPrNumberForBranch(branchName) {
try {
return run(
[
'gh pr list --state open --limit 100 --json headRefName,number --jq',
shellQuote(`[.[] | select(.headRefName == "${branchName}")][0].number // ""`),
].join(' '),
{ allowInDryRun: true }
);
} catch {
return '';
}
}

function ensurePrLabels(branchName) {
const prNumber = getOpenPrNumberForBranch(branchName);
if (!prNumber) {
return;
}

run(`gh pr edit ${prNumber} --add-label auto-generated --add-label api-docs`);
}

function remoteBranchExists(branchName) {
try {
const result = run(`git ls-remote --heads origin ${shellQuote(branchName)}`, { allowInDryRun: true });
Expand All @@ -224,6 +265,49 @@ function getBranchName(branchBaseName) {
return `${branchBaseName}-${suffix}`;
}

function createPullRequest({ title, bodyFilePath, branchName }) {
const command = [
'gh pr create',
'--title',
shellQuote(title),
'--body-file',
shellQuote(bodyFilePath),
'--label auto-generated',
'--label api-docs',
'--head',
shellQuote(branchName),
].join(' ');

if (DRY_RUN) {
run(command);
return;
}

const maxAttempts = 3;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
run(command);
ensurePrLabels(branchName);
return;
} catch (err) {
const existingUrl = getOpenPrUrlForBranch(branchName);
if (existingUrl) {
ensurePrLabels(branchName);
console.log(` + PR exists after create error: ${existingUrl}`);
return;
}

if (attempt === maxAttempts) {
throw err;
}

const delay = attempt * 5000;
console.warn(` ⚠ PR creation failed; retrying in ${delay / 1000}s (${attempt}/${maxAttempts})`);
sleep(delay);
}
}
}

// ---------------------------------------------------------------------------
// docs.json updater
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -411,17 +495,7 @@ async function main() {
if (!DRY_RUN) {
writeFileSync(prBodyPath, prBody);
}
run([
'gh pr create',
'--title',
shellQuote(prTitle),
'--body-file',
shellQuote(prBodyPath),
'--label auto-generated',
'--label api-docs',
'--head',
shellQuote(branchName),
].join(' '));
createPullRequest({ title: prTitle, bodyFilePath: prBodyPath, branchName });

console.log(DRY_RUN ? ` ✅ PR would be created for ${ep.key}` : ` ✅ PR created for ${ep.key}`);
created++;
Expand Down
Loading