mirror of
https://github.com/Dokploy/cli.git
synced 2026-06-15 20:25:22 +02:00
refactor: migrate to biome and update CLI structure
- Removed ESLint configuration and ignore files in favor of Biome for linting. - Introduced biome.json for configuration and updated package.json to reflect new dependencies. - Added OpenAPI specification for Dokploy API and generated CLI commands from it. - Refactored CLI entry point to use Commander instead of Oclif. - Implemented new authentication command and removed deprecated commands. - Updated TypeScript configuration and added build scripts for improved development workflow. - Cleaned up unused files and commands to streamline the codebase.
This commit is contained in:
@@ -1 +0,0 @@
|
||||
/dist
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": [ "prettier"]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
|
||||
node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
|
||||
|
||||
// eslint-disable-next-line n/shebang
|
||||
import {execute} from '@oclif/core'
|
||||
|
||||
await execute({development: true, dir: import.meta.url})
|
||||
@@ -1,3 +0,0 @@
|
||||
@echo off
|
||||
|
||||
node "%~dp0\run" %*
|
||||
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import {execute} from '@oclif/core'
|
||||
|
||||
await execute({dir: import.meta.url})
|
||||
import "../dist/index.js";
|
||||
|
||||
42
biome.json
Normal file
42
biome.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"includes": ["**", "!**/dist", "!node_modules/**", "!src/generated/**"],
|
||||
"maxSize": 2097152
|
||||
},
|
||||
"assist": { "actions": { "source": { "organizeImports": "on" } } },
|
||||
"linter": {
|
||||
"rules": {
|
||||
"complexity": {
|
||||
"noUselessCatch": "off"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedImports": "error",
|
||||
"noUnusedFunctionParameters": "error",
|
||||
"noUnusedVariables": "off"
|
||||
},
|
||||
"style": {
|
||||
"noNonNullAssertion": "off",
|
||||
"noParameterAssign": "error",
|
||||
"useAsConstAssertion": "error",
|
||||
"useDefaultParameterLast": "error",
|
||||
"useSelfClosingElements": "error",
|
||||
"useSingleVarDeclarator": "error",
|
||||
"noUnusedTemplateLiteral": "error",
|
||||
"useNumberNamespace": "error",
|
||||
"noInferrableTypes": "error",
|
||||
"noUselessElse": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off",
|
||||
"noRedeclare": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48976
openapi.json
Normal file
48976
openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
74
package.json
74
package.json
@@ -1,88 +1,54 @@
|
||||
{
|
||||
"name": "@dokploy/cli",
|
||||
"description": "A CLI to manage dokploy server remotely",
|
||||
"version": "v0.2.8",
|
||||
"version": "0.3.0",
|
||||
"author": "Mauricio Siu",
|
||||
"licenses": [{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/Dokploy/cli/blob/master/LICENSE"
|
||||
}],
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/Dokploy/cli/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"bin": {
|
||||
"dokploy": "./bin/run.js"
|
||||
"dokploy": "./dist/index.js"
|
||||
},
|
||||
"bugs": "https://github.com/Dokploy/cli/issues",
|
||||
"dependencies": {
|
||||
"@oclif/core": "^3",
|
||||
"@oclif/plugin-help": "^6",
|
||||
"@oclif/plugin-plugins": "^5",
|
||||
"axios": "^1.7.2",
|
||||
"chalk": "^5.3.0",
|
||||
"cli-table3": "^0.6.5",
|
||||
"inquirer": "^9.2.23",
|
||||
"slugify": "^1.6.6",
|
||||
"superjson": "^2.2.1"
|
||||
"commander": "^13.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@oclif/prettier-config": "^0.2.1",
|
||||
"@oclif/test": "^4",
|
||||
"@types/chai": "^4",
|
||||
"@types/inquirer": "9.0.7",
|
||||
"@types/mocha": "^10",
|
||||
"@biomejs/biome": "2.1.1",
|
||||
"@types/node": "^18",
|
||||
"chai": "^4",
|
||||
"eslint": "^8",
|
||||
"eslint-config-oclif": "^5",
|
||||
"eslint-config-oclif-typescript": "^3",
|
||||
"eslint-config-prettier": "^9",
|
||||
"mocha": "^10",
|
||||
"oclif": "^4",
|
||||
"shx": "^0.3.3",
|
||||
"ts-node": "^10",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"files": [
|
||||
"/bin",
|
||||
"/dist",
|
||||
"/oclif.manifest.json"
|
||||
"/dist"
|
||||
],
|
||||
"homepage": "https://github.com/Dokploy/cli",
|
||||
"keywords": [
|
||||
"oclif"
|
||||
"dokploy",
|
||||
"cli"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"oclif": {
|
||||
"bin": "dokploy",
|
||||
"dirname": "dokploy",
|
||||
"commands": "./dist/commands",
|
||||
"plugins": [
|
||||
"@oclif/plugin-help",
|
||||
"@oclif/plugin-plugins"
|
||||
],
|
||||
"topicSeparator": " ",
|
||||
"topics": {
|
||||
"hello": {
|
||||
"description": "Say hello to the world and others"
|
||||
}
|
||||
}
|
||||
},
|
||||
"repository": "Dokploy/cli",
|
||||
"scripts": {
|
||||
"build": "shx rm -rf dist && tsc -b",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"postpack": "shx rm -f oclif.manifest.json",
|
||||
"posttest": "pnpm run lint",
|
||||
"prepack": "oclif manifest && oclif readme",
|
||||
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
||||
"version": "oclif readme && git add README.md",
|
||||
"publish" :"npm publish"
|
||||
"build": "tsc -b",
|
||||
"generate": "tsx scripts/generate.ts",
|
||||
"prebuild": "pnpm run generate",
|
||||
"dev": "tsx src/index.ts",
|
||||
"lint": "biome check --write .",
|
||||
"publish": "npm publish"
|
||||
},
|
||||
"types": "dist/index.d.ts"
|
||||
}
|
||||
|
||||
5680
pnpm-lock.yaml
generated
5680
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
286
scripts/generate.ts
Normal file
286
scripts/generate.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* Generates CLI commands from the Dokploy OpenAPI spec.
|
||||
*
|
||||
* Usage: npx tsx scripts/generate.ts
|
||||
*
|
||||
* Reads openapi.json from the project root and generates:
|
||||
* - src/generated/commands.ts (all CLI commands)
|
||||
*/
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.resolve(__dirname, "..");
|
||||
const SPEC_PATH = path.join(ROOT, "openapi.json");
|
||||
const OUT_PATH = path.join(ROOT, "src", "generated", "commands.ts");
|
||||
|
||||
interface OpenAPISpec {
|
||||
paths: Record<string, Record<string, OperationObject>>;
|
||||
}
|
||||
|
||||
interface OperationObject {
|
||||
operationId?: string;
|
||||
summary?: string;
|
||||
description?: string;
|
||||
tags?: string[];
|
||||
parameters?: ParameterObject[];
|
||||
requestBody?: {
|
||||
content?: {
|
||||
"application/json"?: {
|
||||
schema?: SchemaObject;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
interface ParameterObject {
|
||||
name: string;
|
||||
in: string;
|
||||
required?: boolean;
|
||||
schema?: SchemaObject;
|
||||
}
|
||||
|
||||
interface SchemaObject {
|
||||
type?: string;
|
||||
properties?: Record<string, SchemaProperty>;
|
||||
required?: string[];
|
||||
anyOf?: SchemaObject[];
|
||||
items?: SchemaObject;
|
||||
enum?: string[];
|
||||
}
|
||||
|
||||
interface SchemaProperty {
|
||||
type?: string;
|
||||
anyOf?: SchemaObject[];
|
||||
enum?: string[];
|
||||
default?: unknown;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface CommandInfo {
|
||||
/** e.g. "application.create" */
|
||||
endpoint: string;
|
||||
/** e.g. "application" */
|
||||
group: string;
|
||||
/** e.g. "create" */
|
||||
action: string;
|
||||
method: "get" | "post";
|
||||
description: string;
|
||||
options: OptionInfo[];
|
||||
}
|
||||
|
||||
interface OptionInfo {
|
||||
name: string;
|
||||
flag: string;
|
||||
description: string;
|
||||
required: boolean;
|
||||
type: "string" | "number" | "boolean";
|
||||
enumValues?: string[];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function resolveType(prop: SchemaProperty): "string" | "number" | "boolean" {
|
||||
const raw = prop.type ?? prop.anyOf?.find((s) => s.type && s.type !== "null")?.type;
|
||||
if (raw === "number" || raw === "integer") return "number";
|
||||
if (raw === "boolean") return "boolean";
|
||||
return "string";
|
||||
}
|
||||
|
||||
function resolveEnum(prop: SchemaProperty): string[] | undefined {
|
||||
if (prop.enum) return prop.enum;
|
||||
const inner = prop.anyOf?.find((s) => s.enum);
|
||||
return inner?.enum;
|
||||
}
|
||||
|
||||
function extractOptionsFromSchema(schema: SchemaObject | undefined): OptionInfo[] {
|
||||
if (!schema?.properties) return [];
|
||||
const required = new Set(schema.required ?? []);
|
||||
return Object.entries(schema.properties).map(([name, prop]) => {
|
||||
const type = resolveType(prop);
|
||||
const enumValues = resolveEnum(prop);
|
||||
let desc = prop.description ?? name;
|
||||
if (enumValues) desc += ` (${enumValues.join(", ")})`;
|
||||
return {
|
||||
name,
|
||||
flag: `--${name} <${type === "boolean" ? "" : "value"}>`.replace(/ <>/g, ""),
|
||||
description: desc,
|
||||
required: required.has(name),
|
||||
type,
|
||||
enumValues,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function extractOptionsFromParams(params: ParameterObject[]): OptionInfo[] {
|
||||
return params.map((p) => {
|
||||
const type = resolveType(p.schema ?? {});
|
||||
const enumValues = resolveEnum(p.schema ?? {});
|
||||
let desc = p.name;
|
||||
if (enumValues) desc += ` (${enumValues.join(", ")})`;
|
||||
return {
|
||||
name: p.name,
|
||||
flag: `--${p.name} <${type === "boolean" ? "" : "value"}>`.replace(/ <>/g, ""),
|
||||
description: desc,
|
||||
required: p.required ?? false,
|
||||
type,
|
||||
enumValues,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function camelToKebab(s: string): string {
|
||||
return s.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Parse spec → CommandInfo[]
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function parseSpec(spec: OpenAPISpec): CommandInfo[] {
|
||||
const commands: CommandInfo[] = [];
|
||||
|
||||
for (const [pathKey, methods] of Object.entries(spec.paths)) {
|
||||
for (const [method, op] of Object.entries(methods)) {
|
||||
const endpoint = pathKey.replace(/^\//, "");
|
||||
const [group, ...rest] = endpoint.split(".");
|
||||
const action = rest.join(".");
|
||||
|
||||
if (!group || !action) continue;
|
||||
|
||||
const bodySchema = op.requestBody?.content?.["application/json"]?.schema;
|
||||
const paramOptions = op.parameters ? extractOptionsFromParams(op.parameters) : [];
|
||||
const bodyOptions = extractOptionsFromSchema(bodySchema);
|
||||
const options = [...paramOptions, ...bodyOptions];
|
||||
|
||||
commands.push({
|
||||
endpoint,
|
||||
group,
|
||||
action,
|
||||
method: method as "get" | "post",
|
||||
description: op.summary ?? op.description ?? `${group} ${action}`,
|
||||
options,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return commands.sort((a, b) => a.endpoint.localeCompare(b.endpoint));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Code generation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function generateOptionLine(opt: OptionInfo): string {
|
||||
const flag = opt.type === "boolean"
|
||||
? `--${opt.name}`
|
||||
: `--${opt.name} <value>`;
|
||||
const escaped = opt.description.replace(/'/g, "\\'");
|
||||
return opt.required
|
||||
? `.requiredOption('${flag}', '${escaped}')`
|
||||
: `.option('${flag}', '${escaped}')`;
|
||||
}
|
||||
|
||||
function generateCoercion(opt: OptionInfo): string {
|
||||
if (opt.type === "number") {
|
||||
return `if (opts["${opt.name}"] != null) opts["${opt.name}"] = Number(opts["${opt.name}"]);`;
|
||||
}
|
||||
if (opt.type === "boolean") {
|
||||
return `if (opts["${opt.name}"] != null) opts["${opt.name}"] = opts["${opt.name}"] === true || opts["${opt.name}"] === "true";`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function generateCommandCode(cmd: CommandInfo, groupVar: string): string {
|
||||
const actionName = camelToKebab(cmd.action);
|
||||
const optionLines = cmd.options.map(generateOptionLine).join("\n\t\t");
|
||||
const coercions = cmd.options
|
||||
.map(generateCoercion)
|
||||
.filter(Boolean)
|
||||
.map((c) => `\t\t\t${c}`)
|
||||
.join("\n");
|
||||
|
||||
const apiCall = cmd.method === "post"
|
||||
? `await apiPost("${cmd.endpoint}", opts)`
|
||||
: `await apiGet("${cmd.endpoint}", opts)`;
|
||||
|
||||
const escapedDesc = cmd.description.replace(/'/g, "\\'");
|
||||
|
||||
return `
|
||||
${groupVar}
|
||||
.command('${actionName}')
|
||||
.description('${escapedDesc}')
|
||||
${optionLines}
|
||||
.option('--json', 'Output raw JSON')
|
||||
.action(async (opts: Record<string, any>) => {
|
||||
const jsonOutput = opts.json; delete opts.json;
|
||||
${coercions}
|
||||
const data = ${apiCall};
|
||||
if (jsonOutput) {
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
} else {
|
||||
printOutput(data);
|
||||
}
|
||||
});`;
|
||||
}
|
||||
|
||||
function generateFile(commands: CommandInfo[]): string {
|
||||
// Group commands by their group name
|
||||
const groups = new Map<string, CommandInfo[]>();
|
||||
for (const cmd of commands) {
|
||||
const existing = groups.get(cmd.group) ?? [];
|
||||
existing.push(cmd);
|
||||
groups.set(cmd.group, existing);
|
||||
}
|
||||
|
||||
const groupBlocks: string[] = [];
|
||||
for (const [group, cmds] of [...groups.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
||||
const varName = `g_${group.replace(/[^a-zA-Z0-9]/g, "_")}`;
|
||||
const kebabGroup = camelToKebab(group);
|
||||
groupBlocks.push(`\tconst ${varName} = program.command('${kebabGroup}').description('${kebabGroup} commands');`);
|
||||
for (const cmd of cmds) {
|
||||
groupBlocks.push(generateCommandCode(cmd, varName));
|
||||
}
|
||||
}
|
||||
|
||||
return `// Auto-generated from openapi.json — do not edit manually.
|
||||
// Run: npx tsx scripts/generate.ts
|
||||
|
||||
import type { Command } from "commander";
|
||||
import chalk from "chalk";
|
||||
import { apiPost, apiGet } from "../client.js";
|
||||
|
||||
function printOutput(data: unknown) {
|
||||
if (data === null || data === undefined) {
|
||||
console.log(chalk.green("OK"));
|
||||
return;
|
||||
}
|
||||
if (typeof data === "string") {
|
||||
console.log(data);
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(data, null, 2));
|
||||
}
|
||||
|
||||
export function registerGeneratedCommands(program: Command) {
|
||||
${groupBlocks.join("\n")}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const spec: OpenAPISpec = JSON.parse(fs.readFileSync(SPEC_PATH, "utf8"));
|
||||
const commands = parseSpec(spec);
|
||||
|
||||
fs.mkdirSync(path.dirname(OUT_PATH), { recursive: true });
|
||||
fs.writeFileSync(OUT_PATH, generateFile(commands));
|
||||
|
||||
console.log(`Generated ${commands.length} commands → ${path.relative(ROOT, OUT_PATH)}`);
|
||||
76
src/client.ts
Normal file
76
src/client.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import axios, { type AxiosInstance } from "axios";
|
||||
import chalk from "chalk";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "config.json");
|
||||
|
||||
export interface AuthConfig {
|
||||
token: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function readAuthConfig(): AuthConfig {
|
||||
const envToken = process.env.DOKPLOY_AUTH_TOKEN;
|
||||
const envUrl = process.env.DOKPLOY_URL;
|
||||
|
||||
if (envToken && envUrl) {
|
||||
return { token: envToken, url: envUrl };
|
||||
}
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
"No configuration found. Please run 'dokploy auth' first or set DOKPLOY_URL and DOKPLOY_AUTH_TOKEN environment variables.",
|
||||
),
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
||||
const { token, url } = config;
|
||||
|
||||
if (!url || !token) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
"Incomplete auth config. Run 'dokploy auth' or set environment variables.",
|
||||
),
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { token, url };
|
||||
}
|
||||
|
||||
export function saveAuthConfig(url: string, token: string): void {
|
||||
fs.writeFileSync(configPath, JSON.stringify({ url, token }, null, 2));
|
||||
}
|
||||
|
||||
export function createClient(): AxiosInstance {
|
||||
const auth = readAuthConfig();
|
||||
return axios.create({
|
||||
baseURL: `${auth.url}/api`,
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function apiPost(endpoint: string, data?: Record<string, unknown>) {
|
||||
const client = createClient();
|
||||
const response = await client.post(`/trpc/${endpoint}`, data ? { json: data } : undefined);
|
||||
return response.data?.result?.data?.json ?? response.data;
|
||||
}
|
||||
|
||||
export async function apiGet(endpoint: string, params?: Record<string, unknown>) {
|
||||
const client = createClient();
|
||||
const query = params
|
||||
? `?input=${encodeURIComponent(JSON.stringify(params))}`
|
||||
: "";
|
||||
const response = await client.get(`/trpc/${endpoint}${query}`);
|
||||
return response.data?.result?.data?.json ?? response.data;
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { type Project, getProjects } from "../../utils/shared.js";
|
||||
import { slugify } from "../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
|
||||
export interface Answers {
|
||||
project: Project;
|
||||
}
|
||||
|
||||
export default class AppCreate extends Command {
|
||||
static description = "Create a new application within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Application name",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Application description",
|
||||
required: false,
|
||||
}),
|
||||
appName: Flags.string({
|
||||
description: "Docker app name",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(AppCreate);
|
||||
let { projectId, environmentId, name, description, appName } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !name || !appName) {
|
||||
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<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the application in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
environmentId = environment.environmentId;
|
||||
}
|
||||
|
||||
if (!name || !appName) {
|
||||
const appDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the application name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Application name is required"),
|
||||
default: name,
|
||||
},
|
||||
{
|
||||
message: "Enter the application description (optional):",
|
||||
name: "appDescription",
|
||||
type: "input",
|
||||
default: description,
|
||||
},
|
||||
]);
|
||||
|
||||
name = appDetails.name;
|
||||
description = appDetails.appDescription;
|
||||
|
||||
const appNamePrompt = await inquirer.prompt([
|
||||
{
|
||||
default: appName || `${slugify(name)}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
appName = appNamePrompt.appName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 application?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("Application creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
appDescription: description,
|
||||
appName,
|
||||
projectId,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error creating application"));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`Application '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating application: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { getProject, getProjects, type Application } from "../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import type { Answers } from "./create.js";
|
||||
|
||||
export default class AppDelete extends Command {
|
||||
static description = "Delete an application from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> app delete",
|
||||
"$ <%= config.bin %> app delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
applicationId: Flags.string({
|
||||
char: 'a',
|
||||
description: 'ID of the application to delete',
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: 'y',
|
||||
description: 'Skip confirmation prompt',
|
||||
default: false,
|
||||
})
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(AppDelete);
|
||||
let { projectId, environmentId, applicationId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !applicationId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to delete the application 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar application del environment
|
||||
if (!applicationId) {
|
||||
if (!selectedEnvironment?.applications || selectedEnvironment.applications.length === 0) {
|
||||
this.error(chalk.yellow("No applications found in this environment."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.applications.map((app: Application) => ({
|
||||
name: app.name,
|
||||
value: app.applicationId,
|
||||
})),
|
||||
message: "Select the application to delete:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
applicationId = appAnswers.selectedApp;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 application?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Application deletion cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const deleteResponse = await axios.post(
|
||||
`${auth.url}/api/trpc/application.delete`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!deleteResponse.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting application"));
|
||||
}
|
||||
|
||||
this.log(chalk.green("Application deleted successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Failed to delete application: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Application } from "../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "./create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class AppDeploy extends Command {
|
||||
static description = "Deploy an application to a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> app deploy",
|
||||
"$ <%= config.bin %> app deploy --applicationId myAppId",
|
||||
"$ DOKPLOY_URL=xxx DOKPLOY_AUTH_TOKEN=xxx <%= config.bin %> app deploy --applicationId myAppId"
|
||||
];
|
||||
|
||||
static flags = {
|
||||
applicationId: Flags.string({
|
||||
char: 'a',
|
||||
description: 'ID of the application to deploy',
|
||||
required: false,
|
||||
}),
|
||||
projectId: Flags.string({
|
||||
char: 'p',
|
||||
description: 'ID of the project',
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: 'e',
|
||||
description: 'ID of the environment',
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: 'y',
|
||||
description: 'Skip confirmation prompt',
|
||||
default: false,
|
||||
})
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(AppDeploy);
|
||||
let { projectId, applicationId, environmentId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !applicationId || !environmentId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the application 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar application del environment
|
||||
if (!applicationId) {
|
||||
if (!selectedEnvironment?.applications || selectedEnvironment.applications.length === 0) {
|
||||
this.error(chalk.yellow("No applications found in this environment."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.applications.map((app: Application) => ({
|
||||
name: app.name,
|
||||
value: app.applicationId,
|
||||
})),
|
||||
message: "Select the application to deploy:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
applicationId = appAnswers.selectedApp;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this application?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Application deployment cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.deploy`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying application"));
|
||||
}
|
||||
this.log(chalk.green("Application deploy successful."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deploying application: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { getProject, getProjects, type Application } from "../../utils/shared.js";
|
||||
import type { Answers } from "./create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class AppStop extends Command {
|
||||
static description = "Stop an application from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app stop"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: 'p',
|
||||
description: 'ID of the project',
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: 'e',
|
||||
description: 'ID of the environment',
|
||||
required: false,
|
||||
}),
|
||||
applicationId: Flags.string({
|
||||
char: 'a',
|
||||
description: 'ID of the application to stop',
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: 'y',
|
||||
description: 'Skip confirmation prompt',
|
||||
default: false,
|
||||
})
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(AppStop);
|
||||
let { projectId, environmentId, applicationId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !applicationId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the application 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar application del environment
|
||||
if (!applicationId) {
|
||||
if (!selectedEnvironment?.applications || selectedEnvironment.applications.length === 0) {
|
||||
this.error(chalk.yellow("No applications found in this environment."));
|
||||
}
|
||||
|
||||
const appAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.applications.map((app: Application) => ({
|
||||
name: app.name,
|
||||
value: app.applicationId,
|
||||
})),
|
||||
message: "Select the application to stop:",
|
||||
name: "selectedApp",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
applicationId = appAnswers.selectedApp;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this application?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Application stop cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.stop`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping application"));
|
||||
}
|
||||
this.log(chalk.green("Application stop successful."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error stopping application: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/commands/auth.ts
Normal file
32
src/commands/auth.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import type { Command } from "commander";
|
||||
import chalk from "chalk";
|
||||
import axios from "axios";
|
||||
import { saveAuthConfig } from "../client.js";
|
||||
|
||||
export function registerAuthCommand(program: Command) {
|
||||
program
|
||||
.command("auth")
|
||||
.description("Authenticate with your Dokploy server")
|
||||
.requiredOption("-u, --url <url>", "Server URL (e.g., https://panel.dokploy.com)")
|
||||
.requiredOption("-t, --token <token>", "API key from your Dokploy dashboard")
|
||||
.action(async (opts: { url: string; token: string }) => {
|
||||
const url = opts.url.replace(/\/+$/, "");
|
||||
|
||||
console.log(chalk.blue("Validating credentials..."));
|
||||
|
||||
try {
|
||||
await axios.get(`${url}/api/trpc/user.get`, {
|
||||
headers: {
|
||||
"x-api-key": opts.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
saveAuthConfig(url, opts.token);
|
||||
console.log(chalk.green("Authenticated successfully."));
|
||||
} catch (error: any) {
|
||||
console.error(chalk.red(`Authentication failed: ${error.message}`));
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer, { type Answers, type QuestionCollection } from "inquirer";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
export default class Authenticate extends Command {
|
||||
static description = "Authenticate the user by saving server URL and token";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> <%= command.id %> --url=https://panel.dokploy.com --token=MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY",
|
||||
"$ <%= config.bin %> <%= command.id %> -u https://panel.dokploy.com -t MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
token: Flags.string({
|
||||
char: "t",
|
||||
description: "Authentication token",
|
||||
}),
|
||||
url: Flags.string({
|
||||
char: "u",
|
||||
description: "Server URL",
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
console.log(
|
||||
chalk.blue.bold("\n Welcome to Dokploy CLI Authentication \n"),
|
||||
);
|
||||
|
||||
const { flags } = await this.parse(Authenticate);
|
||||
|
||||
let answers: Answers = {};
|
||||
|
||||
const questions: QuestionCollection[] = [];
|
||||
|
||||
let config: { token?: string; url?: string } = {};
|
||||
if (fs.existsSync(configPath)) {
|
||||
const configFileContent = fs.readFileSync(configPath, "utf8");
|
||||
config = JSON.parse(configFileContent);
|
||||
}
|
||||
|
||||
if (!flags.url) {
|
||||
questions.push({
|
||||
default: config.url,
|
||||
message: chalk.green(
|
||||
"Enter your server URL (e.g., https://panel.dokploy.com): ",
|
||||
),
|
||||
name: "url",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Server URL is required"),
|
||||
});
|
||||
}
|
||||
|
||||
if (!flags.token) {
|
||||
questions.push({
|
||||
default: config.token,
|
||||
message: chalk.green(
|
||||
"Enter your authentication token (e.g., MRTHGZDGMRZWM43EMZSHGZTTMRTHGZDGONSGMZDTMY=): ",
|
||||
),
|
||||
name: "token",
|
||||
type: "input",
|
||||
validate: (input) =>
|
||||
input ? true : "Authentication token is required",
|
||||
});
|
||||
}
|
||||
|
||||
if (questions.length > 0) {
|
||||
answers = await inquirer.prompt(questions);
|
||||
}
|
||||
|
||||
const url = flags.url || answers.url;
|
||||
const token = flags.token || answers.token;
|
||||
|
||||
config.token = token;
|
||||
config.url = url;
|
||||
|
||||
try {
|
||||
console.log(`\n${chalk.blue("Validating server...")}`);
|
||||
|
||||
await axios.get(
|
||||
`${url}/api/trpc/user.get`,
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
this.log(chalk.green("Authentication details saved successfully."));
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-expect-error - Type
|
||||
chalk.red(`Failed to save authentication details: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects, type Database } from "../../../utils/shared.js";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMariadbCreate extends Command {
|
||||
static description = "Create a new MariaDB database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mariadb create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Database name",
|
||||
required: false,
|
||||
}),
|
||||
databaseName: Flags.string({
|
||||
description: "MariaDB database name",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Database description",
|
||||
required: false,
|
||||
}),
|
||||
databaseRootPassword: Flags.string({
|
||||
description: "Database root password",
|
||||
required: false,
|
||||
}),
|
||||
databasePassword: Flags.string({
|
||||
description: "Database password",
|
||||
required: false,
|
||||
}),
|
||||
databaseUser: Flags.string({
|
||||
description: "Database user",
|
||||
default: "mariadb",
|
||||
}),
|
||||
dockerImage: Flags.string({
|
||||
description: "Docker image",
|
||||
default: "mariadb:11",
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
appName: Flags.string({
|
||||
description: "App name",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMariadbCreate);
|
||||
let {
|
||||
projectId,
|
||||
environmentId,
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databaseRootPassword,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName
|
||||
} = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !name || !databaseName || !appName) {
|
||||
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<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the MariaDB instance in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
environmentId = environment.environmentId;
|
||||
}
|
||||
|
||||
if (!name || !databaseName || !appName) {
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: name,
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: databaseName,
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
default: description,
|
||||
},
|
||||
{
|
||||
message: "Database Root Password (optional):",
|
||||
name: "databaseRootPassword",
|
||||
type: "password",
|
||||
default: databaseRootPassword,
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
default: databasePassword,
|
||||
},
|
||||
{
|
||||
default: dockerImage || "mariadb:11",
|
||||
message: "Docker Image (default: mariadb:11):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: databaseUser || "mariadb",
|
||||
message: "Database User: (default: mariadb):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
name = dbDetails.name;
|
||||
databaseName = dbDetails.databaseName;
|
||||
description = dbDetails.description;
|
||||
databaseRootPassword = dbDetails.databaseRootPassword;
|
||||
databasePassword = dbDetails.databasePassword;
|
||||
dockerImage = dbDetails.dockerImage;
|
||||
databaseUser = dbDetails.databaseUser;
|
||||
|
||||
const appNamePrompt = await inquirer.prompt([
|
||||
{
|
||||
default: appName || `${slugify(name)}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
appName = appNamePrompt.appName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 MariaDB instance?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("MariaDB creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databaseRootPassword,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName,
|
||||
projectId,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating MariaDB instance", response.data.result.data.json));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`MariaDB instance '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating MariaDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
|
||||
export default class DatabaseMariadbDelete extends Command {
|
||||
static description = "Delete a MariaDB database from a project.";
|
||||
static examples = [
|
||||
"$ <%= config.bin %> mariadb delete",
|
||||
"$ <%= config.bin %> mariadb delete -p <projectId>",
|
||||
];
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mariadbId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MariaDB instance to delete",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMariadbDelete);
|
||||
let { projectId, environmentId, mariadbId } = flags;
|
||||
|
||||
if (!projectId || !environmentId || !mariadbId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the MariaDB instance from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedProject = projects.find(p => p.projectId === answers.selectedProject);
|
||||
projectId = answers.selectedProject;
|
||||
} 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MariaDB del environment
|
||||
if (!mariadbId) {
|
||||
if (!selectedEnvironment?.mariadb || selectedEnvironment.mariadb.length === 0) {
|
||||
this.error(chalk.yellow("No MariaDB instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mariadb.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mariadbId,
|
||||
})),
|
||||
message: "Select the MariaDB instance to delete:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mariadbId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to delete this MariaDB instance?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("MariaDB deletion cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.remove`,
|
||||
{
|
||||
json: {
|
||||
mariadbId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting MariaDB instance"));
|
||||
}
|
||||
this.log(chalk.green("MariaDB instance deleted successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deleting MariaDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseMariadbDeploy extends Command {
|
||||
static description = "Deploy an mariadb to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mariadbId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MariaDB instance to deploy",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMariadbDeploy);
|
||||
let { projectId, environmentId, mariadbId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mariadbId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the MariaDB in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MariaDB del environment
|
||||
if (!mariadbId) {
|
||||
if (!selectedEnvironment?.mariadb || selectedEnvironment.mariadb.length === 0) {
|
||||
this.error(chalk.yellow("No MariaDB instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mariadb.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mariadbId,
|
||||
})),
|
||||
message: "Select the MariaDB instance to deploy:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mariadbId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this MariaDB instance?",
|
||||
name: "confirmDeploy",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDeploy) {
|
||||
this.error(chalk.yellow("MariaDB deployment cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.deploy`,
|
||||
{
|
||||
json: {
|
||||
mariadbId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying MariaDB instance"));
|
||||
}
|
||||
this.log(chalk.green("MariaDB instance deployed successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deploying MariaDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMariadbStop extends Command {
|
||||
static description = "Stop an mariadb from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mariadb stop"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mariadbId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MariaDB instance to stop",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMariadbStop);
|
||||
let { projectId, environmentId, mariadbId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mariadbId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the MariaDB instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MariaDB del environment
|
||||
if (!mariadbId) {
|
||||
if (!selectedEnvironment?.mariadb || selectedEnvironment.mariadb.length === 0) {
|
||||
this.error(chalk.yellow("No MariaDB instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mariadb.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mariadbId,
|
||||
})),
|
||||
message: "Select the MariaDB instance to stop:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mariadbId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this MariaDB instance?",
|
||||
name: "confirmStop",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmStop) {
|
||||
this.error(chalk.yellow("MariaDB stop cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mariadb.stop`,
|
||||
{
|
||||
json: {
|
||||
mariadbId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping MariaDB instance"));
|
||||
}
|
||||
this.log(chalk.green("MariaDB instance stopped successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error stopping MariaDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects, type Database } from "../../../utils/shared.js";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMongoCreate extends Command {
|
||||
static description = "Create a new MongoDB database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mongo create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Database name",
|
||||
required: false,
|
||||
}),
|
||||
databaseName: Flags.string({
|
||||
description: "MongoDB database name",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Database description",
|
||||
required: false,
|
||||
}),
|
||||
databasePassword: Flags.string({
|
||||
description: "Database password",
|
||||
required: false,
|
||||
}),
|
||||
databaseUser: Flags.string({
|
||||
description: "Database user",
|
||||
default: "mongo",
|
||||
}),
|
||||
dockerImage: Flags.string({
|
||||
description: "Docker image",
|
||||
default: "mongo:6",
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
appName: Flags.string({
|
||||
description: "App name",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMongoCreate);
|
||||
let {
|
||||
projectId,
|
||||
environmentId,
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName
|
||||
} = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !name || !databaseName || !appName || !databasePassword) {
|
||||
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<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the MongoDB instance in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
environmentId = environment.environmentId;
|
||||
}
|
||||
|
||||
if (!name || !databaseName || !appName || !databasePassword) {
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: name,
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: databaseName,
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
default: description,
|
||||
},
|
||||
{
|
||||
message: "Database password (optional):",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
default: databasePassword,
|
||||
},
|
||||
{
|
||||
default: dockerImage || "mongo:6",
|
||||
message: "Docker Image (default: mongo:6):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: databaseUser || "mongo",
|
||||
message: "Database User: (default: mongo):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
name = dbDetails.name;
|
||||
databaseName = dbDetails.databaseName;
|
||||
description = dbDetails.description;
|
||||
databasePassword = dbDetails.databasePassword;
|
||||
dockerImage = dbDetails.dockerImage;
|
||||
databaseUser = dbDetails.databaseUser;
|
||||
|
||||
const appNamePrompt = await inquirer.prompt([
|
||||
{
|
||||
default: appName || `${slugify(name)}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
appName = appNamePrompt.appName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 MongoDB instance?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("MongoDB creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName,
|
||||
projectId,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating MongoDB instance"));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`MongoDB instance '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating MongoDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabaseMongoDelete extends Command {
|
||||
static description = "Delete a MongoDB database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> mongo delete",
|
||||
"$ <%= config.bin %> mongo delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mongoId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MongoDB instance to delete",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMongoDelete);
|
||||
let { projectId, environmentId, mongoId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mongoId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the MongoDB instance from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedProject = projects.find(p => p.projectId === answers.selectedProject);
|
||||
projectId = answers.selectedProject;
|
||||
} 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MongoDB del environment
|
||||
if (!mongoId) {
|
||||
if (!selectedEnvironment?.mongo || selectedEnvironment.mongo.length === 0) {
|
||||
this.error(chalk.yellow("No MongoDB instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mongo.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mongoId,
|
||||
})),
|
||||
message: "Select the MongoDB instance to delete:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mongoId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 MongoDB instance?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("MongoDB deletion cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.remove`,
|
||||
{
|
||||
json: {
|
||||
mongoId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting MongoDB instance"));
|
||||
}
|
||||
this.log(chalk.green("MongoDB instance deleted successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deleting MongoDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseMongoDeploy extends Command {
|
||||
static description = "Deploy an mongo to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mongoId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MongoDB instance to deploy",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMongoDeploy);
|
||||
let { projectId, environmentId, mongoId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mongoId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the MongoDB instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MongoDB del environment
|
||||
if (!mongoId) {
|
||||
if (!selectedEnvironment?.mongo || selectedEnvironment.mongo.length === 0) {
|
||||
this.error(chalk.yellow("No MongoDB instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mongo.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mongoId,
|
||||
})),
|
||||
message: "Select the MongoDB instance to deploy:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mongoId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this MongoDB instance?",
|
||||
name: "confirmDeploy",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDeploy) {
|
||||
this.error(chalk.yellow("MongoDB deployment cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.deploy`,
|
||||
{
|
||||
json: {
|
||||
mongoId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying MongoDB instance"));
|
||||
}
|
||||
this.log(chalk.green("MongoDB instance deployed successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deploying MongoDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMongoStop extends Command {
|
||||
static description = "Stop an mongo from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mongo stop"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mongoId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MongoDB instance to stop",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMongoStop);
|
||||
let { projectId, environmentId, mongoId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mongoId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the MongoDB instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MongoDB del environment
|
||||
if (!mongoId) {
|
||||
if (!selectedEnvironment?.mongo || selectedEnvironment.mongo.length === 0) {
|
||||
this.error(chalk.yellow("No MongoDB instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mongo.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mongoId,
|
||||
})),
|
||||
message: "Select the MongoDB instance to stop:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mongoId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this MongoDB instance?",
|
||||
name: "confirmStop",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmStop) {
|
||||
this.error(chalk.yellow("MongoDB stop cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mongo.stop`,
|
||||
{
|
||||
json: {
|
||||
mongoId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping MongoDB instance"));
|
||||
}
|
||||
this.log(chalk.green("MongoDB instance stopped successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error stopping MongoDB instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects, type Database } from "../../../utils/shared.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMysqlCreate extends Command {
|
||||
static description = "Create a new MySQL database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mysql create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Database name",
|
||||
required: false,
|
||||
}),
|
||||
databaseName: Flags.string({
|
||||
description: "MySQL database name",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Database description",
|
||||
required: false,
|
||||
}),
|
||||
databaseRootPassword: Flags.string({
|
||||
description: "Database root password",
|
||||
required: false,
|
||||
}),
|
||||
databasePassword: Flags.string({
|
||||
description: "Database password",
|
||||
required: false,
|
||||
}),
|
||||
databaseUser: Flags.string({
|
||||
description: "Database user",
|
||||
default: "mysql",
|
||||
}),
|
||||
dockerImage: Flags.string({
|
||||
description: "Docker image",
|
||||
default: "mysql:8",
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
appName: Flags.string({
|
||||
description: "App name",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMysqlCreate);
|
||||
let {
|
||||
projectId,
|
||||
environmentId,
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databaseRootPassword,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName
|
||||
} = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !name || !databaseName || !appName || !databasePassword || !databaseRootPassword) {
|
||||
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<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the MySQL instance in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
environmentId = environment.environmentId;
|
||||
}
|
||||
|
||||
if (!name || !databaseName || !appName || !databasePassword || !databaseRootPassword) {
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: name,
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: databaseName,
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
default: description,
|
||||
},
|
||||
{
|
||||
message: "Database Root Password:",
|
||||
name: "databaseRootPassword",
|
||||
type: "password",
|
||||
default: databaseRootPassword,
|
||||
},
|
||||
{
|
||||
message: "Database password:",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
default: databasePassword,
|
||||
},
|
||||
{
|
||||
default: dockerImage || "mysql:8",
|
||||
message: "Docker Image (default: mysql:8):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: databaseUser || "mysql",
|
||||
message: "Database User: (default: mysql):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
name = dbDetails.name;
|
||||
databaseName = dbDetails.databaseName;
|
||||
description = dbDetails.description;
|
||||
databaseRootPassword = dbDetails.databaseRootPassword;
|
||||
databasePassword = dbDetails.databasePassword;
|
||||
dockerImage = dbDetails.dockerImage;
|
||||
databaseUser = dbDetails.databaseUser;
|
||||
|
||||
const appNamePrompt = await inquirer.prompt([
|
||||
{
|
||||
default: appName || `${slugify(name)}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
appName = appNamePrompt.appName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 MySQL instance?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("MySQL creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databaseRootPassword,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName,
|
||||
projectId,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating MySQL instance", response.data.result.data.json));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`MySQL instance '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating MySQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabaseMysqlDelete extends Command {
|
||||
static description = "Delete a MySQL database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> mysql delete",
|
||||
"$ <%= config.bin %> mysql delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mysqlId: Flags.string({
|
||||
char: "i",
|
||||
description: "ID of the MySQL database",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMysqlDelete);
|
||||
let { projectId, environmentId, mysqlId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mysqlId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the MySQL instance from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedProject = projects.find(p => p.projectId === answers.selectedProject);
|
||||
projectId = answers.selectedProject;
|
||||
} 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MySQL del environment
|
||||
if (!mysqlId) {
|
||||
if (!selectedEnvironment?.mysql || selectedEnvironment.mysql.length === 0) {
|
||||
this.error(chalk.yellow("No MySQL instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mysql.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mysqlId,
|
||||
})),
|
||||
message: "Select the MySQL instance to delete:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mysqlId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 MySQL instance?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("MySQL deletion cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.remove`,
|
||||
{
|
||||
json: {
|
||||
mysqlId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting MySQL instance"));
|
||||
}
|
||||
this.log(chalk.green("MySQL instance deleted successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deleting MySQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseMysqlDeploy extends Command {
|
||||
static description = "Deploy an mysql to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> app deploy"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mysqlId: Flags.string({
|
||||
char: "m",
|
||||
description: "ID of the MySQL instance to deploy",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMysqlDeploy);
|
||||
let { projectId, environmentId, mysqlId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mysqlId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the MySQL instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MySQL del environment
|
||||
if (!mysqlId) {
|
||||
if (!selectedEnvironment?.mysql || selectedEnvironment.mysql.length === 0) {
|
||||
this.error(chalk.yellow("No MySQL instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mysql.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mysqlId,
|
||||
})),
|
||||
message: "Select the MySQL instance to deploy:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mysqlId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this MySQL instance?",
|
||||
name: "confirmDeploy",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDeploy) {
|
||||
this.error(chalk.yellow("MySQL deployment cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.deploy`,
|
||||
{
|
||||
json: {
|
||||
mysqlId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying MySQL instance"));
|
||||
}
|
||||
this.log(chalk.green("MySQL instance deployed successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deploying MySQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import axios from "axios";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseMysqlStop extends Command {
|
||||
static description = "Stop an mysql from a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> mysql stop"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
mysqlId: Flags.string({
|
||||
char: "i",
|
||||
description: "ID of the MySQL database",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseMysqlStop);
|
||||
let { projectId, environmentId, mysqlId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !mysqlId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the MySQL instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar MySQL del environment
|
||||
if (!mysqlId) {
|
||||
if (!selectedEnvironment?.mysql || selectedEnvironment.mysql.length === 0) {
|
||||
this.error(chalk.yellow("No MySQL instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.mysql.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.mysqlId,
|
||||
})),
|
||||
message: "Select the MySQL instance to stop:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
mysqlId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this MySQL instance?",
|
||||
name: "confirmStop",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmStop) {
|
||||
this.error(chalk.yellow("MySQL stop cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/mysql.stop`,
|
||||
{
|
||||
json: {
|
||||
mysqlId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping MySQL instance"));
|
||||
}
|
||||
this.log(chalk.green("MySQL instance stopped successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error stopping MySQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,237 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects, type Database } from "../../../utils/shared.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
export default class DatabasePostgresCreate extends Command {
|
||||
static description = "Create a new PostgreSQL database within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> postgres create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Database name",
|
||||
required: false,
|
||||
}),
|
||||
databaseName: Flags.string({
|
||||
description: "PostgreSQL database name",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Database description",
|
||||
required: false,
|
||||
}),
|
||||
databasePassword: Flags.string({
|
||||
description: "Database password",
|
||||
required: false,
|
||||
}),
|
||||
databaseUser: Flags.string({
|
||||
description: "Database user",
|
||||
default: "postgres",
|
||||
}),
|
||||
dockerImage: Flags.string({
|
||||
description: "Docker image",
|
||||
default: "postgres:15",
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
appName: Flags.string({
|
||||
description: "App name",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabasePostgresCreate);
|
||||
let {
|
||||
projectId,
|
||||
environmentId,
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName
|
||||
} = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !name || !databaseName || !appName || !databasePassword) {
|
||||
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<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the PostgreSQL instance in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
environmentId = environment.environmentId;
|
||||
}
|
||||
|
||||
if (!name || !databaseName || !appName || !databasePassword) {
|
||||
const dbDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: name,
|
||||
},
|
||||
{
|
||||
message: "Database name:",
|
||||
name: "databaseName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Database name is required"),
|
||||
default: databaseName,
|
||||
},
|
||||
{
|
||||
message: "Enter the database description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
default: description,
|
||||
},
|
||||
{
|
||||
message: "Database password:",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
default: databasePassword,
|
||||
},
|
||||
{
|
||||
default: dockerImage || "postgres:15",
|
||||
message: "Docker Image (default: postgres:15):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
{
|
||||
default: databaseUser || "postgres",
|
||||
message: "Database User: (default: postgres):",
|
||||
name: "databaseUser",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
name = dbDetails.name;
|
||||
databaseName = dbDetails.databaseName;
|
||||
description = dbDetails.description;
|
||||
databasePassword = dbDetails.databasePassword;
|
||||
dockerImage = dbDetails.dockerImage;
|
||||
databaseUser = dbDetails.databaseUser;
|
||||
|
||||
const appNamePrompt = await inquirer.prompt([
|
||||
{
|
||||
default: appName || `${slugify(name)}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
appName = appNamePrompt.appName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 PostgreSQL instance?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("PostgreSQL creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
databaseName,
|
||||
description,
|
||||
databasePassword,
|
||||
databaseUser,
|
||||
dockerImage,
|
||||
appName,
|
||||
projectId,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating PostgreSQL instance", response.data.result.data.json));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`PostgreSQL instance '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating PostgreSQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
|
||||
export default class DatabasePostgresDelete extends Command {
|
||||
static description = "Delete a PostgreSQL database from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> postgres delete",
|
||||
"$ <%= config.bin %> postgres delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
postgresId: Flags.string({
|
||||
char: "d",
|
||||
description: "ID of the PostgreSQL database",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabasePostgresDelete);
|
||||
let { projectId, environmentId, postgresId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !postgresId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the PostgreSQL instance from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedProject = projects.find(p => p.projectId === answers.selectedProject);
|
||||
projectId = answers.selectedProject;
|
||||
} 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar PostgreSQL del environment
|
||||
if (!postgresId) {
|
||||
if (!selectedEnvironment?.postgres || selectedEnvironment.postgres.length === 0) {
|
||||
this.error(chalk.yellow("No PostgreSQL instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.postgres.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.postgresId,
|
||||
})),
|
||||
message: "Select the PostgreSQL instance to delete:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
postgresId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 PostgreSQL instance?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("PostgreSQL deletion cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.remove`,
|
||||
{
|
||||
json: {
|
||||
postgresId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting PostgreSQL instance"));
|
||||
}
|
||||
this.log(chalk.green("PostgreSQL instance deleted successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deleting PostgreSQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabasePostgresDeploy extends Command {
|
||||
static description = "Deploy a PostgreSQL instance to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> postgres deploy"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
postgresId: Flags.string({
|
||||
char: "d",
|
||||
description: "ID of the PostgreSQL instance to deploy",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabasePostgresDeploy);
|
||||
let { projectId, environmentId, postgresId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !postgresId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the PostgreSQL instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar PostgreSQL del environment
|
||||
if (!postgresId) {
|
||||
if (!selectedEnvironment?.postgres || selectedEnvironment.postgres.length === 0) {
|
||||
this.error(chalk.yellow("No PostgreSQL instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.postgres.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.postgresId,
|
||||
})),
|
||||
message: "Select the PostgreSQL instance to deploy:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
postgresId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this PostgreSQL instance?",
|
||||
name: "confirmDeploy",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDeploy) {
|
||||
this.error(chalk.yellow("PostgreSQL deployment cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.deploy`,
|
||||
{
|
||||
json: {
|
||||
postgresId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying PostgreSQL instance"));
|
||||
}
|
||||
this.log(chalk.green("PostgreSQL instance deployed successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deploying PostgreSQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabasePostgresStop extends Command {
|
||||
static description = "Stop a PostgreSQL instance in a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> postgres stop"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
postgresId: Flags.string({
|
||||
char: "d",
|
||||
description: "ID of the PostgreSQL instance to stop",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabasePostgresStop);
|
||||
let { projectId, environmentId, postgresId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !postgresId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the PostgreSQL instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar PostgreSQL del environment
|
||||
if (!postgresId) {
|
||||
if (!selectedEnvironment?.postgres || selectedEnvironment.postgres.length === 0) {
|
||||
this.error(chalk.yellow("No PostgreSQL instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.postgres.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.postgresId,
|
||||
})),
|
||||
message: "Select the PostgreSQL instance to stop:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
postgresId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this PostgreSQL instance?",
|
||||
name: "confirmStop",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmStop) {
|
||||
this.error(chalk.yellow("PostgreSQL stop cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/postgres.stop`,
|
||||
{
|
||||
json: {
|
||||
postgresId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping PostgreSQL instance"));
|
||||
}
|
||||
this.log(chalk.green("PostgreSQL instance stopped successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error stopping PostgreSQL instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { slugify } from "../../../utils/slug.js";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import { getProjects, type Database } from "../../../utils/shared.js";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
|
||||
export default class DatabaseRedisCreate extends Command {
|
||||
static description = "Create a new Redis instance within a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> redis create"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Instance name",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Instance description",
|
||||
required: false,
|
||||
}),
|
||||
databasePassword: Flags.string({
|
||||
description: "Redis password",
|
||||
required: false,
|
||||
}),
|
||||
dockerImage: Flags.string({
|
||||
description: "Docker image",
|
||||
default: "redis:7",
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
appName: Flags.string({
|
||||
description: "App name",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseRedisCreate);
|
||||
let {
|
||||
projectId,
|
||||
name,
|
||||
description,
|
||||
databasePassword,
|
||||
dockerImage,
|
||||
appName
|
||||
} = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !name || !appName || !databasePassword) {
|
||||
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<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to create the Redis instance in:",
|
||||
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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
environmentId = environment.environmentId;
|
||||
}
|
||||
|
||||
if (!name || !appName || !databasePassword) {
|
||||
const redisDetails = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Instance name is required"),
|
||||
default: name,
|
||||
},
|
||||
{
|
||||
message: "Enter the instance description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
default: description,
|
||||
},
|
||||
{
|
||||
message: "Redis password:",
|
||||
name: "databasePassword",
|
||||
type: "password",
|
||||
default: databasePassword,
|
||||
},
|
||||
{
|
||||
default: dockerImage || "redis:7",
|
||||
message: "Docker Image (default: redis:7):",
|
||||
name: "dockerImage",
|
||||
type: "input",
|
||||
},
|
||||
]);
|
||||
|
||||
name = redisDetails.name;
|
||||
description = redisDetails.description;
|
||||
databasePassword = redisDetails.databasePassword;
|
||||
dockerImage = redisDetails.dockerImage;
|
||||
|
||||
const appNamePrompt = await inquirer.prompt([
|
||||
{
|
||||
default: appName || `${slugify(name)}`,
|
||||
message: "Enter the App name:",
|
||||
name: "appName",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "App name is required"),
|
||||
},
|
||||
]);
|
||||
|
||||
appName = appNamePrompt.appName;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Redis instance?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("Redis creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
description,
|
||||
databasePassword,
|
||||
dockerImage,
|
||||
appName,
|
||||
projectId,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating Redis instance", response.data.result.data.json));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`Redis instance '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating Redis instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseRedisDelete extends Command {
|
||||
static description = "Delete a Redis instance from a project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> redis delete",
|
||||
"$ <%= config.bin %> redis delete -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
redisId: Flags.string({
|
||||
char: "r",
|
||||
description: "ID of the Redis instance to delete",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseRedisDelete);
|
||||
let { projectId, environmentId, redisId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !redisId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to delete the Redis instance from:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedProject = projects.find(p => p.projectId === answers.selectedProject);
|
||||
projectId = answers.selectedProject;
|
||||
} 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar Redis del environment
|
||||
if (!redisId) {
|
||||
if (!selectedEnvironment?.redis || selectedEnvironment.redis.length === 0) {
|
||||
this.error(chalk.yellow("No Redis instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.redis.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.redisId,
|
||||
})),
|
||||
message: "Select the Redis instance to delete:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
redisId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Redis instance?",
|
||||
name: "confirmDelete",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDelete) {
|
||||
this.error(chalk.yellow("Redis deletion cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.remove`,
|
||||
{
|
||||
json: {
|
||||
redisId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error deleting Redis instance"));
|
||||
}
|
||||
this.log(chalk.green("Redis instance deleted successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deleting Redis instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseRedisDeploy extends Command {
|
||||
static description = "Deploy a Redis instance to a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> redis deploy"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
redisId: Flags.string({
|
||||
char: "r",
|
||||
description: "ID of the Redis instance to deploy",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseRedisDeploy);
|
||||
let { projectId, environmentId, redisId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !redisId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to deploy the Redis instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar Redis del environment
|
||||
if (!redisId) {
|
||||
if (!selectedEnvironment?.redis || selectedEnvironment.redis.length === 0) {
|
||||
this.error(chalk.yellow("No Redis instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.redis.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.redisId,
|
||||
})),
|
||||
message: "Select the Redis instance to deploy:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
redisId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to deploy this Redis instance?",
|
||||
name: "confirmDeploy",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmDeploy) {
|
||||
this.error(chalk.yellow("Redis deployment cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.deploy`,
|
||||
{
|
||||
json: {
|
||||
redisId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error deploying Redis instance"));
|
||||
}
|
||||
this.log(chalk.green("Redis instance deployed successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error deploying Redis instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import { readAuthConfig } from "../../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import { getProject, getProjects, type Database } from "../../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import type { Answers } from "../../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class DatabaseRedisStop extends Command {
|
||||
static description = "Stop a Redis instance in a project.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> redis stop"];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
environmentId: Flags.string({
|
||||
char: "e",
|
||||
description: "ID of the environment",
|
||||
required: false,
|
||||
}),
|
||||
redisId: Flags.string({
|
||||
char: "r",
|
||||
description: "ID of the Redis instance to stop",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(DatabaseRedisStop);
|
||||
let { projectId, environmentId, redisId } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!projectId || !environmentId || !redisId) {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
let selectedProject;
|
||||
let selectedEnvironment;
|
||||
|
||||
// 1. Seleccionar proyecto
|
||||
if (!projectId) {
|
||||
const { project } = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select a project to stop the Redis instance 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:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
selectedEnvironment = environment;
|
||||
environmentId = environment.environmentId;
|
||||
} else {
|
||||
selectedEnvironment = selectedProject?.environments?.find(e => e.environmentId === environmentId);
|
||||
}
|
||||
|
||||
// 3. Seleccionar Redis del environment
|
||||
if (!redisId) {
|
||||
if (!selectedEnvironment?.redis || selectedEnvironment.redis.length === 0) {
|
||||
this.error(chalk.yellow("No Redis instances found in this environment."));
|
||||
}
|
||||
|
||||
const dbAnswers = await inquirer.prompt([
|
||||
{
|
||||
choices: selectedEnvironment.redis.map((db: Database) => ({
|
||||
name: db.name,
|
||||
value: db.redisId,
|
||||
})),
|
||||
message: "Select the Redis instance to stop:",
|
||||
name: "selectedDb",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
redisId = dbAnswers.selectedDb;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar si no se especifica --skipConfirm
|
||||
if (!flags.skipConfirm) {
|
||||
const confirmAnswers = await inquirer.prompt([
|
||||
{
|
||||
default: false,
|
||||
message: "Are you sure you want to stop this Redis instance?",
|
||||
name: "confirmStop",
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirmAnswers.confirmStop) {
|
||||
this.error(chalk.yellow("Redis stop cancelled."));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/redis.stop`,
|
||||
{
|
||||
json: {
|
||||
redisId,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping Redis instance"));
|
||||
}
|
||||
this.log(chalk.green("Redis instance stopped successfully."));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error stopping Redis instance: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/commands/env/pull.ts
vendored
94
src/commands/env/pull.ts
vendored
@@ -1,94 +0,0 @@
|
||||
import {Args, Command, Flags} from '@oclif/core'
|
||||
import {readAuthConfig} from "../../utils/utils.js";
|
||||
import chalk from "chalk";
|
||||
import {getProject, getProjects} from "../../utils/shared.js";
|
||||
import inquirer from "inquirer";
|
||||
import {Answers} from "../app/create.js";
|
||||
import fs from 'fs';
|
||||
|
||||
export default class EnvPull extends Command {
|
||||
static override args = {
|
||||
file: Args.string({description: 'write to file', required: true}),
|
||||
}
|
||||
|
||||
static override description = 'Store remote environment variables in local'
|
||||
|
||||
static override examples = [
|
||||
'<%= config.bin %> <%= command.id %> .env.stage.local',
|
||||
]
|
||||
|
||||
static override flags = {}
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const {args} = await this.parse(EnvPull)
|
||||
|
||||
if (fs.existsSync(args.file)) {
|
||||
const {override} = await inquirer.prompt<any>([
|
||||
{
|
||||
message: `Do you want to override ${args.file} file?`,
|
||||
name: "override",
|
||||
default: false,
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
if (!override) {
|
||||
return
|
||||
}
|
||||
}
|
||||
const auth = await readAuthConfig(this);
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
const {project} = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select the project:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
const projectId = project.projectId;
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
const {environment} = await inquirer.prompt<any>([
|
||||
{
|
||||
choices: projectSelected.environments.map((environment: any) => ({
|
||||
name: environment.name,
|
||||
value: environment,
|
||||
})),
|
||||
message: "Select the environment:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const choices = [
|
||||
...environment.applications.map((app: any) => ({
|
||||
name: `${app.name} (Application)`,
|
||||
value: app.env,
|
||||
})),
|
||||
...environment.compose.map((compose: any) => ({
|
||||
name: `${compose.name} (Compose)`,
|
||||
value: compose.env,
|
||||
})),
|
||||
]
|
||||
const {env} = await inquirer.prompt<any>([
|
||||
{
|
||||
choices,
|
||||
message: "Select a service to pull the environment variables:",
|
||||
name: "env",
|
||||
type: "list",
|
||||
},
|
||||
|
||||
]);
|
||||
|
||||
|
||||
fs.writeFileSync(args.file, env || "")
|
||||
this.log(chalk.green("Environment variable write to file successful."));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
143
src/commands/env/push.ts
vendored
143
src/commands/env/push.ts
vendored
@@ -1,143 +0,0 @@
|
||||
import {Args, Command, Flags} from '@oclif/core'
|
||||
import fs from "fs";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import {readAuthConfig} from "../../utils/utils.js";
|
||||
import {getProject, getProjects} from "../../utils/shared.js";
|
||||
import {Answers} from "../app/create.js";
|
||||
import axios from "axios";
|
||||
|
||||
export default class EnvPush extends Command {
|
||||
static override args = {
|
||||
file: Args.string({description: '.env file to push', required: true}),
|
||||
}
|
||||
|
||||
static override description = 'Push dotenv file to remote service'
|
||||
|
||||
static override examples = [
|
||||
'<%= config.bin %> <%= command.id %> .env.stage.local',
|
||||
]
|
||||
|
||||
static override flags = {}
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const {args, flags} = await this.parse(EnvPush)
|
||||
|
||||
if (!fs.existsSync(args.file)) {
|
||||
console.log(chalk.red.bold(`\n File ${args.file} doesn't exists \n`));
|
||||
return;
|
||||
}
|
||||
|
||||
const {override} = await inquirer.prompt<any>([
|
||||
{
|
||||
message: `This command will override entire remote environment variables. Do you want to continue?`,
|
||||
name: "override",
|
||||
default: false,
|
||||
type: "confirm",
|
||||
},
|
||||
]);
|
||||
if (!override) {
|
||||
return
|
||||
}
|
||||
|
||||
const fileContent = fs.readFileSync(args.file, 'utf-8');
|
||||
const auth = await readAuthConfig(this);
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
const projects = await getProjects(auth, this);
|
||||
const {project} = await inquirer.prompt<Answers>([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project,
|
||||
})),
|
||||
message: "Select the project:",
|
||||
name: "project",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
const projectId = project.projectId;
|
||||
const projectSelected = await getProject(projectId, auth, this);
|
||||
|
||||
const {environment} = await inquirer.prompt<any>([
|
||||
{
|
||||
choices: projectSelected.environments.map((environment: any) => ({
|
||||
name: environment.name,
|
||||
value: environment,
|
||||
})),
|
||||
message: "Select the environment:",
|
||||
name: "environment",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const choices = [
|
||||
...environment.applications.map((app: any) => ({
|
||||
name: `${app.name} (Application)`,
|
||||
value: {serviceType: 'app', service: app},
|
||||
})),
|
||||
...environment.compose.map((compose: any) => ({
|
||||
name: `${compose.name} (Compose)`,
|
||||
value: {serviceType: 'compose', service: compose}
|
||||
})),
|
||||
]
|
||||
const {result: {serviceType, service}} = await inquirer.prompt<any>([
|
||||
{
|
||||
choices,
|
||||
message: "Select a service to push the environment variables:",
|
||||
name: "result",
|
||||
type: "list",
|
||||
},
|
||||
|
||||
]);
|
||||
|
||||
if (serviceType === 'app') {
|
||||
const {applicationId} = service;
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/application.update`,
|
||||
{
|
||||
json: {
|
||||
applicationId,
|
||||
env: fileContent
|
||||
}
|
||||
}, {
|
||||
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
)
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping application"));
|
||||
}
|
||||
this.log(chalk.green("Environment variable push successful."));
|
||||
|
||||
}
|
||||
|
||||
if (serviceType === 'compose') {
|
||||
const {composeId} = service;
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/compose.update`,
|
||||
{
|
||||
json: {
|
||||
composeId,
|
||||
env: fileContent
|
||||
}
|
||||
}, {
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
)
|
||||
if (response.status !== 200) {
|
||||
this.error(chalk.red("Error stopping application"));
|
||||
}
|
||||
this.log(chalk.green("Environment variable push successful."));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
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<void> {
|
||||
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<Answers>([
|
||||
{
|
||||
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}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
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 <projectId>",
|
||||
];
|
||||
|
||||
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<void> {
|
||||
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<Answers>([
|
||||
{
|
||||
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}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
|
||||
export default class ProjectCreate extends Command {
|
||||
static description = "Create a new project.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> project create",
|
||||
"$ <%= config.bin %> project create -n MyProject -d 'Project description'",
|
||||
"$ <%= config.bin %> project create --name MyProject --skipConfirm",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
name: Flags.string({
|
||||
char: "n",
|
||||
description: "Name of the project",
|
||||
required: false,
|
||||
}),
|
||||
description: Flags.string({
|
||||
char: "d",
|
||||
description: "Description of the project",
|
||||
required: false,
|
||||
}),
|
||||
skipConfirm: Flags.boolean({
|
||||
char: "y",
|
||||
description: "Skip confirmation prompt",
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
const { flags } = await this.parse(ProjectCreate);
|
||||
let { name, description } = flags;
|
||||
|
||||
// Modo interactivo si no se proporcionan los flags necesarios
|
||||
if (!name) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
message: "Enter the project name:",
|
||||
name: "name",
|
||||
type: "input",
|
||||
validate: (input) => (input ? true : "Project name is required"),
|
||||
},
|
||||
{
|
||||
message: "Enter the project description (optional):",
|
||||
name: "description",
|
||||
type: "input",
|
||||
default: description || "",
|
||||
},
|
||||
]);
|
||||
|
||||
name = answers.name;
|
||||
description = answers.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 project?',
|
||||
default: false,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm.proceed) {
|
||||
this.error(chalk.yellow("Project creation cancelled."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
const response = await axios.post(
|
||||
`${auth.url}/api/trpc/project.create`,
|
||||
{
|
||||
json: {
|
||||
name,
|
||||
description,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
this.error(chalk.red("Error creating project", response.data.result.data.json));
|
||||
}
|
||||
|
||||
this.log(chalk.green(`Project '${name}' created successfully.`));
|
||||
} catch (error: any) {
|
||||
this.error(chalk.red(`Error creating project: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
import { Command, Flags } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import { getProjects } from "../../utils/shared.js";
|
||||
|
||||
export default class ProjectInfo extends Command {
|
||||
static description =
|
||||
"Get detailed information about a project, including the number of applications and databases.";
|
||||
|
||||
static examples = [
|
||||
"$ <%= config.bin %> project info",
|
||||
"$ <%= config.bin %> project info -p <projectId>",
|
||||
];
|
||||
|
||||
static flags = {
|
||||
projectId: Flags.string({
|
||||
char: "p",
|
||||
description: "ID of the project",
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
const { flags } = await this.parse(ProjectInfo);
|
||||
|
||||
if (flags.projectId) {
|
||||
await this.showProjectInfo(auth, flags.projectId);
|
||||
} else {
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
try {
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
return;
|
||||
}
|
||||
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
choices: projects.map((project) => ({
|
||||
name: project.name,
|
||||
value: project.projectId,
|
||||
})),
|
||||
message: "Select a project to view details:",
|
||||
name: "selectedProject",
|
||||
type: "list",
|
||||
},
|
||||
]);
|
||||
|
||||
const selectedProjectId = answers.selectedProject;
|
||||
|
||||
await this.showProjectInfo(auth, selectedProjectId);
|
||||
} catch (error) {
|
||||
// @ts-expect-error hola
|
||||
this.error(chalk.red(`Failed to fetch project list: ${error.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async showProjectInfo(
|
||||
auth: { token: string; url: string },
|
||||
projectId: string,
|
||||
) {
|
||||
console.log(
|
||||
chalk.blue.bold(`\n Information for Project ID: ${projectId} \n`),
|
||||
);
|
||||
|
||||
try {
|
||||
const projects = await getProjects(auth, this);
|
||||
const projectInfo = projects.find(p => p.projectId === projectId);
|
||||
|
||||
if (!projectInfo) {
|
||||
this.error(chalk.red("Project not found."));
|
||||
return;
|
||||
}
|
||||
|
||||
this.log(chalk.green(`Project Name: ${projectInfo.name}`));
|
||||
this.log(
|
||||
chalk.green(
|
||||
`Description: ${projectInfo?.description || "No description"}`,
|
||||
),
|
||||
);
|
||||
|
||||
// Contar totales de todos los environments
|
||||
let totalApplications = 0;
|
||||
let totalCompose = 0;
|
||||
let totalMariaDB = 0;
|
||||
let totalMongoDB = 0;
|
||||
let totalMySQL = 0;
|
||||
let totalPostgreSQL = 0;
|
||||
let totalRedis = 0;
|
||||
|
||||
if (projectInfo.environments && projectInfo.environments.length > 0) {
|
||||
this.log(chalk.green(`Number of Environments: ${projectInfo.environments.length}`));
|
||||
|
||||
// Mostrar información por environment
|
||||
projectInfo.environments.forEach((env, envIndex) => {
|
||||
this.log(chalk.blue(`\nEnvironment ${envIndex + 1}: ${env.name} (${env.description})`));
|
||||
|
||||
// Contar recursos por environment
|
||||
const envApps = env.applications?.length || 0;
|
||||
const envCompose = env.compose?.length || 0;
|
||||
const envMariaDB = env.mariadb?.length || 0;
|
||||
const envMongoDB = env.mongo?.length || 0;
|
||||
const envMySQL = env.mysql?.length || 0;
|
||||
const envPostgreSQL = env.postgres?.length || 0;
|
||||
const envRedis = env.redis?.length || 0;
|
||||
|
||||
totalApplications += envApps;
|
||||
totalCompose += envCompose;
|
||||
totalMariaDB += envMariaDB;
|
||||
totalMongoDB += envMongoDB;
|
||||
totalMySQL += envMySQL;
|
||||
totalPostgreSQL += envPostgreSQL;
|
||||
totalRedis += envRedis;
|
||||
|
||||
this.log(` Applications: ${envApps}`);
|
||||
this.log(` Compose Services: ${envCompose}`);
|
||||
this.log(` MariaDB: ${envMariaDB}`);
|
||||
this.log(` MongoDB: ${envMongoDB}`);
|
||||
this.log(` MySQL: ${envMySQL}`);
|
||||
this.log(` PostgreSQL: ${envPostgreSQL}`);
|
||||
this.log(` Redis: ${envRedis}`);
|
||||
|
||||
// Mostrar detalles de applications
|
||||
if (envApps > 0) {
|
||||
this.log(chalk.cyan(" Applications:"));
|
||||
env.applications.forEach((app, index) => {
|
||||
this.log(` ${index + 1}. ${app.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Mostrar detalles de databases
|
||||
if (envMariaDB > 0) {
|
||||
this.log(chalk.cyan(" MariaDB Databases:"));
|
||||
env.mariadb.forEach((db, index) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (envMongoDB > 0) {
|
||||
this.log(chalk.cyan(" MongoDB Databases:"));
|
||||
env.mongo.forEach((db, index) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (envMySQL > 0) {
|
||||
this.log(chalk.cyan(" MySQL Databases:"));
|
||||
env.mysql.forEach((db, index) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (envPostgreSQL > 0) {
|
||||
this.log(chalk.cyan(" PostgreSQL Databases:"));
|
||||
env.postgres.forEach((db, index) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
|
||||
if (envRedis > 0) {
|
||||
this.log(chalk.cyan(" Redis Databases:"));
|
||||
env.redis.forEach((db, index) => {
|
||||
this.log(` ${index + 1}. ${db.name}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.log(chalk.yellow("No environments found in this project."));
|
||||
}
|
||||
|
||||
// Mostrar totales
|
||||
this.log(chalk.green.bold("\n📊 Project Totals:"));
|
||||
this.log(chalk.green(`Total Applications: ${totalApplications}`));
|
||||
this.log(chalk.green(`Total Compose Services: ${totalCompose}`));
|
||||
this.log(chalk.green(`Total MariaDB Databases: ${totalMariaDB}`));
|
||||
this.log(chalk.green(`Total MongoDB Databases: ${totalMongoDB}`));
|
||||
this.log(chalk.green(`Total MySQL Databases: ${totalMySQL}`));
|
||||
this.log(chalk.green(`Total PostgreSQL Databases: ${totalPostgreSQL}`));
|
||||
this.log(chalk.green(`Total Redis Databases: ${totalRedis}`));
|
||||
|
||||
} catch (error) {
|
||||
this.error(
|
||||
// @ts-expect-error
|
||||
chalk.red(`Failed to fetch project information: ${error.message}`),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import chalk from "chalk";
|
||||
import Table from "cli-table3";
|
||||
|
||||
import { readAuthConfig } from "../../utils/utils.js";
|
||||
import { getProjects } from "../../utils/shared.js";
|
||||
|
||||
export default class ProjectList extends Command {
|
||||
static description = "List all projects.";
|
||||
|
||||
static examples = ["$ <%= config.bin %> project list"];
|
||||
|
||||
public async run(): Promise<void> {
|
||||
const auth = await readAuthConfig(this);
|
||||
|
||||
console.log(chalk.blue.bold("\n Listing all Projects \n"));
|
||||
|
||||
try {
|
||||
const projects = await getProjects(auth, this);
|
||||
|
||||
if (projects.length === 0) {
|
||||
this.log(chalk.yellow("No projects found."));
|
||||
} else {
|
||||
this.log(chalk.green("Projects:"));
|
||||
const table = new Table({
|
||||
colWidths: [10, 30, 50],
|
||||
head: [
|
||||
chalk.cyan("Index"),
|
||||
chalk.cyan("Name"),
|
||||
chalk.cyan("Description"),
|
||||
],
|
||||
});
|
||||
const index = 1;
|
||||
for (const project of projects) {
|
||||
table.push([
|
||||
chalk.white(index + 1),
|
||||
chalk.white(project.name),
|
||||
chalk.gray(project.description || "No description"),
|
||||
]);
|
||||
}
|
||||
|
||||
this.log(table.toString());
|
||||
}
|
||||
} catch (error) {
|
||||
// @ts-expect-error error is not defined
|
||||
this.error(chalk.red(`Failed to list projects: ${error?.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import { Command } from "@oclif/core";
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
export default class Verify extends Command {
|
||||
static description = "Verify if the saved authentication token is valid";
|
||||
|
||||
static examples = ["$ <%= config.bin %> <%= command.id %>"];
|
||||
|
||||
async run() {
|
||||
console.log(chalk.blue.bold("\nVerifying Authentication Token"));
|
||||
|
||||
let token: string;
|
||||
let url: string;
|
||||
|
||||
// Verificar variables de entorno primero
|
||||
const envToken = process.env.DOKPLOY_AUTH_TOKEN;
|
||||
const envUrl = process.env.DOKPLOY_URL;
|
||||
|
||||
if (envToken && envUrl) {
|
||||
token = envToken;
|
||||
url = envUrl;
|
||||
this.log(chalk.green("Using environment variables for authentication"));
|
||||
} else {
|
||||
// Si no hay variables de entorno, verificar archivo de configuración
|
||||
if (!fs.existsSync(configPath)) {
|
||||
this.error(
|
||||
chalk.red(
|
||||
"No configuration found. Please either:\n" +
|
||||
"1. Authenticate using `authenticate` command\n" +
|
||||
"2. Set DOKPLOY_URL and DOKPLOY_AUTH_TOKEN environment variables",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
||||
token = config.token;
|
||||
url = config.url;
|
||||
this.log(chalk.green("Using configuration file for authentication"));
|
||||
} catch (error) {
|
||||
this.error(
|
||||
chalk.red(
|
||||
"Invalid configuration file. Please authenticate again using `authenticate` command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Validar el token contra el servidor
|
||||
try {
|
||||
console.log(chalk.blue("Validating token with server..."));
|
||||
|
||||
const response = await axios.get(
|
||||
`${url}/api/trpc/user.get`,
|
||||
{
|
||||
headers: {
|
||||
"x-api-key": token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (response.data.result.data.json) {
|
||||
this.log(chalk.green("\n✓ Token is valid"));
|
||||
} else {
|
||||
this.error(
|
||||
chalk.red(
|
||||
"Invalid token. Please authenticate again using `authenticate` command.",
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.error(
|
||||
chalk.red(
|
||||
`Failed to verify token: ${error.message}. Please authenticate again using 'authenticate' command.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
8720
src/generated/commands.ts
Normal file
8720
src/generated/commands.ts
Normal file
File diff suppressed because it is too large
Load Diff
22
src/index.ts
22
src/index.ts
@@ -1 +1,21 @@
|
||||
export {run} from '@oclif/core'
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { program } from "commander";
|
||||
import chalk from "chalk";
|
||||
import { registerAuthCommand } from "./commands/auth.js";
|
||||
import { registerGeneratedCommands } from "./generated/commands.js";
|
||||
|
||||
const pkg = { name: "dokploy", version: "0.3.0", description: "Dokploy CLI - Manage your Dokploy server" };
|
||||
|
||||
program
|
||||
.name(pkg.name)
|
||||
.version(pkg.version)
|
||||
.description(pkg.description);
|
||||
|
||||
registerAuthCommand(program);
|
||||
registerGeneratedCommands(program);
|
||||
|
||||
program.parseAsync(process.argv).catch((err) => {
|
||||
console.error(chalk.red(err.message));
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Dokploy CLI",
|
||||
};
|
||||
@@ -1,114 +0,0 @@
|
||||
import type { Command } from "@oclif/core";
|
||||
|
||||
import axios from "axios";
|
||||
import chalk from "chalk";
|
||||
|
||||
import type { AuthConfig } from "./utils.js";
|
||||
|
||||
export type Application = {
|
||||
applicationId: string;
|
||||
name: string;
|
||||
// Add other application properties as needed
|
||||
};
|
||||
|
||||
export type Database = {
|
||||
mariadbId?: string;
|
||||
mongoId?: string;
|
||||
mysqlId?: string;
|
||||
postgresId?: string;
|
||||
redisId?: string;
|
||||
name: string;
|
||||
// Add other database properties as needed
|
||||
};
|
||||
|
||||
export type Environment = {
|
||||
name: string;
|
||||
environmentId: string;
|
||||
description: string;
|
||||
createdAt: string;
|
||||
env: string;
|
||||
projectId: string;
|
||||
applications: Application[];
|
||||
mariadb: Database[];
|
||||
mongo: Database[];
|
||||
mysql: Database[];
|
||||
postgres: Database[];
|
||||
redis: Database[];
|
||||
compose: any[];
|
||||
};
|
||||
|
||||
export type Project = {
|
||||
adminId: string;
|
||||
name: string;
|
||||
projectId?: string | undefined;
|
||||
description?: string | undefined;
|
||||
environments?: Environment[];
|
||||
};
|
||||
|
||||
export const getProjects = async (
|
||||
auth: AuthConfig,
|
||||
command: Command,
|
||||
): Promise<Project[]> => {
|
||||
try {
|
||||
const response = await axios.get(`${auth.url}/api/trpc/project.all`, {
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
command.error(chalk.red("Error fetching projects"));
|
||||
}
|
||||
|
||||
const projects = response.data.result.data.json;
|
||||
|
||||
if (projects.length === 0) {
|
||||
command.log(chalk.yellow("No projects found."));
|
||||
return [];
|
||||
}
|
||||
|
||||
return projects;
|
||||
} catch (error) {
|
||||
// @ts-expect-error TODO: Fix this
|
||||
command.error(chalk.red(`Failed to fetch project list: ${error.message}`));
|
||||
}
|
||||
};
|
||||
|
||||
export const getProject = async (
|
||||
projectId: string | undefined,
|
||||
auth: AuthConfig,
|
||||
command: Command,
|
||||
) => {
|
||||
try {
|
||||
if (!projectId) {
|
||||
command.error(chalk.red("Project ID is required"));
|
||||
}
|
||||
const response = await axios.get(`${auth.url}/api/trpc/project.one`, {
|
||||
headers: {
|
||||
"x-api-key": auth.token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
params: {
|
||||
input: JSON.stringify({
|
||||
json: { projectId },
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data.result.data.json) {
|
||||
command.error(chalk.red("Error fetching project"));
|
||||
}
|
||||
|
||||
const project = response.data.result.data.json;
|
||||
|
||||
if (!project) {
|
||||
command.error(chalk.red("Error fetching project"));
|
||||
}
|
||||
|
||||
return project;
|
||||
} catch (error) {
|
||||
// @ts-expect-error TODO: Fix this
|
||||
command.error(chalk.red(`Failed to fetch project: ${error.message}`));
|
||||
}
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import slug from "./slugify.js";
|
||||
|
||||
export const slugify = (text: string | undefined) => {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const cleanedText = text.trim().replaceAll(/[^\d\sA-Za-z]/g, "");
|
||||
return slug(cleanedText, {
|
||||
lower: true,
|
||||
strict: true,
|
||||
trim: true,
|
||||
});
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
import slugify from "slugify";
|
||||
|
||||
export default slugify as unknown as typeof slugify.default;
|
||||
@@ -1,48 +0,0 @@
|
||||
import type { Command } from "@oclif/core";
|
||||
|
||||
import chalk from "chalk";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const configPath = path.join(__dirname, "..", "..", "config.json");
|
||||
|
||||
export type AuthConfig = {
|
||||
token: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export const readAuthConfig = async (command: Command): Promise<AuthConfig> => {
|
||||
// Primero intentar leer desde variables de entorno
|
||||
const envToken = process.env.DOKPLOY_AUTH_TOKEN;
|
||||
const envUrl = process.env.DOKPLOY_URL;
|
||||
|
||||
if (envToken && envUrl) {
|
||||
return { token: envToken, url: envUrl };
|
||||
}
|
||||
|
||||
// Si no hay variables de entorno, usar el archivo de configuración
|
||||
if (!fs.existsSync(configPath)) {
|
||||
command.error(
|
||||
chalk.red(
|
||||
"No configuration file found and no environment variables set. Please authenticate first using the 'authenticate' command or set DOKPLOY_URL and DOKPLOY_AUTH_TOKEN environment variables.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const configFileContent = fs.readFileSync(configPath, "utf8");
|
||||
const config = JSON.parse(configFileContent);
|
||||
const { token, url } = config;
|
||||
|
||||
if (!url || !token) {
|
||||
command.error(
|
||||
chalk.red(
|
||||
"Incomplete authentication details. Please authenticate again using the 'authenticate' command or set environment variables.",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return { token, url };
|
||||
};
|
||||
@@ -7,6 +7,7 @@
|
||||
"strict": true,
|
||||
"target": "es2022",
|
||||
"moduleResolution": "node16",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"ts-node": {
|
||||
|
||||
1
tsconfig.tsbuildinfo
Normal file
1
tsconfig.tsbuildinfo
Normal file
@@ -0,0 +1 @@
|
||||
{"root":["./src/client.ts","./src/index.ts","./src/commands/auth.ts","./src/generated/commands.ts"],"version":"5.9.3"}
|
||||
Reference in New Issue
Block a user