google-labs-jules[bot] 752bfcf03e Refactor infra/setup/cli.ts into smaller command and prompt modules
Decomposes the monolith `infra/setup/cli.ts` into clean `infra/setup/prompts/` and `infra/setup/commands/` directories while adhering to Cliffy idiomatic modularity. Validated via `deno check`, tests, and format.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-26 04:37:41 +00:00

135 lines
3.8 KiB
TypeScript

import { Input, Secret } from "jsr:@cliffy/prompt@1.0.0-rc.7";
import * as colors from "jsr:@std/fmt@0.225.2/colors";
import {
generateDockerCompose,
generateSpireDockerCompose,
} from "../compose.ts";
import {
AuthSetupConfig,
COMPOSE_PATH,
ENV_PATH,
generateEnv,
generateSpireEnv,
SPIRE_COMPOSE_PATH,
SPIRE_ENV_PATH,
} from "../env.ts";
export async function promptAuthConfig(
currentConfig: AuthSetupConfig,
): Promise<Partial<AuthSetupConfig>> {
console.log(
colors.gray(
"Please provide the following Auth Yes configuration details.\n",
),
);
const reg = await Input.prompt({
message: "Enter the Primary Container Registry URL:",
default: currentConfig.reg,
});
const ghcrReg = await Input.prompt({
message: "Enter the GHCR Mirror Registry URL (for SPIRE):",
default: currentConfig.ghcrReg || "ghcr.atyg.org",
});
const domainName = await Input.prompt({
message: "Enter the Auth Domain Name:",
hint: "E.g., auth.system.local",
default: currentConfig.domainName,
});
const appSecret = await Secret.prompt({
message: "Enter the App Secret for the IDP:",
default: currentConfig.appSecret,
minLength: 16,
});
const pwdMessage = currentConfig.dbPassword
? "Enter the PostgreSQL database password: (Leave blank to keep existing password)"
: "Enter the PostgreSQL database password:";
const pwdInput = await Secret.prompt({
message: pwdMessage,
minLength: currentConfig.dbPassword ? 0 : 1,
});
const dbPassword = pwdInput === "" && currentConfig.dbPassword !== ""
? currentConfig.dbPassword
: pwdInput;
return { reg, ghcrReg, domainName, appSecret, dbPassword };
}
export async function promptSpireConfig(
currentConfig: AuthSetupConfig,
): Promise<Partial<AuthSetupConfig>> {
const dbDataPath = await Input.prompt({
message: "Enter the Database Path on the Host:",
default: currentConfig.dbDataPath,
});
const spireDataPath = await Input.prompt({
message: "Enter the SPIRE Path on the Host:",
default: currentConfig.spireDataPath,
});
return { dbDataPath, spireDataPath };
}
export async function promptConfirmation(): Promise<void> {
// Empty implementation as there was no explicit confirmation in cli.ts before
// But we add it to cleanly delineate the flow as requested.
}
export async function generateAuthSetupFiles(
config: AuthSetupConfig,
): Promise<void> {
const envContent = generateEnv(config);
await Deno.writeTextFile(ENV_PATH, envContent);
const spireEnvContent = generateSpireEnv(config);
await Deno.writeTextFile(SPIRE_ENV_PATH, spireEnvContent);
const composeContent = generateDockerCompose();
await Deno.writeTextFile(COMPOSE_PATH, composeContent);
const spireComposeContent = generateSpireDockerCompose();
await Deno.writeTextFile(SPIRE_COMPOSE_PATH, spireComposeContent);
console.log(
colors.green(
`\n✓ Successfully generated ${ENV_PATH}, ${SPIRE_ENV_PATH}, ${COMPOSE_PATH}, and ${SPIRE_COMPOSE_PATH}!`,
),
);
console.log(
colors.green("Setup complete. You may deploy your stacks by running:\n"),
);
console.log(
colors.cyan(
"1. Deploy SPIRE Stack:\n" +
" podman-compose --project-name spire --env-file infra/.env.spire -f infra/compose.spire.yml up -d\n\n" +
"2. Deploy Auth-Yes Stack:\n" +
" podman-compose --project-name auth-yes --env-file infra/stack.env -f infra/compose.yml up -d\n",
),
);
}
export async function handleAuthSetup(
currentConfig: AuthSetupConfig,
): Promise<AuthSetupConfig> {
const authConfig = await promptAuthConfig(currentConfig);
const spireConfig = await promptSpireConfig(currentConfig);
const newConfig: AuthSetupConfig = {
...currentConfig,
...authConfig,
...spireConfig,
};
await promptConfirmation();
await generateAuthSetupFiles(newConfig);
return newConfig;
}