From f95d33cfbbc0d94f76b1fb064f8315963cf441ed Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 5 Oct 2025 02:02:12 -0600 Subject: [PATCH] feat: add environment creation and deletion commands - Introduced EnvironmentCreate and EnvironmentDelete commands for managing environments within projects. - Implemented interactive prompts for selecting projects and environments if flags are not provided. - Added flags for projectId, environmentId, name, description, and skipConfirm to enhance command flexibility. - Improved error handling for environment creation and deletion processes. --- src/commands/environment/create.ts | 131 +++++++++++++++++++++++++++++ src/commands/environment/delete.ts | 129 ++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 src/commands/environment/create.ts create mode 100644 src/commands/environment/delete.ts diff --git a/src/commands/environment/create.ts b/src/commands/environment/create.ts new file mode 100644 index 0000000..761008d --- /dev/null +++ b/src/commands/environment/create.ts @@ -0,0 +1,131 @@ +import { Command, Flags } from "@oclif/core"; +import axios from "axios"; +import chalk from "chalk"; +import inquirer from "inquirer"; + +import { getProjects } from "../../utils/shared.js"; +import { readAuthConfig } from "../../utils/utils.js"; +import type { Answers } from "../app/create.js"; + +export default class EnvironmentCreate extends Command { + static description = "Create a new environment within a project."; + + static examples = ["$ <%= config.bin %> environment create"]; + + static flags = { + projectId: Flags.string({ + char: "p", + description: "ID of the project", + required: false, + }), + name: Flags.string({ + char: "n", + description: "Environment name", + required: false, + }), + description: Flags.string({ + char: "d", + description: "Environment description", + required: false, + }), + skipConfirm: Flags.boolean({ + char: "y", + description: "Skip confirmation prompt", + default: false, + }), + }; + + public async run(): Promise { + const auth = await readAuthConfig(this); + const { flags } = await this.parse(EnvironmentCreate); + let { projectId, name, description } = flags; + + // Modo interactivo si no se proporcionan los flags necesarios + if (!projectId || !name) { + console.log(chalk.blue.bold("\n Listing all Projects \n")); + const projects = await getProjects(auth, this); + + // 1. Seleccionar proyecto + if (!projectId) { + const { project } = await inquirer.prompt([ + { + choices: projects.map((project) => ({ + name: project.name, + value: project, + })), + message: "Select a project to create the environment in:", + name: "project", + type: "list", + }, + ]); + projectId = project.projectId; + } + + // 2. Ingresar detalles del environment + if (!name) { + const envDetails = await inquirer.prompt([ + { + message: "Enter the environment name:", + name: "name", + type: "input", + validate: (input) => (input ? true : "Environment name is required"), + default: name, + }, + { + message: "Enter the environment description (optional):", + name: "description", + type: "input", + default: description, + }, + ]); + + name = envDetails.name; + description = envDetails.description; + } + } + + // Confirmar si no se especifica --skipConfirm + if (!flags.skipConfirm) { + const confirm = await inquirer.prompt([ + { + type: 'confirm', + name: 'proceed', + message: 'Do you want to create this environment?', + default: false, + }, + ]); + + if (!confirm.proceed) { + this.error(chalk.yellow("Environment creation cancelled.")); + return; + } + } + + try { + const response = await axios.post( + `${auth.url}/api/trpc/environment.create`, + { + json: { + name, + description, + projectId, + }, + }, + { + headers: { + "x-api-key": auth.token, + "Content-Type": "application/json", + }, + }, + ); + + if (!response.data.result.data.json) { + this.error(chalk.red("Error creating environment")); + } + + this.log(chalk.green(`Environment '${name}' created successfully.`)); + } catch (error: any) { + this.error(chalk.red(`Error creating environment: ${error.message}`)); + } + } +} diff --git a/src/commands/environment/delete.ts b/src/commands/environment/delete.ts new file mode 100644 index 0000000..8417ac1 --- /dev/null +++ b/src/commands/environment/delete.ts @@ -0,0 +1,129 @@ +import { Command, Flags } from "@oclif/core"; +import axios from "axios"; +import chalk from "chalk"; +import inquirer from "inquirer"; + +import { getProjects } from "../../utils/shared.js"; +import { readAuthConfig } from "../../utils/utils.js"; +import type { Answers } from "../app/create.js"; + +export default class EnvironmentDelete extends Command { + static description = "Delete an environment from a project."; + + static examples = [ + "$ <%= config.bin %> environment delete", + "$ <%= config.bin %> environment delete -p ", + ]; + + static flags = { + projectId: Flags.string({ + char: "p", + description: "ID of the project", + required: false, + }), + environmentId: Flags.string({ + char: "e", + description: "ID of the environment to delete", + required: false, + }), + skipConfirm: Flags.boolean({ + char: "y", + description: "Skip confirmation prompt", + default: false, + }), + }; + + public async run(): Promise { + const auth = await readAuthConfig(this); + const { flags } = await this.parse(EnvironmentDelete); + let { projectId, environmentId } = flags; + + // Modo interactivo si no se proporcionan los flags necesarios + if (!projectId || !environmentId) { + console.log(chalk.blue.bold("\n Listing all Projects \n")); + const projects = await getProjects(auth, this); + + let selectedProject; + + // 1. Seleccionar proyecto + if (!projectId) { + const { project } = await inquirer.prompt([ + { + choices: projects.map((project) => ({ + name: project.name, + value: project, + })), + message: "Select a project to delete the environment from:", + name: "project", + type: "list", + }, + ]); + selectedProject = project; + projectId = project.projectId; + } else { + selectedProject = projects.find(p => p.projectId === projectId); + } + + // 2. Seleccionar environment del proyecto + if (!environmentId) { + if (!selectedProject?.environments || selectedProject.environments.length === 0) { + this.error(chalk.yellow("No environments found in this project.")); + } + + const { environment } = await inquirer.prompt([ + { + choices: selectedProject.environments.map((env) => ({ + name: `${env.name} (${env.description})`, + value: env, + })), + message: "Select an environment to delete:", + name: "environment", + type: "list", + }, + ]); + environmentId = environment.environmentId; + } + } + + // Confirmar si no se especifica --skipConfirm + if (!flags.skipConfirm) { + const confirmAnswers = await inquirer.prompt([ + { + default: false, + message: "Are you sure you want to delete this environment? This action cannot be undone.", + name: "confirmDelete", + type: "confirm", + }, + ]); + + if (!confirmAnswers.confirmDelete) { + this.error(chalk.yellow("Environment deletion cancelled.")); + } + } + + try { + const response = await axios.post( + `${auth.url}/api/trpc/environment.remove`, + { + json: { + environmentId, + }, + }, + { + headers: { + "x-api-key": auth.token, + "Content-Type": "application/json", + }, + }, + ); + + if (!response.data.result.data.json) { + this.error(chalk.red("Error deleting environment")); + } + + this.log(chalk.green("Environment deleted successfully.")); + } catch (error: any) { + this.error(chalk.red(`Error deleting environment: ${error.message}`)); + } + } +}