Files
openwork/evals/scripts/provision-org-connector-two-members.ts

128 lines
4.3 KiB
TypeScript

import { readFile, writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import { parseArgs } from "node:util";
import {
deleteSandboxes,
parseConnectorE2eTestEnv,
provisionDenSandbox,
provisionDesktopSandbox,
renderConnectorE2eTestEnv,
startMockOnSandbox,
} from "@openwork/hosts";
import type { DesktopSandbox } from "@openwork/hosts";
const USAGE = `Usage:
node scripts/provision-org-connector-two-members.ts --ref <branch-or-commit> [--reuse-a <id>] [--reuse-b <id>] [--reuse-den <id>] [--out org-connector-two-members.env]
node scripts/provision-org-connector-two-members.ts --delete <envfile>
node scripts/provision-org-connector-two-members.ts --help`;
function prefixed(prefix: string, observe?: (line: string) => void): (line: string) => void {
return (line) => {
observe?.(line);
console.error(`[${prefix}] ${line}`);
};
}
async function deleteProvisioned(envFile: string): Promise<void> {
const facts = parseConnectorE2eTestEnv(await readFile(envFile, "utf8"));
await deleteSandboxes(facts.created);
const created = new Set(facts.created);
const leftAlone = [facts.sandboxA, facts.sandboxB].filter((sandbox) => !created.has(sandbox));
console.log(`Deleted: ${facts.created.join(", ") || "(none)"}`);
console.log(`Left alone: ${leftAlone.join(", ") || "(none recorded)"}`);
}
async function provisionSpecEnv(options: {
ref: string;
reuseA?: string;
reuseB?: string;
reuseDen?: string;
out: string;
}): Promise<void> {
const created: string[] = [];
function recordCreated(sandbox: string): void {
if (!created.includes(sandbox)) created.push(sandbox);
}
try {
const denLog = prefixed("den", (line) => {
const match = /Creating server sandbox:\s*(\S+)/.exec(line);
if (match?.[1]) recordCreated(match[1]);
});
const den = await provisionDenSandbox({ ref: options.ref, reuse: options.reuseDen, log: denLog });
if (den.created) recordCreated(den.sandbox);
const mock = await startMockOnSandbox({ sandbox: den.sandbox, log: prefixed("mock") });
async function desktop(name: "a" | "b", reuse: string | undefined): Promise<DesktopSandbox> {
const desktopLog = prefixed(name, (line) => {
const match = /desktop sandbox created:\s*(\S+)/.exec(line);
if (match?.[1]) recordCreated(match[1]);
});
const result = await provisionDesktopSandbox({ ref: options.ref, name, reuse, log: desktopLog });
if (result.created) recordCreated(result.sandbox);
return result;
}
const [desktopA, desktopB] = await Promise.all([
desktop("a", options.reuseA),
desktop("b", options.reuseB),
]);
await writeFile(options.out, renderConnectorE2eTestEnv({
denApiUrl: den.apiUrl,
denWebUrl: den.webUrl,
sandboxA: desktopA.sandbox,
sandboxB: desktopB.sandbox,
mockUrl: mock.url,
ref: options.ref,
created,
}), "utf8");
console.log(`Wrote ${resolve(options.out)}`);
console.log(`set -a; source ${options.out}; set +a`);
console.log("pnpm --dir evals exec vitest run --config vitest.config.ts --project e2e specs/org-connector-two-members.e2e.test.ts");
console.log(`node scripts/provision-org-connector-two-members.ts --delete ${options.out}`);
} catch (error) {
console.error(`Provisioning failed. Provision-created sandboxes so far: ${created.join(", ") || "(none)"}`);
throw error;
}
}
async function main(argv: string[]): Promise<void> {
const { values } = parseArgs({
args: argv,
options: {
ref: { type: "string" },
"reuse-a": { type: "string" },
"reuse-b": { type: "string" },
"reuse-den": { type: "string" },
out: { type: "string" },
delete: { type: "string" },
help: { type: "boolean", short: "h" },
},
strict: true,
allowPositionals: false,
});
if (values.help) {
console.log(USAGE);
return;
}
if (values.delete) {
await deleteProvisioned(values.delete);
return;
}
if (!values.ref) throw new Error(`--ref is required.\n\n${USAGE}`);
await provisionSpecEnv({
ref: values.ref,
reuseA: values["reuse-a"],
reuseB: values["reuse-b"],
reuseDen: values["reuse-den"],
out: values.out ?? "org-connector-two-members.env",
});
}
main(process.argv.slice(2)).catch((error: unknown) => {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});