163 lines
5.8 KiB
TypeScript
163 lines
5.8 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { renderUsage } from "citty";
|
|
import { login, logout, whoami } from "../../command/auth";
|
|
import { db } from "../../command/db";
|
|
import { down } from "../../command/down";
|
|
import { exec } from "../../command/exec";
|
|
import { exportCommand } from "../../command/export";
|
|
import { logs } from "../../command/logs";
|
|
import { initializeCompletion, main } from "../../command/main";
|
|
import { maintenance } from "../../command/maintenance";
|
|
import { ps } from "../../command/ps";
|
|
import { restart } from "../../command/restart";
|
|
import { rollback } from "../../command/rollback";
|
|
import { s3 } from "../../command/s3";
|
|
import { start } from "../../command/start";
|
|
import { stop } from "../../command/stop";
|
|
import { up } from "../../command/up";
|
|
|
|
type Command = {
|
|
meta?: { name?: string; description?: string; hidden?: boolean };
|
|
args?: Record<string, Record<string, unknown>>;
|
|
subCommands?: Record<string, Command>;
|
|
run?: unknown;
|
|
};
|
|
|
|
describe("CLI command definitions", () => {
|
|
const commands = [
|
|
["kuber", "Deploy and manage projects on Kubernetes", main],
|
|
["up", "Create and start deployments", up],
|
|
["login", "Log in to the cluster", login],
|
|
["logout", "Log out of kuber.astrxl.dev", logout],
|
|
["whoami", "Show the current kuber user", whoami],
|
|
["start", "Start deployments without rebuilding images", start],
|
|
["stop", "Stop all deployments", stop],
|
|
["restart", "Restart deployments", restart],
|
|
["rollback", "Roll deployments back to the previous release", rollback],
|
|
["maintenance", "Toggle maintenance page on hostnames", maintenance],
|
|
["s3", "View project object storage settings", s3],
|
|
["down", "Delete managed resources except ingress and PVCs", down],
|
|
["ps", "List deployments", ps],
|
|
["logs", "Show deployment logs", logs],
|
|
["exec", "Execute a command inside a deployment pod", exec],
|
|
["export", "Write rendered manifests to a YAML file", exportCommand],
|
|
["db", "View project databases and credentials", db],
|
|
] as const;
|
|
|
|
test.each(commands)(
|
|
"defines %s command metadata",
|
|
(name, description, command) => {
|
|
const definition = command as Command;
|
|
expect(definition.meta).toMatchObject({ name, description });
|
|
if (name !== "kuber" && name !== "db" && name !== "s3")
|
|
expect(typeof definition.run).toBe("function");
|
|
if (name === "kuber") expect(definition.run).toBeUndefined();
|
|
},
|
|
);
|
|
|
|
test("defines the rollback command alias", () => {
|
|
expect((rollback as Command).meta).toMatchObject({ alias: "fuck" });
|
|
});
|
|
|
|
test("defines build, cleanup, listing, logging, and export flags", () => {
|
|
expect((up as Command).args?.build).toMatchObject({
|
|
type: "boolean",
|
|
alias: "b",
|
|
default: true,
|
|
});
|
|
expect((down as Command).args?.full).toMatchObject({
|
|
type: "boolean",
|
|
alias: "f",
|
|
});
|
|
expect((ps as Command).args?.all).toMatchObject({
|
|
type: "boolean",
|
|
alias: "a",
|
|
});
|
|
expect((logs as Command).args?.follow).toMatchObject({
|
|
type: "boolean",
|
|
alias: "f",
|
|
});
|
|
expect((exportCommand as Command).args?.output).toMatchObject({
|
|
type: "string",
|
|
alias: "o",
|
|
});
|
|
expect((main as Command).args?.config).toMatchObject({
|
|
type: "string",
|
|
});
|
|
expect((login as Command).args?.session).toMatchObject({
|
|
type: "boolean",
|
|
});
|
|
});
|
|
|
|
test("defines both database inspection subcommands", () => {
|
|
const subCommands = (db as Command).subCommands;
|
|
expect(Object.keys(subCommands ?? {}).sort()).toEqual(["creds", "ls"]);
|
|
expect(subCommands?.ls?.meta?.name).toBe("ls");
|
|
expect(subCommands?.creds?.meta?.name).toBe("creds");
|
|
expect(typeof subCommands?.ls?.run).toBe("function");
|
|
expect(typeof subCommands?.creds?.run).toBe("function");
|
|
});
|
|
|
|
test("defines S3 inspection subcommands", () => {
|
|
const subCommands = (s3 as Command).subCommands;
|
|
expect(Object.keys(subCommands ?? {}).sort()).toEqual([
|
|
"creds",
|
|
"ls",
|
|
"ui",
|
|
]);
|
|
expect(subCommands?.ls?.meta?.name).toBe("ls");
|
|
expect(subCommands?.creds?.meta?.name).toBe("creds");
|
|
expect(subCommands?.ui?.meta?.name).toBe("ui");
|
|
expect(typeof subCommands?.ls?.run).toBe("function");
|
|
expect(typeof subCommands?.creds?.run).toBe("function");
|
|
expect(typeof subCommands?.ui?.run).toBe("function");
|
|
});
|
|
|
|
test("registers shell completion on the root command", async () => {
|
|
await initializeCompletion();
|
|
expect((await Promise.resolve(main.meta))?.name).toBe("kuber");
|
|
expect(
|
|
Object.keys((await Promise.resolve(main.subCommands)) ?? {}),
|
|
).toContain("complete");
|
|
});
|
|
|
|
test("hides internal commands only from root help", async () => {
|
|
const usage = await renderUsage(main);
|
|
for (const name of [
|
|
"ci",
|
|
"whoami",
|
|
"logout",
|
|
"operations",
|
|
"maintenance",
|
|
"audit",
|
|
"users",
|
|
]) {
|
|
expect(usage).not.toContain(name);
|
|
expect(usage).not.toContain(`${name}|`);
|
|
}
|
|
for (const name of ["add", "login", "up"]) expect(usage).toContain(name);
|
|
});
|
|
|
|
test("does not mutate exported command metadata when loading hidden commands", async () => {
|
|
await renderUsage(main);
|
|
const { ci } = await import("../../command/ci");
|
|
const { whoami, logout } = await import("../../command/auth");
|
|
const { operations } = await import("../../command/operations");
|
|
const { maintenance } = await import("../../command/maintenance");
|
|
const { audit } = await import("../../command/audit");
|
|
const { users } = await import("../../command/users");
|
|
for (const command of [
|
|
ci,
|
|
whoami,
|
|
logout,
|
|
operations,
|
|
maintenance,
|
|
audit,
|
|
users,
|
|
])
|
|
expect(
|
|
(command as Command & { meta?: { hidden?: boolean } }).meta?.hidden,
|
|
).toBeUndefined();
|
|
});
|
|
});
|