Maratón Behind the Code Latinoamérica: Sé parte del Desafío. Inscríbete antes del 7 de Setiembre.

Cómo automatizar el versionado al lanzamiento de módulos npm privados con Travis CI

Presence Insights: Contexto

IBM Presence Insights está formado por casi 30 bibliotecas e itera durante un ciclo de dos semanas. Durante ese ciclo de dos semanas, la ramificación predeterminada de esas bibliotecas cambia rápidamente a medida que varios equipos entregarán funciones. Debido a que dependemos de npm para desplegar esas bibliotecas al entorno de preparación, manejar esto de forma tradicional provocaría que muchas versiones se cortasen durante cada ciclo de desarrollo, y la mayor parte de ellas serían poco importantes o extremadamente pequeñas. Esto causaba un historial de versiones excesivamente complicado que era difícil de analizar cuando surgían las regresiones.

A través de etiquetas de distribución de npm, se pueden establecer y gestionar varios flujos de desarrollo sin complicar el historial de versionado de la biblioteca. Las etiquetas de distribución son objetivos instalados correctamente, lo que significa que una etiqueta de distribución llamada inestable podría ser instalada con npm a través de npm install @pi/library@unstable. Esto también significa que es un objetivo válido para un package.json.

Cuando se entrega código a alguna ramificación durante la iteración y este pasa las pruebas de regresión, Travis CI crea una versión basada en la versión («más reciente») actual. La versión más reciente contiene metadatos adicionales, entre ellos, el nombre de la rama y un sello temporal. Esta versión se publica bajo una etiqueta que se basa en el nombre de la ramificación.

Recursos

Esta automatización se maneja a través de:

  • travis.yml
  • package.json
  • @pidev/publish

.travis.yml

La utilización de Travis.yaml desde el registrador de PI controla la configuración de la ejecución de la construcción de Travis en la entrega del código. Aquí tiene un ejemplo:


            deploy:
                provider: script
                script: npm run travis‑publish
                skip_cleanup: true
                on:
                    all_branches: true
                    node: '0.12'
                    tags: false

Este bloque declara que el despliegue se gestiona mediante un script que proporcionamos a través de npm run travis-publish. on:d se utiliza para definir los módulos a publicar. Debido a que queremos gestionar las versiones antes de su lanzamiento, publicamos desde todas las ramas y no publicamos las etiquetas activas (el script envía las etiquetas activas al final de cada iteración). skip_cleanup está activo porque nuestro script personalizado para la publicación depende de algunas dependencias de Node.

package.json

Define lo que npm run travis-publish significa. Un ejemplo de package.json del registrador Presence Insights es:

"travis-publish": "publish npm --platform travis"

«publish» es una CLI escrita en Node y que se especifica como dependencia de desarrollo (dev):

"@pidev/publish": "0.x"

@pidev/publish

Define la lógica personalizada para nuestros despliegues, lo que incluye el empedrado de metadatos del nombre de la marca y del sello temporal. Es una sencilla CLI del nodo commander + shelljs que expone un comando para publicar en npm a través de publish npm. Cuando --platform travis está presente, se utiliza una rutina que accede a variables de entorno de Travis.

Para Presence Insights, llamamos al entorno de preparación YS1-dev. Cuando se enviaron los cambios a la rama predeterminada, la etiqueta que se utilizó fue dev para coincidir con el nombre del área de preparación. Para otros equipos o situaciones, se recomienda utilizar rc para dejar claro que todas las cosas de la rama predeterminada son candidatas hacerla a ser lanzadas.

// cambiar la rama maestra, principal flujo de desarrollo
if (branch === 'master') {
    sh.echo(ch.blue('creating dev version and publishing'));
    version += '‑dev‑' + moment().tz('America/New_york').format('YYYYMMDD‑HHmm');
    tag = 'dev';
}

La versión se crea desde la etiqueta de distribución, y la zona horaria se hace en el formato YYYYMMDD-HHmm. Por ejemplo: @pilib/logger@1.0.5-dev-20160416-0945.

Resultado de ejemplo de una ejecución de una construcción en Travis:

creando versión de dev y publicándola
exec npm version 1.2.11‑dev‑20160421‑1754
v1.2.11‑dev‑20160421‑1754
exec npm dist‑tag add @pilib/logger@1.2.11‑dev‑20160421‑1754 dev
+dev: @pilib/logger@1.2.11‑dev‑20160421‑1754
exec npm publish ‑‑tag dev
+ @pilib/logger@1.2.11‑dev‑20160421‑1754

Si no es la rama predeterminada, hacemos una pequeña normalización para asegurarnos de que se puede utilizar el nombre de la marca de forma segura en los metadatos de la versión.

  • Eliminar /
  • Reemplazar _ con –
  • Use normalize()



else {
    // si no es una rama maestra, es una rama de funciones, crear la etiqueta de distribución para la función
    // en base al nombre de la rama y publicar en la misma.
    sh.echo(ch.blue('creando una versión de función y publicándola'));

    var normalizedBranch = branch.split('/').join('‑');
    normalizedBranch = normalizedBranch.split('_').join('‑');
    normalizedBranch = normalizedBranch.normalize();

    sh.echo(ch.green(normalizedBranch) + ' es la etiqueta de distribución para esta función');
    version += '‑' + normalizedBranch + '‑' + moment().tz('America/New_york').format('YYYYMMDD‑HHmm');
    tag = normalizedBranch;
}

En este escenario, una rama llamada feature/geofences_39284 (donde 39284 es el id del elemento de trabajo) es normalizada creando la etiqueta feature-geofences-39284, con una versión completa de @pilib/logger@1.0.5-feature-geofences-39284-20160416-0945, por ejemplo. Esta versión está disponible a través de instalar npm install @pilib/logger@feature-geofences-39284.

Después de analizar sintácticamente la información y de unir nuestra etiqueta y la cadena de caracteres de la versión previa al lanzamiento, publicamos en npm sin actualizar la etiqueta latest.

// salir de forma adecuada si la versión falla
if (sh.exec('npm version ' + version).code !== 0) {
    sh.exit(1);
}

// salir de forma adecuada si falla la incorporación de la etiqueta de distribución
if (sh.exec('npm dist‑tag add ' + scope + '/' + name + '@' + version + ' ' + tag).code !== 0) {
    sh.exit(1);
}

// salir de forma adecuada si publicación falla
if (sh.exec('npm publish ‑‑tag ' + tag).code !== 0) {
    sh.exit(1);
}

Primero, corte la versión que hemos creado. Añada dist-tag explícitamente si esta es la primera vez, después, publique con el indicador --tag para decir a npm que no actualice la versión más reciente.

Con eso, el código enviado está disponible para entornos locales y de preparación a través de la etiqueta de distribución creada. Los proyectos que especifiquen dev como la versión para las dependencias privadas de Presence Insights recogerán automáticamente los cambios para la rama predeterminada a través de la iteración. Los proyectos que especifiquen versiones de funciones recogerán los cambios para esa rama.

Siguientes pasos

  1. Adelgazar @pidev/publish actualmente depende de cosas como moment-timezone, pero la zona horaria sólo se necesita una vez. También utiliza el comandante, que es una infraestructura algo grande. Es posible adelgazar @pidev/publish para que sólo dependa de shelljs, yargsy chalk.
  2. Parametrizar la rama predeterminada y la etiqueta que la representa en @pidev/publish. Utilizamos la rama maestra para nuestra rama predeterminada, pero el nombre de nuestro entorno de preparación es dev, así que esto es algo confuso. Cambie el nombre de dev a preparación o rc.

Conclusión

En este artículo, aprendió cómo automatizar la gestión de versiones previa al lanzamiento mediante la combinación de etiquetas de distribución npm con Travis CI. Las versiones previas al lanzamiento pueden ser una potente herramienta para permitir tener comentarios rápidos en entornos desplegados mientras se mantiene un historial de versiones conciso y fácil de entender, y también permite trabajar de forma iterativa para tener una única versión más fácilmente.