This repository has been archived on 2026-08-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
pi-web/scripts/smoke-package-install.mjs

133 lines
4.8 KiB
JavaScript

import { execFile } from "node:child_process";
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { createRequire } from "node:module";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { promisify } from "node:util";
const NPM_VERSION = "12.0.1";
const MARKER = "pi-web-package-pty-ok";
const execFileAsync = promisify(execFile);
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
if (process.platform === "win32") {
throw new Error("The installed-package PTY smoke test requires a POSIX shell");
}
const npmExecPath = process.env["npm_execpath"];
if (npmExecPath === undefined || npmExecPath === "") {
throw new Error("npm_execpath is required; run this check through `npm run smoke:package-install`");
}
const root = await mkdtemp(join(tmpdir(), "pi-web-package-install-"));
try {
const packDir = join(root, "pack");
const npmToolDir = join(root, "npm-tool");
const globalPrefix = join(root, "global");
await Promise.all([
mkdir(packDir, { recursive: true }),
mkdir(join(globalPrefix, "lib"), { recursive: true }),
mkdir(npmToolDir, { recursive: true }),
writeFile(join(npmToolDir, "package.json"), '{"private":true}\n'),
]);
const packOutput = await runNpm(npmExecPath, ["pack", "--ignore-scripts", "--json", "--pack-destination", packDir], repoRoot);
const tarballPath = join(packDir, packageTarballFilename(packOutput));
await runNpm(npmExecPath, [
"install",
"--ignore-scripts",
"--no-audit",
"--no-fund",
"--no-package-lock",
"--no-save",
`npm@${NPM_VERSION}`,
], npmToolDir);
const npm12ExecPath = join(npmToolDir, "node_modules", "npm", "bin", "npm-cli.js");
await runNpm(npm12ExecPath, [
"install",
"--global",
tarballPath,
"--prefix",
globalPrefix,
"--allow-scripts=node-pty",
"--no-audit",
"--no-fund",
], root);
const packageRoot = join(globalPrefix, "lib", "node_modules", "@jmfederico", "pi-web");
await smokeInstalledTerminalService(packageRoot);
console.log(`Installed-package PTY smoke test passed with npm ${NPM_VERSION}.`);
} finally {
await rm(root, { recursive: true, force: true });
}
async function runNpm(npmCliPath, args, cwd) {
const result = await execFileAsync(process.execPath, [npmCliPath, ...args], {
cwd,
encoding: "utf8",
maxBuffer: 10 * 1024 * 1024,
timeout: 180_000,
});
return result.stdout;
}
function packageTarballFilename(output) {
const parsed = JSON.parse(output);
if (!Array.isArray(parsed) || parsed.length !== 1 || typeof parsed[0]?.filename !== "string") {
throw new Error("npm pack returned an unexpected result");
}
return parsed[0].filename;
}
async function smokeInstalledTerminalService(packageRoot) {
const requireFromPackage = createRequire(join(packageRoot, "package.json"));
const nodePtyPackageJsonPath = requireFromPackage.resolve("node-pty/package.json");
const nodePtyPackage = JSON.parse(await readFile(nodePtyPackageJsonPath, "utf8"));
if (typeof nodePtyPackage.version !== "string" || nodePtyPackage.version.includes("-")) {
throw new Error(`Installed package resolved a non-stable node-pty version: ${String(nodePtyPackage.version)}`);
}
const terminalModuleUrl = pathToFileURL(join(packageRoot, "dist", "server", "terminals", "terminalService.js")).href;
const { TerminalService } = await import(terminalModuleUrl);
const previousShell = process.env["SHELL"];
process.env["SHELL"] = "/bin/sh";
const service = new TerminalService();
try {
const run = service.runCommand({
origin: "package-smoke",
projectId: "package-smoke",
workspaceId: "package-smoke",
cwd: packageRoot,
title: "Installed package PTY smoke test",
command: `printf '%s' '${MARKER}'`,
});
let output = "";
let detach = () => undefined;
const exitCode = await new Promise((resolvePromise, reject) => {
const timeout = setTimeout(() => reject(new Error(`Timed out waiting for installed node-pty output: ${JSON.stringify(output)}`)), 10_000);
try {
detach = service.attach(run.terminalId, {
output: (data) => { output += data; },
exit: (code) => {
clearTimeout(timeout);
resolvePromise(code);
},
});
} catch (error) {
clearTimeout(timeout);
reject(error);
}
});
detach();
if (exitCode !== 0) throw new Error(`Installed PTY command exited with ${String(exitCode)}`);
if (!output.includes(MARKER)) throw new Error(`Installed PTY output did not contain ${MARKER}: ${JSON.stringify(output)}`);
} finally {
service.dispose();
if (previousShell === undefined) delete process.env["SHELL"];
else process.env["SHELL"] = previousShell;
}
}