@limlabs/limo
Version:
Infrastructure as Code generator
238 lines (237 loc) • 10.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getResourceGroupType = exports.getFramework = exports.getResourceGroupName = exports.init = exports.initOptionsSchema = void 0;
const zod_1 = __importDefault(require("zod"));
const commander_1 = require("commander");
const prompts_1 = __importDefault(require("prompts"));
const path_1 = __importDefault(require("path"));
const frameworks_1 = require("../frameworks");
const resourceGroups_1 = require("../resourceGroups");
const workspace_1 = require("../workspace");
const data_1 = require("../migrations/data");
const process_1 = require("process");
const apply_1 = require("../migrations/apply");
const date_1 = require("../utils/date");
const templates_1 = require("../templates");
const cli_helpers_1 = require("../cli-helpers");
exports.initOptionsSchema = zod_1.default.object({
directory: zod_1.default.string().optional().default(process.cwd()),
name: zod_1.default.string().optional(),
framework: zod_1.default.string().optional(),
resourceGroupType: zod_1.default.enum(resourceGroups_1.AllResourceGroupTypes).optional(),
noScroll: zod_1.default.boolean().optional(),
apply: zod_1.default.boolean().optional()
});
exports.init = new commander_1.Command()
.name("init")
.allowUnknownOption(true)
.description("Initialize a new infrastructure resource group")
.option("-d, --directory <directory>", "Directory where the infrastructure folder should be added", process.cwd())
.option("-n, --name <name>", "Name of the resourceGroup")
.option("-t, --resourceGroupType <type>", "Type of resource group to create")
.option("-f, --framework <framework>", "Framework to use")
.option("--noScroll", "Disable scrolling output")
.option("--apply", "Apply the generated platform migration")
.option("--inputs <otherInputs>", "Resource group / framework specific inputs: comma separated key=value format")
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b;
const cmdArgs = exports.initOptionsSchema.parse(options);
const other = (0, cli_helpers_1.parseOtherArgs)((_b = (_a = options.inputs) === null || _a === void 0 ? void 0 : _a.split(",")) !== null && _b !== void 0 ? _b : []);
if (cmdArgs.directory) {
process.chdir(cmdArgs.directory);
}
let frameworkType = cmdArgs.framework;
if (!frameworkType) {
frameworkType = yield (0, frameworks_1.detectFramework)(cmdArgs.directory);
}
frameworkType =
frameworkType != "unknown" ? frameworkType : yield getFramework(cmdArgs);
yield (0, workspace_1.renderWorkspace)();
const resourceGroupName = yield getResourceGroupName(cmdArgs);
const resourceGroupType = yield getResourceGroupType(cmdArgs, frameworkType);
const resourceGroup = (0, resourceGroups_1.importResourceGroupType)(resourceGroupType, resourceGroupName, cmdArgs.directory);
if (!resourceGroup || !resourceGroup.inputSchema) {
throw new Error("Resource group type not found");
}
const promptInputs = [];
if (frameworkType !== "unknown") {
const framework = yield (0, frameworks_1.importFramework)(frameworkType, resourceGroupType, resourceGroupName, cmdArgs.directory);
if (!framework) {
throw new Error("Framework not found");
}
if (framework.inputSchema) {
const frameworkInputs = yield (0, templates_1.getInputPrompts)(framework.inputSchema);
promptInputs.push(...frameworkInputs);
}
}
const resourceGroupInputs = yield (0, templates_1.getInputPrompts)(resourceGroup.inputSchema);
resourceGroupInputs.forEach((resourceGroupInput) => {
if (!promptInputs.find((input) => input.name === resourceGroupInput.name)) {
promptInputs.push(resourceGroupInput);
}
});
const answers = {};
const newPrompts = promptInputs.filter((resourceGroup) => {
const key = resourceGroup.name;
const type = resourceGroup.type;
if (other[key]) {
switch (type) {
case "text":
answers[key] = other[key];
break;
case "number":
answers[key] = parseInt(other[key]);
break;
case "confirm":
answers[key] = other[key] === "true";
break;
case "select":
if (!resourceGroup.choices ||
!Array.isArray(resourceGroup.choices)) {
throw new Error(`Error choices not found for select type: ${resourceGroup.name}`);
}
if (resourceGroup.choices.filter((choice) => choice.value === other[key]).length === 0) {
throw new Error(`Error choice ${other[key]} not found for select type: ${resourceGroup.name}`);
}
answers[key] = other[key];
default:
break;
}
return false;
}
return true;
});
const inputs = yield (0, prompts_1.default)(newPrompts);
const initID = `init-${resourceGroupName}`.replace(" ", "-");
const initMigration = {
id: initID,
up: [
{
type: "initResourceGroup",
options: {
args: {
name: resourceGroupName,
type: resourceGroupType,
framework: frameworkType,
inputs: Object.assign(Object.assign({}, answers), inputs)
}
}
}
],
down: [
{
type: "removeResourceGroup",
options: {
args: {
name: resourceGroupName
}
}
}
]
};
if (frameworkType !== "unknown") {
initMigration.up.push({
type: "configureFramework",
options: {
args: {
frameworkType: frameworkType,
resourceGroupType: resourceGroupType,
resourceGroupName: resourceGroupName,
operation: "apply",
inputs: Object.assign(Object.assign({}, answers), inputs)
}
}
});
if (!initMigration.down) {
initMigration.down = [];
}
initMigration.down.push({
type: "configureFramework",
options: {
args: {
frameworkType: frameworkType,
resourceGroupType: resourceGroupType,
resourceGroupName: resourceGroupName,
operation: "revert",
inputs: Object.assign(Object.assign({}, answers), inputs)
}
}
});
}
yield (0, data_1.ensureMigrations)();
const infrastructurePath = path_1.default.join((0, process_1.cwd)(), "infrastructure");
const migrationPath = path_1.default.join(infrastructurePath, "migrations");
const timestamp = (0, date_1.getCurrentTimestamp)();
yield (0, apply_1.ensureMigrationNotApplied)(initMigration);
yield (0, data_1.exportMigration)(initMigration, path_1.default.join(migrationPath, `${timestamp}-${initID}.yaml`));
if (cmdArgs.apply === true) {
yield (0, apply_1.triggerMigration)(initMigration, true, {
noScroll: cmdArgs.noScroll
});
}
else {
console.log("Migration created but not applied.");
}
}));
function getResourceGroupName(cmdArgs) {
return __awaiter(this, void 0, void 0, function* () {
if (cmdArgs.name) {
return cmdArgs.name;
}
const answer = yield (0, prompts_1.default)({
type: "text",
name: "name",
message: "Select a resource group name"
});
return answer.name;
});
}
exports.getResourceGroupName = getResourceGroupName;
function getFramework(cmdArgs) {
return __awaiter(this, void 0, void 0, function* () {
if (cmdArgs.framework) {
return cmdArgs.framework;
}
const answer = yield (0, prompts_1.default)({
type: "select",
name: "framework",
message: "Select a framework",
choices: frameworks_1.AllFrameworkTypes.map((type) => ({ title: type, value: type }))
});
return answer.framework;
});
}
exports.getFramework = getFramework;
function getResourceGroupType(cmdArgs, frameworkType) {
return __awaiter(this, void 0, void 0, function* () {
if (cmdArgs.resourceGroupType) {
return cmdArgs.resourceGroupType;
}
const supportedResourceGroupTypes = frameworkType === "unknown"
? resourceGroups_1.AllResourceGroupTypes
: yield (0, frameworks_1.getSupportedResourceGroupTypesForFramework)(frameworkType);
const answer = yield (0, prompts_1.default)({
type: "select",
name: "resourceGroupType",
message: "Select a resource group type",
choices: supportedResourceGroupTypes.map((type) => ({
title: type,
value: type
}))
});
return answer.resourceGroupType;
});
}
exports.getResourceGroupType = getResourceGroupType;