diff --git a/scripts/check-upstream-release.mjs b/scripts/check-upstream-release.mjs index 7d459b809..dcf4599af 100644 --- a/scripts/check-upstream-release.mjs +++ b/scripts/check-upstream-release.mjs @@ -22,8 +22,9 @@ import { execFileSync } from "node:child_process"; import { appendFileSync, readFileSync } from "node:fs"; -const UPSTREAM_REMOTE = "upstream"; const UPSTREAM_REPO = "badlogic/pi-mono"; +const UPSTREAM_REMOTE_URL = `https://github.com/${UPSTREAM_REPO}.git`; +const UPSTREAM_MAIN_REF = "refs/remotes/pi-mono/main"; const PIN_PATH = ".github/upstream.json"; function log(message) { @@ -55,7 +56,7 @@ function latestUpstreamReleaseTag() { log("gh releases/latest unavailable; falling back to remote tags"); } - const lsRemote = run("git", ["ls-remote", "--tags", "--refs", UPSTREAM_REMOTE, "v*"]); + const lsRemote = run("git", ["ls-remote", "--tags", "--refs", UPSTREAM_REMOTE_URL, "v*"]); const tags = lsRemote .split("\n") .filter(Boolean) @@ -81,10 +82,16 @@ function compareSemver(a, b) { function resolveTagSha(tag) { // Fetch the tag so the commit object exists locally for the ancestry check. - const fetch = tryRun("git", ["fetch", "--quiet", UPSTREAM_REMOTE, "--no-tags", `+refs/tags/${tag}:refs/upstream-tags/${tag}`]); + const fetch = tryRun("git", [ + "fetch", + "--quiet", + UPSTREAM_REMOTE_URL, + "--no-tags", + `+refs/tags/${tag}:refs/upstream-tags/${tag}`, + ]); if (!fetch.ok) { // Fall back to a full tag fetch. - tryRun("git", ["fetch", "--quiet", "--tags", UPSTREAM_REMOTE]); + tryRun("git", ["fetch", "--quiet", "--tags", UPSTREAM_REMOTE_URL]); } const peeled = tryRun("git", ["rev-parse", `refs/upstream-tags/${tag}^{commit}`]); if (peeled.ok && peeled.stdout) { @@ -94,7 +101,8 @@ function resolveTagSha(tag) { } function resolveUpstreamHeadSha() { - return run("git", ["rev-parse", `${UPSTREAM_REMOTE}/main`]); + run("git", ["fetch", "--quiet", UPSTREAM_REMOTE_URL, `+refs/heads/main:${UPSTREAM_MAIN_REF}`]); + return run("git", ["rev-parse", UPSTREAM_MAIN_REF]); } function currentPinTag() { @@ -129,7 +137,7 @@ function main() { const sha = resolveTagSha(tag); log(`resolved ${tag} -> ${sha}`); const upstreamHeadSha = resolveUpstreamHeadSha(); - log(`resolved ${UPSTREAM_REMOTE}/main -> ${upstreamHeadSha}`); + log(`resolved ${UPSTREAM_REPO} main -> ${upstreamHeadSha}`); if (force) { log("--force set; proceeding regardless of merge state"); diff --git a/scripts/check-upstream-release.test.mjs b/scripts/check-upstream-release.test.mjs index ec09d04cf..b9dc40455 100644 --- a/scripts/check-upstream-release.test.mjs +++ b/scripts/check-upstream-release.test.mjs @@ -2,9 +2,11 @@ import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { after, before, describe, it } from "node:test"; -const UPSTREAM_REMOTE_URL = "https://github.com/badlogic/pi-mono.git"; +const CONTRIBUTOR_UPSTREAM_URL = "https://github.com/code-yeongyu/senpi.git"; +const DETECTOR_UPSTREAM_URL = "https://github.com/badlogic/pi-mono.git"; let addedUpstreamRemote = false; +let originalUpstreamUrl = ""; function git(args) { return execFileSync("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim(); @@ -18,28 +20,39 @@ function tryGit(args) { } } +function tryGitCommand(args) { + try { + execFileSync("git", args, { stdio: "ignore" }); + return true; + } catch { + return false; + } +} + describe("upstream release detector outputs", () => { let upstreamAvailable = false; before(() => { - if (!tryGit(["remote", "get-url", "upstream"])) { - if (!tryGit(["remote", "add", "upstream", UPSTREAM_REMOTE_URL])) return; + originalUpstreamUrl = tryGit(["remote", "get-url", "upstream"]); + if (originalUpstreamUrl) { + if (!tryGitCommand(["remote", "set-url", "upstream", CONTRIBUTOR_UPSTREAM_URL])) return; + } else { + if (!tryGitCommand(["remote", "add", "upstream", CONTRIBUTOR_UPSTREAM_URL])) return; addedUpstreamRemote = true; } - // A real fetch of the upstream GitHub repo. On credential-less/offline + // Probe the repository the detector actually reads. On credential-less/offline // runners (e.g. the release publish job checks out with - // persist-credentials:false) this cannot authenticate — skip rather than + // persist-credentials:false) this can be unreachable — skip rather than // hard-fail the whole `test:scripts` suite, since this test inherently // requires the external upstream repo. - if (tryGit(["fetch", "--quiet", "upstream", "+refs/heads/main:refs/remotes/upstream/main"]) === "" && !tryGit(["rev-parse", "upstream/main"])) { - return; - } - upstreamAvailable = tryGit(["rev-parse", "upstream/main"]) !== ""; + upstreamAvailable = Boolean(tryGit(["ls-remote", DETECTOR_UPSTREAM_URL, "refs/heads/main"])); }); after(() => { if (addedUpstreamRemote) { git(["remote", "remove", "upstream"]); + } else if (originalUpstreamUrl) { + git(["remote", "set-url", "upstream", originalUpstreamUrl]); } }); @@ -48,16 +61,27 @@ describe("upstream release detector outputs", () => { t.skip("upstream remote unreachable (offline or no git credentials)"); return; } - const stdout = execFileSync("node", ["scripts/check-upstream-release.mjs", "--force"], { encoding: "utf8" }); + const stdout = execFileSync("node", ["scripts/check-upstream-release.mjs", "--force"], { + encoding: "utf8", + env: { ...process.env, GITHUB_OUTPUT: "" }, + }); const output = Object.fromEntries( stdout .trim() .split("\n") .map((line) => line.split("=", 2)), ); - const upstreamMain = git(["rev-parse", "upstream/main"]); + const upstreamMain = git(["ls-remote", DETECTOR_UPSTREAM_URL, "refs/heads/main"]).split(/\s+/, 1)[0]; const releaseTag = output.tag; - const releaseSha = tryGit(["rev-parse", `refs/upstream-tags/${releaseTag}^{commit}`]) || git(["rev-parse", `${releaseTag}^{commit}`]); + const remoteTagRefs = git([ + "ls-remote", + "--tags", + DETECTOR_UPSTREAM_URL, + `refs/tags/${releaseTag}`, + `refs/tags/${releaseTag}^{}`, + ]).split("\n"); + const peeledTag = remoteTagRefs.find((line) => line.endsWith(`refs/tags/${releaseTag}^{}`)); + const releaseSha = (peeledTag ?? remoteTagRefs[0]).split(/\s+/, 1)[0]; assert.equal(output.proceed, "true"); assert.equal(output.sha, releaseSha);