UNPKG

@pagopa/dx-cli

Version:

A CLI useful to manage DX tools.

167 lines (166 loc) 6.67 kB
import * as assert from "node:assert/strict"; import { cloudAccountSchema, } from "../../../../domain/cloud-account.js"; import { environmentSchema, getInitializationStatus, hasUserPermissionToInitialize, } from "../../../../domain/environment.js"; import * as azure from "../../../azure/locations.js"; import { getLogger } from "@logtape/logtape"; import { z } from "zod/v4"; import { githubRepoSchema } from "../../../../domain/github-repo.js"; import { getGithubRepo } from "../../../github/github-repo.js"; const initSchema = z.object({ cloudAccountsToInitialize: z.array(cloudAccountSchema), terraformBackend: z .object({ cloudAccount: cloudAccountSchema, }) .optional(), }); const tagsSchema = z.record(z.string(), z.string().min(1)); export const workspaceSchema = z.object({ domain: z.string().default(""), }); export const payloadSchema = z.object({ env: environmentSchema, github: githubRepoSchema, init: initSchema.optional(), tags: tagsSchema, workspace: workspaceSchema, }); const prompts = (deps) => async (inquirer) => { const logger = getLogger(["gen", "env"]); const github = await getGithubRepo(); assert.ok(github, "This generator only works inside a GitHub repository."); logger.debug("github repo {github}", { github }); const answers = await inquirer.prompt([ { choices: [ { name: "PROD", value: "prod" }, { name: "UAT", value: "uat" }, { name: "DEV", value: "dev" }, ], default: "prod", message: "Environment name", name: "env.name", type: "list", }, { choices: [{ name: "Microsoft Azure", value: "azure" }], default: ["azure"], message: "Cloud provider(s)", name: "csp", type: "checkbox", validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Please select at least one cloud provider.", }, { choices: async () => getCloudAccountChoices(await deps.cloudAccountRepository.list()), loop: false, message: "Account(s)", name: "env.cloudAccounts", type: "checkbox", validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Please select a cloud account.", }, { message: "Prefix (2-4 characters)", name: "env.prefix", transformer: (value) => value.trim().toLowerCase(), type: "input", validate: (value) => value.length >= 2 && value.length <= 4 ? true : "Please enter a valid prefix.", }, { message: "Domain (optional)", name: "workspace.domain", transformer: (value) => value.trim().toLowerCase(), type: "input", }, { choices: [ { name: "TECNOLOGIA E SERVIZI", value: "TS000", }, ], default: "TS000 - Tecnologia e Servizi", message: "Cost center", name: "tags.CostCenter", type: "list", validate: (value) => Array.isArray(value) && value.length > 0 ? true : "Please select a Cost Center.", }, { message: "Business unit", name: "tags.BusinessUnit", transformer: (value) => value.trim(), validate: (value) => value.trim().length > 0 ? true : "Business Unit cannot be empty.", }, { message: "Management team", name: "tags.ManagementTeam", transformer: (value) => value.trim(), validate: (value) => value.trim().length > 0 ? true : "Management Team cannot be empty.", }, ]); const payload = payloadSchema.parse({ ...answers, github }); const locations = await inquirer.prompt(payload.env.cloudAccounts.map((account) => ({ choices: getCloudLocationChoices(azure.cloudRegions), default: azure.defaultLocation, message: `Default location for ${account.displayName}`, name: account.id, type: "list", }))); payload.env.cloudAccounts.forEach((account) => { const location = locations[account.id]; if (location) { account.defaultLocation = location; } }); const initStatus = await getInitializationStatus(deps.cloudAccountService, payload.env); logger.debug("initialization status {initStatus}", { initStatus }); if (initStatus.initialized) { return payload; } assert.ok(await hasUserPermissionToInitialize(deps.cloudAccountService, payload.env), "You don't have permission to initialize this environment. Ask your Engineering Leader to initialize it for you."); const missingRemoteBackend = initStatus.issues.some((issue) => issue.type === "MISSING_REMOTE_BACKEND"); const initInput = await inquirer.prompt([ { default: true, message: "The environment is not initialized. Do you want to initialize it now?", name: "init", type: "confirm", }, { choices: getCloudAccountChoices(payload.env.cloudAccounts), message: "Cloud Account to use for the remote Terraform backend", name: "terraformBackend.cloudAccount", type: "list", when: (answers) => answers.init && missingRemoteBackend && payload.env.cloudAccounts.length > 1, }, ]); assert.ok(initInput.init, "Can't proceed without initialization"); payload.init = payloadSchema.shape.init.parse({ cloudAccountsToInitialize: initStatus.issues .filter((issue) => issue.type === "CLOUD_ACCOUNT_NOT_INITIALIZED") .map((issue) => issue.cloudAccount), terraformBackend: missingRemoteBackend ? { cloudAccount: initInput.terraformBackend?.cloudAccount || payload.env.cloudAccounts[0], } : undefined, }); return payload; }; // Creates Inquirer choices, prioritizing those that match the env prefix export const getCloudAccountChoices = (cloudAccounts) => cloudAccounts.map((account) => ({ name: `${account.displayName}`, value: account, })); export const getCloudLocationChoices = (regions) => regions.map((r) => ({ name: r.displayName, value: r.name })); export default prompts;