@batistafull/deploy-server 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/bin/deploy-server.js +22 -37
- package/lib/deploy.js +108 -0
- package/package.json +15 -2
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @batistafull/deploy-server
|
|
2
|
+
|
|
3
|
+
Herramienta CLI de despliegue dirigida por configuración. Ejecuta los comandos de build de tu proyecto y copia las carpetas `dist` y `server` a la carpeta destino que indiques, con opción de subir el resultado por FTP/FTPS.
|
|
4
|
+
|
|
5
|
+
## Instalación
|
|
6
|
+
|
|
7
|
+
Global:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @batistafull/deploy-server
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
O como dependencia de desarrollo del proyecto:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install --save-dev @batistafull/deploy-server
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Uso
|
|
20
|
+
|
|
21
|
+
Desde la raíz de tu proyecto, crea un archivo `deploy.config.json` (ver formato abajo) y ejecuta:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
deploy-server
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Opciones
|
|
28
|
+
|
|
29
|
+
| Opción | Descripción | Por defecto |
|
|
30
|
+
| ----------------- | ---------------------------------------------- | -------------------- |
|
|
31
|
+
| `--config <path>` | Ruta al archivo de configuración | `deploy.config.json` |
|
|
32
|
+
| `--clean` | Limpia la carpeta de salida antes de desplegar | (desactivado) |
|
|
33
|
+
| `-h, --help` | Muestra la ayuda | |
|
|
34
|
+
|
|
35
|
+
Ejemplos:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Deploy con la config por defecto
|
|
39
|
+
deploy-server
|
|
40
|
+
|
|
41
|
+
# Limpiar la salida antes de copiar
|
|
42
|
+
deploy-server --clean
|
|
43
|
+
|
|
44
|
+
# Usar otro archivo de config
|
|
45
|
+
deploy-server --config configs/prod.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Configuración
|
|
49
|
+
|
|
50
|
+
Crea `deploy.config.json` en la raíz de tu proyecto. **Este archivo lo creas tú**, no viene incluido en el paquete.
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"output": "C:/inetpub/app.host",
|
|
55
|
+
"dist": "dist",
|
|
56
|
+
"server": "api",
|
|
57
|
+
"buildCommand": ["npm install", "npm run build"],
|
|
58
|
+
"exclude": ["node_modules", ".git", ".env"],
|
|
59
|
+
"ftp": {
|
|
60
|
+
"enabled": false,
|
|
61
|
+
"host": "ftp.example.com",
|
|
62
|
+
"secure": true,
|
|
63
|
+
"remotePath": "/public_html"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Campos
|
|
69
|
+
|
|
70
|
+
| Campo | Tipo | Descripción |
|
|
71
|
+
| -------------- | --------------------- | ------------------------------------------------------------- |
|
|
72
|
+
| `output` | `string` | Ruta destino del deploy (ver nota abajo). |
|
|
73
|
+
| `dist` | `string` | Ruta (relativa al proyecto) de la carpeta compilada a copiar. |
|
|
74
|
+
| `server` | `string` | Ruta (relativa al proyecto) de la carpeta del servidor/API. |
|
|
75
|
+
| `buildCommand` | `string` o `string[]` | Comando(s) de build. Si es un array, se ejecutan en orden. |
|
|
76
|
+
| `exclude` | `string[]` | Nombres de archivos o carpetas a excluir al copiar. |
|
|
77
|
+
| `ftp` | `object` | (Opcional) Configuración de subida por FTP/FTPS. Ver abajo. |
|
|
78
|
+
|
|
79
|
+
> **`output`:** si es una ruta **absoluta** se usa tal cual (ej: `C:/inetpub/app.host`);
|
|
80
|
+
> si es **relativa** se resuelve desde la raíz del proyecto (ej: `../deploy/app.host`).
|
|
81
|
+
|
|
82
|
+
### FTP / FTPS
|
|
83
|
+
|
|
84
|
+
La subida por FTP está desactivada salvo que pongas `ftp.enabled: true`.
|
|
85
|
+
|
|
86
|
+
| Campo | Descripción |
|
|
87
|
+
| ---------------- | -------------------------------------------------------------------------- |
|
|
88
|
+
| `ftp.enabled` | `true` para activar la subida. |
|
|
89
|
+
| `ftp.host` | Host del servidor FTP (fallback de `FTP_HOST`). |
|
|
90
|
+
| `ftp.secure` | `true` (por defecto) usa FTPS con TLS. Pon `false` solo si no hay soporte. |
|
|
91
|
+
| `ftp.remotePath` | Carpeta remota destino. |
|
|
92
|
+
|
|
93
|
+
> **Seguridad:** las credenciales se leen preferentemente de variables de entorno.
|
|
94
|
+
> **No pongas la contraseña en el JSON.**
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Linux / macOS
|
|
98
|
+
FTP_HOST=ftp.tuservidor.com FTP_USER=usuario FTP_PASSWORD=secreto deploy-server
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```powershell
|
|
102
|
+
# Windows (PowerShell)
|
|
103
|
+
$env:FTP_HOST="ftp.tuservidor.com"; $env:FTP_USER="usuario"; $env:FTP_PASSWORD="secreto"
|
|
104
|
+
deploy-server
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Si el FTP está habilitado y faltan `FTP_HOST`, `FTP_USER` o `FTP_PASSWORD` (y tampoco están en el config), el deploy falla con un error claro.
|
|
108
|
+
|
|
109
|
+
## Qué hace, paso a paso
|
|
110
|
+
|
|
111
|
+
1. Carga el `deploy.config.json`.
|
|
112
|
+
2. Si se pasa `--clean`, borra la carpeta de salida.
|
|
113
|
+
3. Ejecuta el/los `buildCommand`.
|
|
114
|
+
4. Copia `dist` → `<output>` (aplicando `exclude`).
|
|
115
|
+
5. Copia `server` → `<output>` (aplicando `exclude`).
|
|
116
|
+
6. Si `ftp.enabled`, sube la carpeta de salida por FTP/FTPS.
|
|
117
|
+
|
|
118
|
+
## Licencia
|
|
119
|
+
|
|
120
|
+
MIT
|
package/bin/deploy-server.js
CHANGED
|
@@ -1,39 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
execSync("npm run build", {
|
|
26
|
-
cwd: projectRoot,
|
|
27
|
-
stdio: "inherit"
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
console.log("📦 Copiando dist...");
|
|
31
|
-
fs.cpSync(distPath, destination, { recursive: true });
|
|
32
|
-
|
|
33
|
-
console.log("📦 Copiando server/api...");
|
|
34
|
-
fs.cpSync(apiPath, destination, { recursive: true });
|
|
35
|
-
|
|
36
|
-
console.log("✅ Deploy completado en:", destination);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
run();
|
|
3
|
+
const { program } = require("commander");
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const deploy = require("../lib/deploy");
|
|
6
|
+
|
|
7
|
+
program
|
|
8
|
+
.name("deploy-server")
|
|
9
|
+
.description("Config-driven deploy tool")
|
|
10
|
+
.option("--config <path>", "config file path", "deploy.config.json")
|
|
11
|
+
.option("--clean", "clean output folder before deploy")
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
console.log(chalk.blue("🚀 Loading deploy config..."));
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
await deploy(options);
|
|
17
|
+
console.log(chalk.green("✅ Deploy completed"));
|
|
18
|
+
} catch (err) {
|
|
19
|
+
console.error(chalk.red("❌ Deploy failed:"), err);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
program.parse();
|
package/lib/deploy.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs-extra");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
const { execSync } = require("child_process");
|
|
5
|
+
const ftp = require("basic-ftp");
|
|
6
|
+
|
|
7
|
+
// Ejecuta una lista de comandos de build en orden
|
|
8
|
+
function runBuildCommands(commands, cwd) {
|
|
9
|
+
for (const command of commands) {
|
|
10
|
+
console.log(chalk.gray(`🔨 $ ${command}`));
|
|
11
|
+
execSync(command, { cwd, stdio: "inherit" });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Copia un directorio excluyendo los patrones indicados (match por nombre o ruta relativa)
|
|
16
|
+
async function copyFiltered(srcPath, destPath, exclude = []) {
|
|
17
|
+
if (!(await fs.pathExists(srcPath))) {
|
|
18
|
+
console.log(chalk.yellow(`⚠️ Origen no encontrado, se omite: ${srcPath}`));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
await fs.copy(srcPath, destPath, {
|
|
23
|
+
filter: (src) => {
|
|
24
|
+
const relative = path.relative(srcPath, src);
|
|
25
|
+
if (!relative) return true; // el propio directorio raíz
|
|
26
|
+
const name = path.basename(src);
|
|
27
|
+
return !exclude.some(
|
|
28
|
+
(pattern) => name === pattern || relative.split(path.sep).includes(pattern)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = async function deploy(options) {
|
|
35
|
+
const config = require(path.resolve(process.cwd(), options.config));
|
|
36
|
+
|
|
37
|
+
const projectRoot = process.cwd();
|
|
38
|
+
|
|
39
|
+
if (!config.output) {
|
|
40
|
+
throw new Error("Falta 'output' en el config: indica la carpeta destino del deploy.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 'output' es la ruta destino. Si es absoluta se usa tal cual;
|
|
44
|
+
// si es relativa se resuelve desde la raíz del proyecto.
|
|
45
|
+
const outputPath = path.resolve(projectRoot, config.output);
|
|
46
|
+
|
|
47
|
+
const distPath = path.join(projectRoot, config.dist);
|
|
48
|
+
const serverPath = path.join(projectRoot, config.server);
|
|
49
|
+
|
|
50
|
+
// Clean
|
|
51
|
+
if (options.clean) {
|
|
52
|
+
console.log(chalk.gray("🧹 Cleaning output..."));
|
|
53
|
+
await fs.remove(outputPath);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await fs.ensureDir(outputPath);
|
|
57
|
+
|
|
58
|
+
// BUILD (ARRAY)
|
|
59
|
+
if (Array.isArray(config.buildCommand)) {
|
|
60
|
+
runBuildCommands(config.buildCommand, projectRoot);
|
|
61
|
+
} else {
|
|
62
|
+
execSync(config.buildCommand, {
|
|
63
|
+
cwd: projectRoot,
|
|
64
|
+
stdio: "inherit"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// COPY DIST
|
|
69
|
+
console.log(chalk.blue("📦 Copying dist..."));
|
|
70
|
+
await copyFiltered(distPath, outputPath, config.exclude || []);
|
|
71
|
+
|
|
72
|
+
// COPY SERVER
|
|
73
|
+
console.log(chalk.blue("📦 Copying server..."));
|
|
74
|
+
await copyFiltered(serverPath, outputPath, config.exclude || []);
|
|
75
|
+
|
|
76
|
+
// FTP (opcional)
|
|
77
|
+
if (config.ftp?.enabled) {
|
|
78
|
+
const client = new ftp.Client();
|
|
79
|
+
|
|
80
|
+
// Las credenciales se leen preferentemente de variables de entorno.
|
|
81
|
+
// El config solo debe usarse como fallback para valores no sensibles.
|
|
82
|
+
const host = process.env.FTP_HOST || config.ftp.host;
|
|
83
|
+
const user = process.env.FTP_USER || config.ftp.user;
|
|
84
|
+
const password = process.env.FTP_PASSWORD || config.ftp.password;
|
|
85
|
+
// FTPS por defecto; poner ftp.secure=false en el config solo si el
|
|
86
|
+
// servidor no soporta TLS (no recomendado).
|
|
87
|
+
const secure = config.ftp.secure !== false;
|
|
88
|
+
|
|
89
|
+
if (!host || !user || !password) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
"FTP habilitado pero faltan credenciales. Define FTP_HOST, FTP_USER y FTP_PASSWORD (o config.ftp.*)."
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(chalk.yellow(`📡 Connecting FTP (${secure ? "FTPS" : "sin cifrar"})...`));
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await client.access({ host, user, password, secure });
|
|
99
|
+
|
|
100
|
+
await client.ensureDir(config.ftp.remotePath);
|
|
101
|
+
await client.uploadFromDir(outputPath);
|
|
102
|
+
|
|
103
|
+
console.log(chalk.green("🌐 FTP upload done"));
|
|
104
|
+
} finally {
|
|
105
|
+
client.close();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@batistafull/deploy-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Deploy tool that builds and copies dist + api to Documents/app.host",
|
|
5
5
|
"main": "bin/deploy-server.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"deploy-server": "bin/deploy-server.js"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"lib/"
|
|
12
|
+
],
|
|
9
13
|
"keywords": ["deploy", "cli", "nodejs"],
|
|
10
14
|
"author": "batistafull",
|
|
11
15
|
"license": "MIT",
|
|
12
|
-
"type": "commonjs"
|
|
16
|
+
"type": "commonjs",
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=16"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"basic-ftp": "^5.0.5",
|
|
22
|
+
"chalk": "^4.1.2",
|
|
23
|
+
"commander": "^12.1.0",
|
|
24
|
+
"fs-extra": "^11.2.0"
|
|
25
|
+
}
|
|
13
26
|
}
|