UNPKG

limgen

Version:

Infrastructure as Code generator

107 lines (86 loc) 3.35 kB
import { AllProjectTypes, importProjectType, ProjectType, readProjectMetadata } from "@/project"; import { Command } from "commander"; import { z } from 'zod'; import fs from 'fs/promises'; import path from "path"; import prompts from "prompts"; import { spinner } from "@/cli-helpers"; import { execPromise } from "@/exec"; const envPullOptionsSchema = z.object({ project: z.string().optional(), stack: z.string().optional(), directory: z.string().optional(), }); export type EnvPullOptions = z.infer<typeof envPullOptionsSchema>; export const envPull = new Command() .name('env-pull') .description('Pull project environment variables into a local .env file') .option('-p, --projectName <project>', 'Name of the project to pull environment variables from') .option('-s, --stack <stack>', 'Name of the stack to pull environment variables from') .option('-d, --directory <directory>', 'Directory for the base infrastructure folder') .action(async (options: any) => { const cmdArgs = envPullOptionsSchema.parse({ options }); if (options.directory) { process.chdir(options.directory); } const projectName = await getProjectName(cmdArgs); const projectType = await getProjectType({ projectName }); const project = await importProjectType(projectType); if (!project.envPull) { throw new Error(`Project type ${projectType} does not support env-pull`); } const stack = await getStackName({ projectName, stack: cmdArgs.stack, }); const msg = spinner(`Pulling environment variables for ${projectName} stack ${stack}`).start(); await project.envPull({ projectName, stack, }); msg.succeed(`Environment variables pulled for ${projectName} stack ${stack}`); }); async function getProjectName(cmdArgs: EnvPullOptions): Promise<string> { if (cmdArgs.project) { return cmdArgs.project; } // get the project name from a prompt by reading what's in the infrastructure folder relative to ${directory} const projects = await fs.readdir('infrastructure/projects'); // use a prompt from prompts() furnction const { projectName } = await prompts({ type: 'select', name: 'projectName', message: 'Select a project', choices: projects.map((project) => ({ title: project, value: project })), }); return projectName; } async function getProjectType( { projectName }: { projectName: string }): Promise<ProjectType> { const metadata = await readProjectMetadata({ projectName: projectName, }); if (!AllProjectTypes.includes(metadata.projectType as ProjectType)) { throw new Error(`Unsupported project type: ${metadata.projectType}`); } return metadata.projectType as ProjectType; } async function getStackName(opts: { projectName: string; stack?: string; }) { if (opts.stack) { return opts.stack; } const { stdout } = await execPromise('pulumi stack ls --json', { cwd: path.join('infrastructure', 'projects', opts.projectName) }); const stacks = JSON.parse(stdout); if (stacks.length === 0) { throw new Error('No stacks found'); } const { stackName } = await prompts({ type: 'select', name: 'stackName', message: 'Select a stack', choices: stacks.map((stack: any) => ({ title: stack.name, value: stack.name })), }); return stackName; }