Publicar un script bash como un paquete NPM

Fabian Zamudio

El propósito de este post es no simplemente publicar un paquete sin sentido en npm, sino aprovechar y crear uno con funcionalidades globales para automatizar tareas cotidianas. Puedes encontrar el proyecto base en mi repositorio de github https://github.com/zamudio-fabian/npm-script-bash.

 

¿Qué es NPM?

Antes de comenzar vamos a asentar las bases y entender un poco más el contexto. NPM es un administrador de paquetes para NodeJS el cual fue creado en 2009 como un proyecto de código abierto para ayudar a los desarrolladores de a compartir fácilmente el código en forma de paquetes. Ya se han publicado miles de paquetes en el registro de NPM lo que lo hace un lugar confiable para compartir nuestros conocimientos.
 


Primeros pasos 

Los requisitos para alcanzar nuestro objetivo son simples, primero se necesita tener instalado npm en nuestro equipo ya que nos provee de los comandos para publicar y probar nuestro código (más información sobre su instalación en https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). Como siguiente paso vamos a necesitar nuestra propia cuenta en el registry NPM lo cual podemos lograrlo completando los datos en el siguiente link https://www.npmjs.com/signup. ES momento de conectar nuestro equipo con el registry NPM para lo cual se debe ejecutar el siguiente comando y contestar con los datos correctos las preguntas que nos hara.

# Log in to NPM registry
npm login 

# Corroborar que estemos correctamente logeados
npm whoami


Una vez completados los pasos anteriores estamos listos para crear nuestro proyecto y gracias a npm nos ahorramos mucho tiempo con su automatización, para eso seguiremos estos pasos:
 

# Cramos la carpeta para nuestro proyecto
mkdir zamu-utils 

# Cambiamos el directorio
cd zamu-utils     

# Inicializamos nuestro paquete npm (nos hara una seguidilla de preguntas sobre la configuración)
npm init

 

Let´s do it  

En esta ocasión nos vamos a diferenciar del resto de los artículos que puedes encontrar, en que nuestro paquete npm debe ser usado de forma global y requiere algunas configuraciones especiales. Lo que finalmente automatice este paquete queda a total libertad del lector, algunos ejemplos de lo se puede realizar son:

  1. Realizar backups de motores de base de datos
  2. Conectarse a AWS
  3. Comenzar tareas en instancias de servidores

 

Como mencione anteriormente este tipo de paquete requiere ciertas configuraciones que no son comunes y a pesar de ser pocas son criticas hacerlas correctamente. 

Nuestro componente principal es el archivo cli.js el cual contiene la lógica para buscar el comportamiento adecuado de cada uno de los comandos disponibles. El comportamiento de cada comando debe estar alojado dentro de la carpeta commands/{nombreDelCommando} y dentro un archivo llamado command.sh, ej: commands/help/command.sh

cli.js

#!/usr/bin/env node
const fs = require('fs');
const shell = require('shelljs');
const pjson = require('./package.json');
const [, , ...args] = process.argv;

function getParamsStringFromArgs(argsAux) {
    let params = '';
    argsAux.map((param) => {
        params += `${param} `;
        return params;
    });
    return params;
}

function execBash(pathCommand, options = []) {
    options.shift();
    const params = getParamsStringFromArgs(options);
    const command = `bash ${pathCommand} ${params}`;
    shell.exec(command);
}

try {
    console.log(`qr-utils v${pjson.version}`);
    const action = args[0];
    let actionFileName = 'help';
    switch (action) {
        case 'date':
        case 'd':
            actionFileName = 'date';
            break;
        case 'help':
        case 'h':
        default:
            actionFileName = 'help';
            break;
    }
    if (
        args.length >= 1 &&
        fs.existsSync(`${__dirname}/commands/${actionFileName}`)
    ) {
        execBash(
            `${__dirname}/commands/${actionFileName}/command.sh`,
            args
        );
    } else {
        execBash(`${__dirname}/commands/help/command.sh`);
    }
} catch (err) {
    console.error(err);
}


Para finalizar deberemos configurar el archivo package.js como vemos en el siguiente ejemplo

package.js

{

    ...
	"main": "cli.js",
	"name": "zamu-utils",
	"bin": {
		"zamu": "cli.js"
	},
	...
}

 

Testing & publishing  

Antes de publicar el paquete y en futuras entregas debemos probar el correcto funcionamiento. Para esto npm nos probé un comando para instalar nuestro paquete de forma local simulando una instalación.
 

# Instalamos de forma local (se debe estar dentro del proyecto)
sudo npm link

# Ejecutamos nuestra paquete
zamu help

 

Una vez conforme con nuestros resultados no queda más que publicarlo en el registry NPM.

# Publicando el paquete (se debe estar dentro del proyecto)
npm publish

Es importante que cada vez que publiquemos cambios en nuestro paquete aumentemos la versión del mismo.
 

  • npm
  • package
WRITTEN BY

Software Developer. Follow me: LinkedIn @fabian-zamudio-dev | Github @zamudio-fabian | Twitter @fabian_zamudio