Skip to content

Commit f3017ea

Browse files
committed
fix: improve branch syncing logic and update help documentation
1 parent 632616d commit f3017ea

1 file changed

Lines changed: 77 additions & 15 deletions

File tree

scripts/sync-from-node.ts

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
*
77
* Options:
88
* --help, -h Show this help message
9-
* --branch, -b Specify branch/tag to sync from (default: v24.x-staging)
9+
* --branch, -b Specify branch/tag to sync from. When omitted, resolves
10+
* the highest vNN.x-staging branch on nodejs/node via the
11+
* GitHub API (falls back to FALLBACK_STAGING_BRANCH below
12+
* on API failure).
1013
* --repo, -r Specify GitHub repository (default: nodejs/node)
1114
* --dry-run Show what files would be downloaded without actually downloading
1215
*
@@ -26,6 +29,13 @@ import { githubFetch } from "./github-api";
2629

2730
const execAsync = promisify(exec);
2831

32+
// Last-resort default when the GitHub API is unreachable (rate limit, offline,
33+
// etc.). Bump this when a new Node.js major's staging branch becomes the
34+
// supported compatibility target. We sync from `vNN.x-staging` rather than
35+
// `main` so we stay aligned with the stabilized view of the current release
36+
// line; `main` includes the next major's in-flight work.
37+
const FALLBACK_STAGING_BRANCH = "v25.x-staging";
38+
2939
const __filename = fileURLToPath(import.meta.url);
3040
const __dirname = path.dirname(__filename);
3141
const packageRoot = path.join(__dirname, "..");
@@ -67,9 +77,15 @@ const filesToSync: SyncedFile[] = [
6777

6878
// Parse command line arguments
6979
function parseArgs() {
70-
const args = {
80+
const args: {
81+
help: boolean;
82+
branch: string | null;
83+
repo: string;
84+
dryRun: boolean;
85+
force: boolean;
86+
} = {
7187
help: false,
72-
branch: "v25.x-staging",
88+
branch: null,
7389
repo: "nodejs/node",
7490
dryRun: false,
7591
force: false,
@@ -121,6 +137,45 @@ function parseArgs() {
121137
return args;
122138
}
123139

140+
/**
141+
* Resolve the `vNN.x-staging` branch corresponding to the latest RELEASED
142+
* Node.js major. We deliberately don't pick the highest existing staging
143+
* branch: Node.js creates `vNN.x-staging` well before `vNN.0.0` actually
144+
* ships, so a naive "highest branch" pick would drag us into in-flight
145+
* next-major work. Our compat promise is against released Node.js, so we
146+
* follow the staging branch for the current stable line.
147+
*
148+
* Returns FALLBACK_STAGING_BRANCH if the API call fails (rate limit,
149+
* network, unexpected response shape).
150+
*/
151+
async function resolveLatestStagingBranch(repo: string): Promise<string> {
152+
try {
153+
// /releases/latest returns the newest non-prerelease, non-draft release
154+
// across all release lines. For nodejs/node that's effectively the
155+
// latest "current" release (not LTS), which is what our compat target
156+
// tracks.
157+
const url = `https://api.github.com/repos/${repo}/releases/latest`;
158+
const res = await githubFetch(url, { logRateLimit: false });
159+
if (!res.ok) {
160+
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
161+
}
162+
const release = (await res.json()) as { tag_name?: string };
163+
const match = release.tag_name?.match(/^v(\d+)\./);
164+
if (!match) {
165+
throw new Error(
166+
`Unexpected latest-release tag shape: ${release.tag_name}`,
167+
);
168+
}
169+
return `v${match[1]}.x-staging`;
170+
} catch (err: any) {
171+
console.log(
172+
`Warning: Could not resolve latest staging branch (${err.message}); ` +
173+
`falling back to ${FALLBACK_STAGING_BRANCH}`,
174+
);
175+
return FALLBACK_STAGING_BRANCH;
176+
}
177+
}
178+
124179
function showHelp() {
125180
const help = `
126181
Sync Node.js SQLite implementation files from GitHub into this package.
@@ -130,7 +185,9 @@ Usage:
130185
131186
Options:
132187
--help, -h Show this help message
133-
--branch, -b Specify branch/tag to sync from (default: v24.x-staging)
188+
--branch, -b Specify branch/tag to sync from. When omitted, resolves
189+
the highest vNN.x-staging branch on nodejs/node via the
190+
GitHub API (fallback: ${FALLBACK_STAGING_BRANCH}).
134191
--repo, -r Specify GitHub repository (default: nodejs/node)
135192
--dry-run Show what files would be downloaded without actually downloading
136193
--force, -f Force sync even if current version is newer
@@ -319,9 +376,14 @@ async function main() {
319376
return;
320377
}
321378

379+
const branch = args.branch ?? (await resolveLatestStagingBranch(args.repo));
380+
if (!args.branch) {
381+
console.log(`Resolved default branch: ${branch}`);
382+
}
383+
322384
console.log(`Syncing Node.js SQLite files from GitHub`);
323385
console.log(`Repository: ${args.repo}`);
324-
console.log(`Branch/Tag: ${args.branch}`);
386+
console.log(`Branch/Tag: ${branch}`);
325387
console.log(`Package root: ${packageRoot}`);
326388

327389
if (args.dryRun) {
@@ -338,7 +400,7 @@ async function main() {
338400
// Fetch Node.js version and commit info
339401
try {
340402
// Get commit SHA using authenticated fetch
341-
const commitUrl = `https://api.github.com/repos/${args.repo}/commits/${args.branch}`;
403+
const commitUrl = `https://api.github.com/repos/${args.repo}/commits/${branch}`;
342404
const commitResponse = await githubFetch(commitUrl);
343405

344406
if (commitResponse.ok) {
@@ -349,12 +411,12 @@ async function main() {
349411
// Only parse node_version.h for release tags (e.g., v25.8.1), not staging
350412
// branches — staging branches have version numbers bumped ahead of the
351413
// actual release, so the parsed version would be misleading.
352-
const isReleaseTag = /^v\d+\.\d+\.\d+$/.test(args.branch);
414+
const isReleaseTag = /^v\d+\.\d+\.\d+$/.test(branch);
353415

354416
if (isReleaseTag) {
355-
nodeVersion = args.branch;
417+
nodeVersion = branch;
356418
} else {
357-
const versionRef = nodeCommitSha || args.branch;
419+
const versionRef = nodeCommitSha || branch;
358420
const versionUrl = `https://raw.githubusercontent.com/${args.repo}/${versionRef}/src/node_version.h`;
359421
const versionResponse = await fetch(versionUrl);
360422
if (versionResponse.ok) {
@@ -372,7 +434,7 @@ async function main() {
372434
if (majorMatch && minorMatch && patchMatch) {
373435
// Use the branch name, not the (potentially unreleased) version
374436
// from the header. The commit SHA suffix provides traceability.
375-
nodeVersion = args.branch;
437+
nodeVersion = branch;
376438
}
377439
}
378440
}
@@ -383,13 +445,13 @@ async function main() {
383445
}
384446

385447
console.log(
386-
`Node.js version: ${nodeVersion || "unknown"} (${nodeCommitSha?.substring(0, 7) || args.branch})`,
448+
`Node.js version: ${nodeVersion || "unknown"} (${nodeCommitSha?.substring(0, 7) || branch})`,
387449
);
388450

389451
// Check if we should skip the entire sync based on SHA
390452
if (
391453
nodeCommitSha &&
392-
shouldSkipSync(args.repo, args.branch, nodeCommitSha, args.force)
454+
shouldSkipSync(args.repo, branch, nodeCommitSha, args.force)
393455
) {
394456
console.log("✅ No sync needed - files are already up to date");
395457
return;
@@ -399,7 +461,7 @@ async function main() {
399461

400462
for (const file of filesToSync) {
401463
// Use commit SHA for consistency, fallback to branch if SHA not available
402-
const ref = nodeCommitSha || args.branch;
464+
const ref = nodeCommitSha || branch;
403465
const url = `https://raw.githubusercontent.com/${args.repo}/${ref}/${file.src}`;
404466
const destPath = path.join(packageRoot, file.dest);
405467

@@ -434,7 +496,7 @@ async function main() {
434496
// Always update Node.js version if we have it
435497
try {
436498
const nodeVersionString =
437-
(nodeVersion || args.branch) +
499+
(nodeVersion || branch) +
438500
(nodeCommitSha ? `@${nodeCommitSha.substring(0, 7)}` : "");
439501
await execAsync(`npm pkg set versions.nodejs="${nodeVersionString}"`, {
440502
cwd: packageRoot,
@@ -479,7 +541,7 @@ async function main() {
479541

480542
// Update sync cache with the current SHA
481543
if (nodeCommitSha) {
482-
updateSyncCache(args.repo, args.branch, nodeCommitSha);
544+
updateSyncCache(args.repo, branch, nodeCommitSha);
483545
}
484546

485547
console.log("\n✅ Sync complete!");

0 commit comments

Comments
 (0)