121 lines
6.0 KiB
JavaScript
121 lines
6.0 KiB
JavaScript
// Arma una carpeta lista para copiar al servidor: release/devolucion-proveedores/
|
|
//
|
|
// npm run publicar compila todo y arma la carpeta
|
|
// npm run publicar -- --sin-build reutiliza los builds que ya existen (libs/shared/dist, apps/*/dist)
|
|
//
|
|
// Contenido: la API compilada, la web compilada y solo las dependencias de producción de la API
|
|
// (sin Angular CLI ni herramientas de desarrollo). Las dependencias de la API son JavaScript puro,
|
|
// así que se puede publicar desde un Mac o Linux y ejecutar en Windows.
|
|
import { spawnSync } from 'node:child_process';
|
|
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const raiz = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const destino = join(raiz, 'release', 'devolucion-proveedores');
|
|
const app = join(destino, 'app');
|
|
const sinBuild = process.argv.includes('--sin-build');
|
|
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
|
|
function ejecutar(comando, args, cwd) {
|
|
console.log(`\n$ ${comando} ${args.join(' ')} (${cwd})`);
|
|
// shell: true en Windows porque npm es un .cmd
|
|
const r = spawnSync(comando, args, { cwd, stdio: 'inherit', shell: process.platform === 'win32' });
|
|
if (r.status !== 0) {
|
|
console.error(`\nFalló: ${comando} ${args.join(' ')}`);
|
|
process.exit(r.status ?? 1);
|
|
}
|
|
}
|
|
|
|
function copiar(origen, destinoRelativo) {
|
|
const desde = join(raiz, origen);
|
|
if (!existsSync(desde)) {
|
|
console.error(`Falta ${origen}. Ejecute "npm run publicar" sin --sin-build (o "npm run build" antes).`);
|
|
process.exit(1);
|
|
}
|
|
cpSync(desde, join(app, destinoRelativo ?? origen), { recursive: true });
|
|
}
|
|
|
|
/** Commit corto de git (con "-modificado" si hay cambios sin commit), o null si no hay git o commits. */
|
|
function commitActual() {
|
|
const git = (...args) => spawnSync('git', args, { cwd: raiz, encoding: 'utf8' });
|
|
const head = git('rev-parse', '--short', 'HEAD');
|
|
if (head.status !== 0) return null;
|
|
const cambios = git('status', '--porcelain').stdout.trim().length > 0;
|
|
return `${head.stdout.trim()}${cambios ? '-modificado' : ''}`;
|
|
}
|
|
|
|
function tamano(carpeta) {
|
|
let total = 0;
|
|
for (const e of readdirSync(carpeta, { withFileTypes: true, recursive: true })) {
|
|
if (e.isFile()) total += statSync(join(e.parentPath, e.name)).size;
|
|
}
|
|
return `${(total / 1024 / 1024).toFixed(1)} MB`;
|
|
}
|
|
|
|
console.log('Publicando Devolución a Proveedores');
|
|
if (!sinBuild) ejecutar(npm, ['run', 'build'], raiz);
|
|
|
|
rmSync(destino, { recursive: true, force: true });
|
|
mkdirSync(app, { recursive: true });
|
|
|
|
// Lo mínimo para que `npm ci` resuelva los mismos paquetes del package-lock: el package.json raíz
|
|
// y el de cada workspace (la web no se instala, pero debe estar declarada para que el lock coincida).
|
|
copiar('package.json');
|
|
copiar('package-lock.json');
|
|
copiar('libs/shared/package.json');
|
|
copiar('libs/shared/dist');
|
|
copiar('apps/api/package.json');
|
|
copiar('apps/api/dist');
|
|
copiar('apps/api/.env.example');
|
|
copiar('apps/web/package.json');
|
|
copiar('apps/web/dist/web/browser');
|
|
|
|
ejecutar(npm, ['ci', '--omit=dev', '--workspace=@dp/shared', '--workspace=api', '--no-audit', '--no-fund'], app);
|
|
|
|
// npm deja enlaces simbólicos (el de cada workspace y los atajos de .bin) que no sobreviven al copiar la
|
|
// carpeta de un Mac/Linux a Windows. La API importa @dp/shared al ejecutarse, así que ese enlace se
|
|
// reemplaza por una copia real; los demás no se usan y se quitan.
|
|
const nodeModules = join(app, 'node_modules');
|
|
rmSync(join(nodeModules, 'api'), { recursive: true, force: true });
|
|
const compartido = join(nodeModules, '@dp', 'shared');
|
|
rmSync(compartido, { recursive: true, force: true }); // quita solo el enlace, no su destino
|
|
mkdirSync(compartido, { recursive: true });
|
|
cpSync(join(app, 'libs', 'shared', 'package.json'), join(compartido, 'package.json'));
|
|
cpSync(join(app, 'libs', 'shared', 'dist'), join(compartido, 'dist'), { recursive: true });
|
|
rmSync(join(app, 'libs'), { recursive: true, force: true });
|
|
for (const e of readdirSync(nodeModules, { withFileTypes: true, recursive: true })) {
|
|
if (e.name === '.bin') rmSync(join(e.parentPath, e.name), { recursive: true, force: true });
|
|
}
|
|
|
|
const enlaces = readdirSync(app, { withFileTypes: true, recursive: true })
|
|
.filter((e) => e.isSymbolicLink())
|
|
.map((e) => join(e.parentPath, e.name));
|
|
if (enlaces.length > 0) {
|
|
console.error(`\nQuedaron enlaces simbólicos en el paquete (no sobreviven en Windows):\n ${enlaces.join('\n ')}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Archivos de despliegue para Windows junto a la carpeta app/
|
|
for (const archivo of readdirSync(join(raiz, 'deploy', 'windows'))) {
|
|
cpSync(join(raiz, 'deploy', 'windows', archivo), join(destino, archivo));
|
|
}
|
|
for (const carpeta of ['logs', 'certificados']) mkdirSync(join(destino, carpeta), { recursive: true });
|
|
writeFileSync(join(destino, 'certificados', 'LEEME.txt'), 'Ponga aquí el certificado HTTPS (.pfx, o .key y .crt) y apunte el .env a estos archivos.\n');
|
|
|
|
// Versión: el número sale del package.json raíz (npm run version:parche|menor|mayor). La API lee
|
|
// app/version.json al arrancar y la web la muestra en el login y en la barra superior.
|
|
const { name, version } = JSON.parse(readFileSync(join(raiz, 'package.json'), 'utf8'));
|
|
const publicado = new Date().toISOString();
|
|
const commit = commitActual();
|
|
writeFileSync(join(app, 'version.json'), `${JSON.stringify({ version, publicado, commit }, null, 2)}\n`);
|
|
writeFileSync(
|
|
join(destino, 'VERSION.txt'),
|
|
`${name} ${version}\nPublicado: ${publicado}\nCommit: ${commit ?? '(sin git)'}\nNode de la publicación: ${process.version}\nSistema: ${process.platform}\n`,
|
|
);
|
|
|
|
console.log(`\nListo: ${destino} (${tamano(destino)})`);
|
|
console.log(`Versión ${version} · commit ${commit ?? '(sin git)'}`);
|
|
if (commit?.endsWith('-modificado')) console.log('Atención: había cambios sin commit; el release no corresponde exactamente a ese commit.');
|
|
console.log('Siguiente paso: copie esa carpeta al servidor y siga DEPLOY.md.');
|