Skip to content

Commit 0ebba4d

Browse files
committed
[policy] Make CI reproducible from clean clones
Change-Id: I7f656d1c5432ab839eebb4bc44b0815671750a5e
1 parent af9d9e7 commit 0ebba4d

4 files changed

Lines changed: 33 additions & 9 deletions

File tree

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"dev": "bun run dev:server & bun run dev:webui & wait",
3535
"dev:webui": "bun run --cwd apps/webui dev",
3636
"dev:server": "bun run --cwd apps/server dev",
37-
"typecheck": "bun run typecheck:scripts && bun run typecheck:sdk && bun run typecheck:cli && bun run typecheck:playbooks && bun run typecheck:playground && bun run typecheck:webui && bun run typecheck:server",
37+
"typecheck": "bun run build:sdk && bun run typecheck:scripts && bun run typecheck:sdk && bun run typecheck:cli && bun run typecheck:playbooks && bun run typecheck:playground && bun run typecheck:webui && bun run typecheck:server",
38+
"build:sdk": "bun run --cwd packages/sdk build",
3839
"typecheck:scripts": "tsc -p scripts/tsconfig.json --noEmit",
3940
"typecheck:sdk": "bun run --cwd packages/sdk typecheck",
4041
"typecheck:cli": "bun run --cwd packages/cli typecheck",

scripts/open-source.test.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ function publicWorktreeFiles(): string[] {
2424
.filter((file) => file && isReadableRegularFile(resolve(root, file)));
2525
}
2626

27+
function publicWorktreeFilesMatching(predicate: (file: string) => boolean): string[] {
28+
return publicWorktreeFiles().filter(predicate);
29+
}
30+
31+
function isVisiblePath(file: string): boolean {
32+
return file.split("/").every((segment) => !segment.startsWith("."));
33+
}
34+
2735
function output(command: string[]): string {
2836
const result = Bun.spawnSync(command, { cwd: root, stdout: "pipe", stderr: "pipe" });
2937
if (result.exitCode !== 0) throw new Error(result.stderr.toString());
@@ -45,7 +53,9 @@ describe("open-source repository invariants", () => {
4553
});
4654

4755
test("published packages have no runtime dependency on private workspaces", () => {
48-
const packageFiles = output(["rg", "--files", "-g", "package.json"]).trim().split("\n").filter(Boolean);
56+
const packageFiles = publicWorktreeFilesMatching(
57+
(file) => isVisiblePath(file) && (file === "package.json" || file.endsWith("/package.json")),
58+
);
4959
const manifests = packageFiles.map(
5060
(file) =>
5161
JSON.parse(readFileSync(resolve(root, file), "utf8")) as {
@@ -91,7 +101,7 @@ describe("open-source repository invariants", () => {
91101
});
92102

93103
test("all local Markdown links resolve", () => {
94-
const files = output(["rg", "--files", "-g", "*.md"]).trim().split("\n").filter(Boolean);
104+
const files = publicWorktreeFilesMatching((file) => isVisiblePath(file) && file.endsWith(".md"));
95105
const missing: string[] = [];
96106
for (const file of files) {
97107
const body = readFileSync(resolve(root, file), "utf8");
@@ -106,10 +116,9 @@ describe("open-source repository invariants", () => {
106116
});
107117

108118
test("third-party GitHub Actions are pinned to full commit SHAs", () => {
109-
const workflows = output(["rg", "--files", ".github/workflows", "-g", "*.yml", "-g", "*.yaml"])
110-
.trim()
111-
.split("\n")
112-
.filter(Boolean);
119+
const workflows = publicWorktreeFilesMatching(
120+
(file) => file.startsWith(".github/workflows/") && (file.endsWith(".yml") || file.endsWith(".yaml")),
121+
);
113122
const unpinned: string[] = [];
114123
for (const file of workflows) {
115124
const body = readFileSync(resolve(root, file), "utf8");

scripts/verify.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ describe("verification profiles", () => {
4545
test("rejects an explicit BASE that is not a commit", () => {
4646
expect(() => resolveComparisonBase("not-a-real-commit")).toThrow("is not a commit");
4747
});
48+
49+
test("falls back when a push base disappeared after a GitHub history rewrite", () => {
50+
const previous = process.env.GITHUB_ACTIONS;
51+
process.env.GITHUB_ACTIONS = "true";
52+
try {
53+
expect(resolveComparisonBase("not-a-real-commit")).toBeTruthy();
54+
} finally {
55+
if (previous === undefined) delete process.env.GITHUB_ACTIONS;
56+
else process.env.GITHUB_ACTIONS = previous;
57+
}
58+
});
4859
});
4960

5061
describe("publish manifest", () => {

scripts/verify.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,11 @@ function gitCommitExists(ref: string): boolean {
5454

5555
export function resolveComparisonBase(explicitBase = process.env.BASE): string | undefined {
5656
if (explicitBase && !/^0+$/.test(explicitBase)) {
57-
if (!gitCommitExists(explicitBase)) throw new Error(`Verification BASE '${explicitBase}' is not a commit.`);
58-
return explicitBase;
57+
if (gitCommitExists(explicitBase)) return explicitBase;
58+
if (process.env.GITHUB_ACTIONS !== "true") {
59+
throw new Error(`Verification BASE '${explicitBase}' is not a commit.`);
60+
}
61+
console.warn(`Verification BASE '${explicitBase}' is unavailable after a history rewrite; using a local fallback.`);
5962
}
6063
return output(["git", "merge-base", "HEAD", "origin/HEAD"]) || output(["git", "rev-parse", "HEAD^"]) || undefined;
6164
}

0 commit comments

Comments
 (0)