diff --git a/scripts/release-lock.mjs b/scripts/release-lock.mjs new file mode 100644 index 0000000000..42740404b1 --- /dev/null +++ b/scripts/release-lock.mjs @@ -0,0 +1,32 @@ +const DESKTOP_PACKAGE_NAMES = new Set(["dbx", "dbx-web"]); + +export function normalizeDesktopPackageVersions(lockfile) { + let inPackage = false; + let packageName = ""; + + return lockfile + .split("\n") + .map((line) => { + if (line.startsWith("[")) { + inPackage = line === "[[package]]"; + packageName = ""; + return line; + } + + if (inPackage && line.startsWith('name = "')) { + packageName = line.slice('name = "'.length, -1); + return line; + } + + if (inPackage && DESKTOP_PACKAGE_NAMES.has(packageName) && /^version = ".*"$/.test(line)) { + return 'version = ""'; + } + + return line; + }) + .join("\n"); +} + +export function isDesktopVersionOnlyCargoLockChange(beforeLockfile, afterLockfile) { + return beforeLockfile !== afterLockfile && normalizeDesktopPackageVersions(beforeLockfile) === normalizeDesktopPackageVersions(afterLockfile); +} diff --git a/scripts/release.mjs b/scripts/release.mjs index 15ab3ed481..9c2bd0cbd2 100644 --- a/scripts/release.mjs +++ b/scripts/release.mjs @@ -2,6 +2,7 @@ import { spawnSync } from "node:child_process"; import { readFileSync } from "node:fs"; import { createInterface } from "node:readline/promises"; import { stdin as input, stdout as output } from "node:process"; +import { isDesktopVersionOnlyCargoLockChange } from "./release-lock.mjs"; import { evaluateAgentVersionBump, getAgentVersionChanges, @@ -410,7 +411,7 @@ function getPackageReleaseStatus() { }; } - const changedFiles = getChangedFilesSince(latest.tag, PACKAGE_RELEASE_PATHS); + const changedFiles = getPackageChangedFilesSince(latest.tag); return { needed: changedFiles.length > 0, baseline: latest.tag, @@ -419,6 +420,21 @@ function getPackageReleaseStatus() { }; } +function getPackageChangedFilesSince(ref) { + const changedFiles = getChangedFilesSince(ref, PACKAGE_RELEASE_PATHS); + if (!changedFiles.includes("Cargo.lock") || !isDesktopOnlyCargoLockChangeSince(ref)) { + return changedFiles; + } + + return changedFiles.filter((file) => file !== "Cargo.lock"); +} + +function isDesktopOnlyCargoLockChangeSince(ref) { + const beforeLockfile = run("git", ["show", `${ref}:Cargo.lock`]).stdout; + const afterLockfile = readFileSync("Cargo.lock", "utf8"); + return isDesktopVersionOnlyCargoLockChange(beforeLockfile, afterLockfile); +} + function getLatestAgentTag() { const tag = getLatestSemverTag(AGENT_TAG_PREFIX); if (tag) return { tag: tag.tag, source: "current repo" }; diff --git a/scripts/release.test.mjs b/scripts/release.test.mjs index ea9127a6a6..bbb255b12c 100644 --- a/scripts/release.test.mjs +++ b/scripts/release.test.mjs @@ -4,6 +4,7 @@ import { tmpdir } from "node:os"; import { join, resolve } from "node:path"; import { spawnSync } from "node:child_process"; import test from "node:test"; +import { isDesktopVersionOnlyCargoLockChange } from "./release-lock.mjs"; const repoRoot = new URL("..", import.meta.url).pathname; const releaseScript = join(repoRoot, "scripts/release.mjs"); @@ -135,3 +136,37 @@ test("Windows 7 release build does not use sccache", () => { const win7Job = workflow.slice(start, end); assert.doesNotMatch(win7Job, /RUSTC_WRAPPER|SCCACHE_|sccache/i); }); + +test("desktop-only Cargo.lock version refresh does not count as a Node package change", () => { + const before = ` +[[package]] +name = "dbx" +version = "0.5.95" +dependencies = ["dbx-core"] + +[[package]] +name = "dbx-web" +version = "0.5.95" +dependencies = ["dbx-core"] + +[[package]] +name = "dbx-mcp" +version = "0.4.73" +dependencies = ["dbx-core"] +`; + const after = before.replaceAll('version = "0.5.95"', 'version = "0.5.96"'); + + assert.equal(isDesktopVersionOnlyCargoLockChange(before, after), true); +}); + +test("Cargo.lock dependency changes still count as a Node package change", () => { + const before = ` +[[package]] +name = "dbx" +version = "0.5.95" +dependencies = ["dbx-core"] +`; + const after = before.replace('dependencies = ["dbx-core"]', 'dependencies = ["dbx-core", "dbx-mcp"]'); + + assert.equal(isDesktopVersionOnlyCargoLockChange(before, after), false); +});