From f2745d74ea3776959388084104a368e0daf87b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Vila=C3=A7a=20de=20Jesus?= Date: Sun, 25 Oct 2026 07:14:16 -0300 Subject: [PATCH 1/2] chore: start #591 From 4920a3fa7a8882d275f8d7ccb764adeadee47c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Vila=C3=A7a=20de=20Jesus?= Date: Sun, 25 Oct 2026 07:15:27 -0300 Subject: [PATCH 2/2] fix: land gate always rebuilds dist after a rebase (#591) --- packages/ui/tests/dist-fresh.test.ts | 24 ++++++++++++++++++++++++ scripts/dist-fresh.ts | 9 +++++++++ scripts/test-changed.ts | 14 +++++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 packages/ui/tests/dist-fresh.test.ts create mode 100644 scripts/dist-fresh.ts diff --git a/packages/ui/tests/dist-fresh.test.ts b/packages/ui/tests/dist-fresh.test.ts new file mode 100644 index 00000000..b25f29dd --- /dev/null +++ b/packages/ui/tests/dist-fresh.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "bun:test"; +import { distStale } from "../../../scripts/dist-fresh"; + +// The land gate decides whether to rebuild `dist` before it tests the site. A dist built before the +// rebase holds old code even when the PR's own diff touches no package file (#591). +const none = { exists: true, changedAfter: false }; + +describe("distStale", () => { + it("is stale when it does not exist", () => { + expect(distStale({ land: false, exists: false, changedAfter: false })).toBe(true); + }); + + it("a dev run keeps a dist newer than every changed file", () => { + expect(distStale({ land: false, ...none })).toBe(false); + }); + + it("a dev run rebuilds when a changed file is newer than the dist", () => { + expect(distStale({ land: false, ...none, changedAfter: true })).toBe(true); + }); + + it("the land gate always rebuilds: the rebase brings in sources the diff does not list", () => { + expect(distStale({ land: true, ...none })).toBe(true); + }); +}); diff --git a/scripts/dist-fresh.ts b/scripts/dist-fresh.ts new file mode 100644 index 00000000..f564f89b --- /dev/null +++ b/scripts/dist-fresh.ts @@ -0,0 +1,9 @@ +/** + * Whether a build output (`packages/ui/dist`, `site/dist`) has to be rebuilt before the site is tested. + * A dev run trusts file times: the output is stale when it is missing or a changed file is newer. + * The land gate never does: it runs right after a rebase, which brings in sources that are not in the + * PR's diff (so no changed file is "newer"), while the output may predate the rebase by hours (#591). + */ +export function distStale(o: { land: boolean; exists: boolean; changedAfter: boolean }): boolean { + return o.land || !o.exists || o.changedAfter; +} diff --git a/scripts/test-changed.ts b/scripts/test-changed.ts index d36a4d82..b5f8cc98 100755 --- a/scripts/test-changed.ts +++ b/scripts/test-changed.ts @@ -30,6 +30,7 @@ import { spawnSync } from "node:child_process"; import { existsSync, readFileSync, statSync } from "node:fs"; import { join } from "node:path"; +import { distStale } from "./dist-fresh.ts"; import { lockReachesRuntime, ROOT, select } from "./route-impact.ts"; import { affected, buildGraph, isSharedComponent, landBudget } from "./test-graph.ts"; @@ -203,11 +204,18 @@ if (siteRun) { const siteDist = mtime(join(ROOT, "site/dist/index.html")); const newer = (re: RegExp, than: number) => changed.some((f) => re.test(f) && mtime(join(ROOT, f)) > than); - const pkgStale = !pkgDist || newer(/^packages\/ui\/(src|scripts|package\.json)/, pkgDist); + const pkgStale = distStale({ + land, + exists: pkgDist > 0, + changedAfter: newer(/^packages\/ui\/(src|scripts|package\.json)/, pkgDist), + }); const siteStale = - !siteDist || pkgStale || - newer(/^site\/(src|public|astro\.config\.mjs|package\.json)/, siteDist); + distStale({ + land, + exists: siteDist > 0, + changedAfter: newer(/^site\/(src|public|astro\.config\.mjs|package\.json)/, siteDist), + }); // A build is ~75 s (package 17 s + site 58 s), more than the whole 60 s dev budget: only the land gate // builds. A dev run uses `site/dist` when it is fresh, and says so when it cannot. if ((pkgStale || siteStale) && !land) {