mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-08 01:57:31 +01:00
fix(service): make managed installs start reliably
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
8925d3f38a
commit
c9559a5d90
10 files changed
+88
-45
No files matched your search
@@ -93,7 +93,15 @@ describe("managed install commands", () => {
|
||||
if (file === "curl" && !args.includes("--output")) return { stdout: JSON.stringify({ sha }), stderr: "" };
|
||||
if (file === "curl") { fs.writeFileSync(args[args.indexOf("--output") + 1], "archive"); return { stdout: "", stderr: "" }; }
|
||||
if (file === "tar") { const checkout = args[args.indexOf("-C") + 1]; fs.mkdirSync(path.join(checkout, "cli"), { recursive: true }); fs.writeFileSync(path.join(checkout, "cli", "package.json"), JSON.stringify({ version: "0.3.1" })); return { stdout: "", stderr: "" }; }
|
||||
if (file === "corepack" || file === "bash") return { stdout: "", stderr: "" };
|
||||
if (file === "corepack") {
|
||||
if (args.includes("pack")) {
|
||||
const destination = args[args.indexOf("--pack-destination") + 1];
|
||||
const packageName = args.includes("packages/db") ? "paperclipai-db" : "paperclipai-server";
|
||||
fs.writeFileSync(path.join(destination, `${packageName}-0.3.1.tgz`), "package");
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
}
|
||||
if (file === "bash") return { stdout: "", stderr: "" };
|
||||
if (file === "npm" && args[0] === "pack") { fs.writeFileSync(path.join(args[args.indexOf("--pack-destination") + 1], "paperclipai-0.3.1.tgz"), "package"); return { stdout: "", stderr: "" }; }
|
||||
if (file === "npm" && args[0] === "install") { const prefix = args[args.indexOf("--prefix") + 1]; const packageRoot = path.join(prefix, "node_modules", "paperclipai"); fs.mkdirSync(path.join(packageRoot, "dist"), { recursive: true }); fs.writeFileSync(path.join(packageRoot, "package.json"), JSON.stringify({ version: "0.3.1" })); fs.writeFileSync(path.join(packageRoot, "dist", "index.js"), "#!/usr/bin/env node\n"); return { stdout: "", stderr: "" }; }
|
||||
if (file === process.execPath) return { stdout: "0.3.1\n", stderr: "" };
|
||||
@@ -105,7 +113,8 @@ describe("managed install commands", () => {
|
||||
expect(manifest).toMatchObject({ source: "git", repo: "HenkDz/paperclip", ref: "master", sha });
|
||||
expect(manifest?.payloadPath).toContain(path.join("git", sha.slice(0, 12)));
|
||||
expect(runCommand.mock.calls.filter(([command, args]) => command === "curl" && args.includes("--output"))).toHaveLength(1);
|
||||
expect(runCommand.mock.calls.filter(([command]) => command === "corepack")).toHaveLength(1);
|
||||
expect(runCommand.mock.calls.filter(([command, args]) => command === "corepack" && args[1] === "install")).toHaveLength(1);
|
||||
expect(runCommand.mock.calls.filter(([command, args]) => command === "corepack" && args.includes("pack"))).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("installs through the shim, reports provenance, and uninstalls without deleting user data", async () => {
|
||||
|
||||
@@ -12,15 +12,19 @@ const config = {
|
||||
} as PaperclipConfig;
|
||||
|
||||
let previousPaperclipHome: string | undefined;
|
||||
let previousServiceManaged: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
previousPaperclipHome = process.env.PAPERCLIP_HOME;
|
||||
previousServiceManaged = process.env.PAPERCLIP_SERVICE_MANAGED;
|
||||
process.env.PAPERCLIP_HOME = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-service-restart-"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (previousPaperclipHome === undefined) delete process.env.PAPERCLIP_HOME;
|
||||
else process.env.PAPERCLIP_HOME = previousPaperclipHome;
|
||||
if (previousServiceManaged === undefined) delete process.env.PAPERCLIP_SERVICE_MANAGED;
|
||||
else process.env.PAPERCLIP_SERVICE_MANAGED = previousServiceManaged;
|
||||
});
|
||||
|
||||
function managerFixture(active = true) {
|
||||
@@ -52,6 +56,15 @@ function managerFixture(active = true) {
|
||||
}
|
||||
|
||||
describe("service health doctor checks", () => {
|
||||
it("skips live service checks during the managed unit's own activation", async () => {
|
||||
process.env.PAPERCLIP_SERVICE_MANAGED = "1";
|
||||
const detect = vi.fn();
|
||||
const probe = vi.fn();
|
||||
await expect(serviceHealthChecks(config, { detect, probe })).resolves.toEqual([]);
|
||||
expect(detect).not.toHaveBeenCalled();
|
||||
expect(probe).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("skips exact version matching unless a restart version is explicit", () => {
|
||||
expect(resolveRestartExpectedVersion(null)).toBeNull();
|
||||
expect(resolveRestartExpectedVersion(undefined)).toBeNull();
|
||||
|
||||
@@ -40,6 +40,8 @@ export async function serviceHealthChecks(
|
||||
config: PaperclipConfig,
|
||||
dependencies: Partial<ServiceCheckDependencies> = {},
|
||||
): Promise<CheckResult[]> {
|
||||
if (process.env.PAPERCLIP_SERVICE_MANAGED === "1") return [];
|
||||
|
||||
const deps: ServiceCheckDependencies = {
|
||||
detect: (instanceId) => detectServiceManager({ instanceId }),
|
||||
probe: probeHealth,
|
||||
|
||||
@@ -185,11 +185,18 @@ export async function installGitPayload(repo: string, sha: string, runCommand: C
|
||||
await runCommand("tar", ["-xzf", archivePath, "--strip-components=1", "-C", checkoutPath], { maxBuffer: 4 * 1024 * 1024 });
|
||||
await runCommand("corepack", ["pnpm", "install", "--frozen-lockfile"], { cwd: checkoutPath, maxBuffer: 32 * 1024 * 1024 });
|
||||
await runCommand("bash", ["scripts/build-npm.sh", "--skip-checks"], { cwd: checkoutPath, maxBuffer: 32 * 1024 * 1024 });
|
||||
await runCommand("corepack", ["pnpm", "--filter", "@paperclipai/db", "build"], { cwd: checkoutPath, maxBuffer: 32 * 1024 * 1024 });
|
||||
await runCommand("corepack", ["pnpm", "--filter", "@paperclipai/server", "build"], { cwd: checkoutPath, maxBuffer: 32 * 1024 * 1024 });
|
||||
const metadata = JSON.parse(fs.readFileSync(path.join(checkoutPath, "cli", "package.json"), "utf8")) as { version: string };
|
||||
await runCommand("corepack", ["pnpm", "--dir", "packages/db", "pack", "--pack-destination", stagingRoot], { cwd: checkoutPath, maxBuffer: 16 * 1024 * 1024 });
|
||||
await runCommand("corepack", ["pnpm", "--dir", "server", "pack", "--pack-destination", stagingRoot], { cwd: checkoutPath, env: { ...process.env, PAPERCLIP_RELEASE_REUSE_UI_DIST: "1" }, maxBuffer: 32 * 1024 * 1024 });
|
||||
await runCommand("npm", ["pack", "--pack-destination", stagingRoot], { cwd: path.join(checkoutPath, "cli"), maxBuffer: 16 * 1024 * 1024 });
|
||||
const tarball = fs.readdirSync(stagingRoot).find((entry) => entry.endsWith(".tgz"));
|
||||
if (!tarball) throw new Error("npm pack did not produce a paperclipai tarball.");
|
||||
await runCommand("npm", ["install", "--prefix", stagedPayload, path.join(stagingRoot, tarball), "--no-audit", "--no-fund"], { cwd: stagingRoot, maxBuffer: 32 * 1024 * 1024 });
|
||||
const tarballs = fs.readdirSync(stagingRoot).filter((entry) => entry.endsWith(".tgz"));
|
||||
const cliTarball = tarballs.find((entry) => /^paperclipai-(?!db-|server-)/.test(entry));
|
||||
const dbTarball = tarballs.find((entry) => entry.startsWith("paperclipai-db-"));
|
||||
const serverTarball = tarballs.find((entry) => entry.startsWith("paperclipai-server-"));
|
||||
if (!cliTarball || !dbTarball || !serverTarball) throw new Error("Git install packaging did not produce paperclipai, @paperclipai/db, and @paperclipai/server tarballs.");
|
||||
await runCommand("npm", ["install", "--prefix", stagedPayload, path.join(stagingRoot, cliTarball), path.join(stagingRoot, dbTarball), path.join(stagingRoot, serverTarball), "--no-audit", "--no-fund"], { cwd: stagingRoot, maxBuffer: 32 * 1024 * 1024 });
|
||||
await smokePayload(stagedPayload, metadata.version, runCommand);
|
||||
fs.renameSync(stagedPayload, payloadPath);
|
||||
return { payloadPath, reused: false, version: metadata.version };
|
||||
|
||||
Reference in new issue
Block a user