mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-31 14:16:39 +01:00
Use one explicit Turbo cache mode for forced CI execution and preserve cache trust boundaries. Match OpenCode’s ignored stdin in the relocated Linux shell-hook fixture while retaining strict OOM and parent-isolation assertions. Co-Authored-By: Paperclip <noreply@paperclip.ing>
53 lines
2.6 KiB
JavaScript
53 lines
2.6 KiB
JavaScript
import { spawnSync, execFileSync } from "node:child_process";
|
|
import { lstatSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
import { createHash } from "node:crypto";
|
|
import { matchesGlob } from "node:path";
|
|
import { executionPlan, sourceFiles } from "./execution-plan.mjs";
|
|
|
|
const task = process.env.CI_TASK;
|
|
if (!/^ci:[a-z-]+$/.test(task ?? "")) throw new Error("Invalid CI task");
|
|
const args = JSON.parse(process.env.CI_TASK_ARGS || "[]");
|
|
if (!Array.isArray(args) || args.some((arg) => typeof arg !== "string")) throw new Error("Invalid task arguments");
|
|
const version = (command, argv) => {
|
|
try { return execFileSync(command, argv, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim(); }
|
|
catch { return "unavailable"; }
|
|
};
|
|
const config = JSON.parse(readFileSync("turbo.json", "utf8"));
|
|
const files = sourceFiles();
|
|
const execution = executionPlan(config, task, args, files);
|
|
mkdirSync(".turbo/task-configs", { recursive: true });
|
|
const runtimeConfig = `.turbo/task-configs/${task.replace(":", "-")}.json`;
|
|
writeFileSync(runtimeConfig, JSON.stringify(execution.config));
|
|
const classified = [...config.globalDependencies, ...Object.values(config.tasks).flatMap((entry) => entry.inputs)];
|
|
const unknownInputs = createHash("sha256");
|
|
let uncacheable = false;
|
|
for (const file of files) {
|
|
if (classified.some((glob) => matchesGlob(file, glob))) continue;
|
|
unknownInputs.update(JSON.stringify(file));
|
|
try {
|
|
if (lstatSync(file).isFile()) unknownInputs.update(readFileSync(file));
|
|
else uncacheable = true;
|
|
} catch (error) {
|
|
if (error.code !== "ENOENT") throw error;
|
|
unknownInputs.update("<deleted>");
|
|
}
|
|
}
|
|
const scope = {
|
|
node: process.version, pnpm: version("pnpm", ["--version"]),
|
|
platform: process.platform, arch: process.arch, cwd: realpathSync(process.cwd()),
|
|
libc: process.report.getReport().header.glibcVersionRuntime ?? null,
|
|
rust: version("rustc", ["--version", "--verbose"]),
|
|
unknownInputs: unknownInputs.digest("hex"),
|
|
};
|
|
const force = process.env.CI_FORCE_TASKS === "true" || uncacheable;
|
|
const result = spawnSync("pnpm", ["exec", "turbo", "run", execution.target,
|
|
"--root-turbo-json", runtimeConfig, "--summarize", force ? "--cache=" : "--cache=local:rw", "--cache-dir=.turbo/cache",
|
|
...(process.env.CI_TASK_DRY_RUN === "true" ? ["--dry=json"] : []),
|
|
"--", ...execution.args], {
|
|
stdio: "inherit",
|
|
env: { ...process.env, TURBO_TELEMETRY_DISABLED: "1",
|
|
CI_TASK_CACHE_SCOPE: createHash("sha256").update(JSON.stringify(scope)).digest("hex") },
|
|
});
|
|
if (result.error) throw result.error;
|
|
process.exitCode = result.status ?? 1;
|