Archived
feat: unify Docker entrypoint
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
@@ -8,10 +8,20 @@ import type { PiWebComponentStatus } from "../shared/apiTypes.js";
|
||||
|
||||
const originalSkipVersionCheck = process.env["PI_WEB_SKIP_VERSION_CHECK"];
|
||||
const originalHome = process.env["HOME"];
|
||||
const originalPath = process.env["PATH"];
|
||||
const originalDockerRuntime = process.env["PI_WEB_DOCKER_RUNTIME"];
|
||||
const originalDockerMode = process.env["PI_WEB_DOCKER_MODE"];
|
||||
const originalDockerInstallDir = process.env["PI_WEB_DOCKER_INSTALL_DIR"];
|
||||
const originalDockerDevRepoRoot = process.env["PI_WEB_DOCKER_DEV_REPO_ROOT"];
|
||||
|
||||
afterEach(() => {
|
||||
restoreEnv("PI_WEB_SKIP_VERSION_CHECK", originalSkipVersionCheck);
|
||||
restoreEnv("HOME", originalHome);
|
||||
restoreEnv("PATH", originalPath);
|
||||
restoreEnv("PI_WEB_DOCKER_RUNTIME", originalDockerRuntime);
|
||||
restoreEnv("PI_WEB_DOCKER_MODE", originalDockerMode);
|
||||
restoreEnv("PI_WEB_DOCKER_INSTALL_DIR", originalDockerInstallDir);
|
||||
restoreEnv("PI_WEB_DOCKER_DEV_REPO_ROOT", originalDockerDevRepoRoot);
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
@@ -42,6 +52,7 @@ describe("PI WEB status", () => {
|
||||
|
||||
it("reports stale session daemon versions as messages", async () => {
|
||||
process.env["PI_WEB_SKIP_VERSION_CHECK"] = "1";
|
||||
disableDockerRuntimeEnv();
|
||||
const daemon = daemonWithComponent({
|
||||
component: "sessiond",
|
||||
label: "Session daemon",
|
||||
@@ -63,9 +74,13 @@ describe("PI WEB status", () => {
|
||||
it("suggests native systemd commands for local development services", async () => {
|
||||
if (process.platform !== "linux") return;
|
||||
process.env["PI_WEB_SKIP_VERSION_CHECK"] = "1";
|
||||
disableDockerRuntimeEnv();
|
||||
const home = await tempHome();
|
||||
const binDir = await tempHome();
|
||||
try {
|
||||
process.env["HOME"] = home;
|
||||
await installExecutable(binDir, "systemctl");
|
||||
process.env["PATH"] = `${binDir}:${process.env["PATH"] ?? ""}`;
|
||||
await installSystemdServiceFiles(home, ["pi-web-sessiond.service", "pi-web-ui-dev.service"]);
|
||||
const daemon = daemonWithComponent(staleLocalSessiond());
|
||||
|
||||
@@ -76,12 +91,72 @@ describe("PI WEB status", () => {
|
||||
expect(status.commands.restartSessiond).toBe("systemd-run --user --collect --unit=pi-web-restart-sessiond -- systemctl --user restart pi-web-sessiond.service");
|
||||
expect(status.messages.find((message) => message.id === "sessiond-stale")?.command).toBe("systemd-run --user --collect --unit=pi-web-restart-sessiond -- systemctl --user restart pi-web-sessiond.service");
|
||||
} finally {
|
||||
await rm(home, { recursive: true, force: true });
|
||||
await Promise.all([
|
||||
rm(home, { recursive: true, force: true }),
|
||||
rm(binDir, { recursive: true, force: true }),
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
it("suggests Docker commands when running inside the Docker runtime", async () => {
|
||||
process.env["PI_WEB_SKIP_VERSION_CHECK"] = "1";
|
||||
process.env["PI_WEB_DOCKER_RUNTIME"] = "1";
|
||||
process.env["PI_WEB_DOCKER_MODE"] = "runtime";
|
||||
process.env["PI_WEB_DOCKER_INSTALL_DIR"] = "/srv/pi-web-docker";
|
||||
process.env["PATH"] = "";
|
||||
const daemon = daemonWithComponent({ ...staleLocalSessiond(), installation: { kind: "docker", path: "/srv/pi-web-docker", dockerMode: "runtime" } });
|
||||
|
||||
const status = await getPiWebStatus(daemon);
|
||||
|
||||
expect(status.components.web.installation).toEqual({ kind: "docker", path: "/srv/pi-web-docker", dockerMode: "runtime" });
|
||||
expect(status.commands).toEqual({
|
||||
update: "pi-web-docker update",
|
||||
restart: "pi-web-docker restart",
|
||||
restartWeb: "pi-web-docker restart-web",
|
||||
restartSessiond: "pi-web-docker restart-sessiond",
|
||||
status: "pi-web-docker status",
|
||||
});
|
||||
expect(JSON.stringify(status)).not.toContain("npm install -g");
|
||||
expect(JSON.stringify(status)).not.toContain("pi-web restart");
|
||||
});
|
||||
|
||||
it("suggests explicit Docker development commands when running inside the Docker dev runtime", async () => {
|
||||
process.env["PI_WEB_SKIP_VERSION_CHECK"] = "1";
|
||||
process.env["PI_WEB_DOCKER_RUNTIME"] = "1";
|
||||
process.env["PI_WEB_DOCKER_MODE"] = "dev";
|
||||
process.env["PI_WEB_DOCKER_DEV_REPO_ROOT"] = "/workspace/pi-web";
|
||||
process.env["PATH"] = "";
|
||||
const daemon = daemonWithComponent({ ...staleLocalSessiond(), installation: { kind: "docker", path: "/workspace/pi-web", dockerMode: "dev" } });
|
||||
|
||||
const status = await getPiWebStatus(daemon);
|
||||
|
||||
expect(status.commands).toEqual({
|
||||
update: "pi-web-docker --dev update",
|
||||
restart: "pi-web-docker --dev restart",
|
||||
restartWeb: "pi-web-docker --dev restart-web",
|
||||
restartSessiond: "pi-web-docker --dev restart-sessiond",
|
||||
status: "pi-web-docker --dev status",
|
||||
});
|
||||
});
|
||||
|
||||
it("infers explicit Docker development commands from the generated dev root when mode is omitted", async () => {
|
||||
process.env["PI_WEB_SKIP_VERSION_CHECK"] = "1";
|
||||
process.env["PI_WEB_DOCKER_RUNTIME"] = "1";
|
||||
Reflect.deleteProperty(process.env, "PI_WEB_DOCKER_MODE");
|
||||
process.env["PI_WEB_DOCKER_DEV_REPO_ROOT"] = "/workspace/pi-web";
|
||||
process.env["PATH"] = "";
|
||||
const daemon = daemonWithComponent(staleLocalSessiond());
|
||||
|
||||
const status = await getPiWebStatus(daemon);
|
||||
|
||||
expect(status.components.web.installation).toEqual({ kind: "docker", path: "/workspace/pi-web", dockerMode: "dev" });
|
||||
expect(status.commands.update).toBe("pi-web-docker --dev update");
|
||||
expect(status.commands.status).toBe("pi-web-docker --dev status");
|
||||
});
|
||||
|
||||
it("omits local restart commands when no native service command is known", async () => {
|
||||
process.env["PI_WEB_SKIP_VERSION_CHECK"] = "1";
|
||||
disableDockerRuntimeEnv();
|
||||
const home = await tempHome();
|
||||
try {
|
||||
process.env["HOME"] = home;
|
||||
@@ -131,6 +206,19 @@ async function installSystemdServiceFiles(home: string, names: string[]): Promis
|
||||
await Promise.all(names.map((name) => writeFile(join(dir, name), "")));
|
||||
}
|
||||
|
||||
async function installExecutable(dir: string, name: string): Promise<void> {
|
||||
const path = join(dir, name);
|
||||
await writeFile(path, "#!/usr/bin/env sh\nexit 0\n");
|
||||
await chmod(path, 0o755);
|
||||
}
|
||||
|
||||
function disableDockerRuntimeEnv(): void {
|
||||
process.env["PI_WEB_DOCKER_RUNTIME"] = "0";
|
||||
Reflect.deleteProperty(process.env, "PI_WEB_DOCKER_MODE");
|
||||
Reflect.deleteProperty(process.env, "PI_WEB_DOCKER_INSTALL_DIR");
|
||||
Reflect.deleteProperty(process.env, "PI_WEB_DOCKER_DEV_REPO_ROOT");
|
||||
}
|
||||
|
||||
function restoreEnv(key: string, value: string | undefined): void {
|
||||
if (value === undefined) Reflect.deleteProperty(process.env, key);
|
||||
else process.env[key] = value;
|
||||
|
||||
Reference in New Issue
Block a user