Módulo 3: Exportar, normalizar y estructurar el repositorio

7. Automatizar la exportación con un script

Descripción

Al terminar esta lección vas a poder ejecutar todo el trabajo de las lecciones 2 a 5 —exportar los workflows, normalizarlos, renombrarlos y dejarlos en su carpeta— con un solo comando, gracias a un script de shell. Vas a saber cómo está armado ese script, cómo correrlo antes de cada commit, y cómo, si quieres, engancharlo a Git para que se dispare solo. También vas a conocer la alternativa Enterprise —el control de versiones con Git nativo de n8n— y a tener el criterio honesto para decidir cuándo el flujo con script es suficiente y cuándo vale la pena pagar.

Esto importa porque un proceso manual, por bien que lo entiendas, es un proceso que a veces no se hace. Ya lo viste en la lección 1: un respaldo que depende de que te acuerdes de correr cinco comandos, en la práctica, es un respaldo que se salta el día que estás ocupado. Automatizar convierte "recordar hacer cinco cosas en orden" en "correr un comando", y esa diferencia es la que hace que el repo se mantenga al día de verdad, no solo con buenas intenciones. Es el paso que transforma la disciplina en un hábito que no cuesta.

Conexión con el módulo: las lecciones 2, 3 y 4 te enseñaron las piezas —exportar, cuidar los secretos, normalizar—; la 5 y la 6 les dieron forma y documentación. Esta lección junta las piezas mecánicas en una sola máquina: el script export.sh que orquesta el comando de exportación de la lección 2 y el normalizador de la lección 4, dejando el repositorio estructurado como definió la lección 5. Es la penúltima parada: después de esto, en la lección 8 vas a usar este mismo script para producir el entregable del proyecto. El script que escribas aquí es una herramienta que te va a acompañar más allá de la guía.

Recordatorio importante sobre las restricciones de n8n 2.0. A lo largo de esta guía insistimos en que dentro del nodo Code de n8n 2.0 no puedes usar require, ni acceder al sistema de archivos, ni correr comandos del sistema. Nada de eso aplica aquí. El script de esta lección no es un nodo Code: es un script de shell que corre en tu terminal, en tu computadora, fuera de n8n por completo. Ahí tienes acceso total a git, a la CLI de n8n, a jq, a leer y escribir archivos, a todo. La restricción del nodo Code es sobre el código que corre dentro de un workflow; este script vive afuera, y por eso puede hacer lo que un workflow no.

Por qué un script, y qué es exactamente

Hasta ahora, cada vez que quisiste actualizar el repositorio, hiciste una secuencia: exportar con docker exec ... export:workflow, sacar los archivos del contenedor, normalizar cada uno con jq, renombrarlos a nombres legibles. Cinco o seis comandos, en orden, sin equivocarte en ninguno. Funciona, pero tiene dos problemas: es tedioso, y es frágil —un paso que olvidas o inviertes y el resultado sale mal—.

Un script resuelve las dos cosas. Un script no es más que un archivo de texto que contiene una lista de comandos, en orden, para que la máquina los ejecute uno tras otro cuando tú se lo pidas. Es exactamente la misma secuencia que harías a mano, pero escrita una vez y guardada, para no volver a teclearla nunca. Piénsalo como la lista de pasos de una receta: en lugar de recordar de memoria "primero exportar, después normalizar, después renombrar" cada vez, lo escribes una vez en la receta y después solo dices "haz la receta".

El tipo de script que vamos a escribir es un script de shell, o bash script. "Shell" es el nombre del programa que interpreta los comandos que escribes en la terminal —el mismo que entiende cd, ls, git—. Un script de shell es un archivo con esos mismos comandos, que el shell lee y ejecuta de arriba abajo. Si sabes escribir comandos en la terminal, ya sabes casi todo lo necesario para escribir un script: es lo mismo, guardado en un archivo.

Anatomía de un script de shell

Antes de escribir el nuestro, veamos las piezas de las que está hecho cualquier script de shell, porque son pocas y se repiten en todos.

El shebang. La primera línea de un script suele ser esta:

#!/usr/bin/env bash

Se llama shebang (por los símbolos #!), y le dice al sistema con qué programa ejecutar el archivo. Traducido: "para correr esto, usa bash". El /usr/bin/env bash es una forma portable de decir "busca bash donde sea que esté instalado". Sin esta línea, el sistema no sabría que el archivo es un script de bash. Es la etiqueta que dice "esto se lee con bash".

La línea de seguridad. Justo después, esta línea, que parece críptica y es una de las más útiles:

set -euo pipefail

Son tres protecciones juntas que hacen que el script falle temprano y ruidosamente en vez de seguir adelante con un error escondido:

  • -eexit on error: si cualquier comando falla, el script se detiene ahí en vez de continuar. Sin esto, un error en el paso de exportar seguiría al paso de normalizar sobre datos vacíos.
  • -uunset: si usas una variable que no existe (por un typo, por ejemplo), el script se detiene en vez de usar un valor vacío silenciosamente.
  • -o pipefail — si encadenas comandos con | (tubería) y uno del medio falla, todo el encadenado se considera fallido, en vez de que el error se pierda.

La analogía: es el cinturón de seguridad del script. No cambia lo que hace cuando todo va bien, pero cuando algo sale mal, te frena de golpe en vez de dejarte seguir hacia el choque. Ponlo en todos tus scripts.

Las variables. Guardar un valor con un nombre para reutilizarlo:

CONTAINER="n8n"
OUT_DIR="./workflows"

Se asignan sin espacios alrededor del =, y se usan con un $ delante: $CONTAINER, $OUT_DIR. Sirven para no repetir el mismo valor por todo el script y para poder cambiarlo en un solo lugar. Si mañana tu contenedor se llama distinto, cambias una línea y no diez.

Los comandos y los bucles. El resto del script son los comandos que ya conoces —docker exec, jq, mkdir— más, cuando hace falta repetir algo para varios archivos, un bucle for que dice "para cada archivo de esta carpeta, haz esto". Lo vemos en el ejemplo.

Con estas piezas ya puedes leer cualquier script de shell. Ahora escribamos el nuestro.

El script export.sh

Este es el corazón de la lección: un script que hace, de una pasada, todo el trabajo de exportar y normalizar el repositorio de Cumbre. Va en scripts/export.sh, el lugar que la lección 5 le reservó.

#!/usr/bin/env bash
# export.sh — exporta, normaliza y deja el repo cumbre-automations listo para commit.
# Corre en tu terminal, FUERA de n8n. Requiere: docker, jq.
set -euo pipefail

# --- Configuración (ajusta a tu instancia) ---
CONTAINER="n8n"                          # nombre del contenedor (míralo con: docker ps)
OUT_DIR="./workflows"                    # carpeta final, versionada
RAW_DIR="./.export-raw"                  # carpeta temporal para el crudo (se borra al final)
IN_CONTAINER="/tmp/wf-export"            # dónde exporta la CLI dentro del contenedor

# Campos volátiles que quitamos para diffs limpios (lección 4).
VOLATILE='del(.pinData, .versionId, .active, .triggerCount, .meta.instanceId)'

# --- Paso 1: exportar todos los workflows dentro del contenedor ---
echo "1/4  Exportando workflows..."
rm -rf "$RAW_DIR" && mkdir -p "$RAW_DIR"
docker exec -u node "$CONTAINER" n8n export:workflow --all --separate --pretty --output="$IN_CONTAINER"

# --- Paso 2: traer los archivos del contenedor a tu máquina ---
echo "2/4  Copiando desde el contenedor..."
docker cp "$CONTAINER:$IN_CONTAINER/." "$RAW_DIR/"

# --- Paso 3: normalizar y renombrar cada uno a su nombre legible ---
echo "3/4  Normalizando y renombrando..."
mkdir -p "$OUT_DIR"
for f in "$RAW_DIR"/*.json; do
  name=$(jq -r '.name' "$f")             # lee el nombre real del workflow desde el JSON
  slug=$(echo "$name" | tr '[:upper:] ' '[:lower:]-')   # a minúsculas; espacios -> guiones
  jq -S "$VOLATILE" "$f" > "$OUT_DIR/$slug.json"         # normaliza y escribe con nombre legible
  echo "     - $slug.json"
done

# --- Paso 4: limpiar el temporal ---
echo "4/4  Limpiando..."
rm -rf "$RAW_DIR"

echo "Listo. Revisa el resultado con:  git status  y  git diff"

Vamos a leerlo por bloques, porque cada uno es una lección anterior convertida en código:

La configuración. Las cuatro variables de arriba juntan en un solo lugar todo lo que cambia entre máquinas: el nombre del contenedor, las carpetas. Si tu instancia se llama distinto, tocas una línea. La variable VOLATILE guarda el filtro de jq de la lección 4 —los mismos cinco campos que quitamos— para no repetirlo.

El paso 1 es el comando de exportación de la lección 2: docker export:workflow --all --separate --pretty. Fíjate en un cambio respecto de cuando lo corrías a mano: aquí es docker exec -u node sin el -it. Recuerda de la lección 2 que -it daba una terminal interactiva; en un script, que corre solo sin nadie tecleando, no queremos terminal interactiva, así que la quitamos. El -u node se queda, porque los permisos siguen importando. Exporta dentro del contenedor, a /tmp/wf-export.

El paso 2 resuelve el detalle de Docker de la lección 2 —los archivos caen dentro del contenedor— con docker cp, que los trae a tu máquina, a la carpeta temporal .export-raw.

El paso 3 es el más denso, y es la lección 4 más la 5 juntas. El bucle for f in "$RAW_DIR"/*.json dice "para cada archivo .json de la carpeta cruda, llámalo f y haz lo siguiente". Adentro, tres cosas: lee el nombre real del workflow con jq -r '.name' (el -r da el texto sin comillas); lo convierte a un slug legible en kebab-case con tr (minúsculas, espacios a guiones); y normaliza con jq -S "$VOLATILE" escribiendo el resultado directo a workflows/<slug>.json. En una sola pasada, cada workflow queda normalizado y con nombre legible. Aquí desaparece el problema de los nombres feos de id de la lección 5: el script lee el nombre de adentro del JSON y lo usa.

El paso 4 borra el temporal, para no dejar basura.

Fíjate en la elegancia de lo que logramos: seis líneas de comandos que a mano eran una sesión entera de trabajo, ahora corren solas y siempre igual. El script es la reproducibilidad de la lección 1 hecha realidad.

Hacerlo ejecutable y correrlo

Un script recién creado es solo un archivo de texto; hay que darle permiso de ejecución para que el sistema lo trate como un programa:

chmod +x scripts/export.sh

chmod +x significa "hazlo ejecutable" (execute). Es un paso de una sola vez: una vez marcado, queda así. Después lo corres:

./scripts/export.sh

El ./ delante le dice al shell "el script está aquí, en esta carpeta". Un detalle que confunde: las rutas dentro del script (./workflows, ./.export-raw) son relativas a dónde estás parado cuando lo corres, no a dónde vive el script. Así que córrelo siempre desde la raíz del repositorio (cumbre-automations), no desde dentro de scripts/. Si lo corres desde otro lado, las carpetas van a caer donde no esperas. Un script más avanzado se ancla a su propia ubicación para no depender de esto, pero para empezar, la regla simple —"corre desde la raíz del repo"— basta. Qué esperar: la terminal imprime los cuatro pasos con sus mensajes —1/4 Exportando..., y al final la lista de archivos escritos y Listo—, y tu carpeta workflows/ queda con los workflows normalizados y bien nombrados. Ahora corres git status y git diff para revisar qué cambió, y commiteas tú, con calma, lo que quieras. El script prepara; tú decides qué entra a la historia.

Un script que avisa si le falta algo

El export.sh de arriba supone que docker y jq están instalados. Si no lo están, el script va a fallar a mitad de camino con un error confuso —"command not found"— que no le dice al usuario qué instalar. Un buen script revisa sus dependencias al principio y avisa claro si falta algo, en vez de estrellarse a la mitad. Es un gesto de cortesía con quien lo corra, incluido tú en seis meses. Se agrega justo después del set -euo pipefail:

# --- Verificación de dependencias ---
for cmd in docker jq; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "Error: falta '$cmd'. Instálalo antes de correr este script." >&2
    exit 1
  fi
done

Léelo: para cada herramienta que el script necesita (docker, jq), command -v "$cmd" pregunta "¿existe este comando?". Si no existe (el ! invierte la respuesta), imprime un error claro que nombra qué falta —el >&2 manda el mensaje al canal de errores, la convención para mensajes que no son la salida normal— y exit 1 detiene el script de inmediato. El 1 es un código de salida distinto de cero, que por convención significa "terminé mal"; un 0 significaría "todo bien".

La diferencia entre un script con esta verificación y uno sin ella es la diferencia entre un error que dice "falta jq, instálalo" y uno que dice "línea 23: jq: command not found" en medio de una ejecución a medias. El primero se arregla en un minuto; el segundo manda a la gente a buscar en internet. Anticipar el tropiezo y avisar claro es la misma voz de las guías de instalación, aplicada al código.

Correrlo antes de cada commit: a mano o con un hook

La disciplina que este script habilita es simple: antes de commitear un cambio de workflow, corre export.sh. Editas en el editor de n8n, corres el script, revisas el diff, commiteas. Así el repositorio siempre refleja el estado real de la instancia, normalizado y limpio.

Hay dos formas de asegurar que ese "antes de cada commit" ocurra.

Forma 1 — a mano, como un hábito. Simplemente lo corres tú antes de commitear. Es lo más simple, lo más transparente, y lo que recomiendo para empezar. El costo: depende de que te acuerdes. La ventaja: control total, ninguna sorpresa.

Forma 2 — un git hook pre-commit. Git permite disparar un script automáticamente en ciertos momentos; a esos disparadores se les llama hooks (ganchos). El hook pre-commit corre justo antes de que un commit se complete. Si pones tu script ahí, se ejecuta solo cada vez que commiteas. Vive en un archivo .git/hooks/pre-commit:

#!/usr/bin/env bash
# .git/hooks/pre-commit — re-exporta y normaliza antes de cada commit.
./scripts/export.sh
git add workflows/

(También hay que hacerlo ejecutable con chmod +x .git/hooks/pre-commit.)

Suena ideal, pero tiene dos trampas que debes conocer antes de adoptarlo, porque no las cuenta cualquiera:

Trampa 1: los hooks no se versionan. La carpeta .git/hooks/ vive dentro de .git/, que Git no versiona —es la maquinaria interna del repo, no su contenido—. Eso significa que tu hook existe solo en tu máquina; si un compañero clona el repo, no lo tiene. Para compartir hooks en un equipo hay herramientas (como configurar core.hooksPath a una carpeta versionada, o usar un gestor de hooks), pero es complejidad extra que conviene sopesar.

Trampa 2: re-exportar en el commit puede traer sorpresas. El hook re-exporta desde la instancia viva en el momento del commit. Si entre que editaste y que commiteas alguien más tocó otro workflow en la instancia, el hook lo va a arrastrar a tu commit sin que lo esperes. Es sutil y confunde.

Por eso mi recomendación honesta es: empieza con la Forma 1, a mano. Corre el script como un paso deliberado y consciente, no como magia que ocurre a tus espaldas. El hook automático es una optimización que tiene sentido cuando el flujo ya está aceitado y entiendes bien sus trampas, no antes.

La alternativa cómoda: un Makefile o un script de npm

Escribir ./scripts/export.sh no es difícil, pero hay formas de darle un nombre aún más corto y memorable, sobre todo si el repo va a tener varios scripts.

Un Makefile. make es una herramienta veterana que ejecuta "objetivos" con nombre definidos en un archivo Makefile. Con esto en la raíz:

export:
	./scripts/export.sh

.PHONY: export

corres el script con solo make export. (La línea del comando lleva una tabulación al inicio, no espacios —make es estricto con eso—; y .PHONY le dice a make que export es una acción, no un archivo que produce.)

Un script de npm. Si tu proyecto ya usa Node, puedes definir el script en package.json:

{
  "scripts": {
    "export": "./scripts/export.sh"
  }
}

y correrlo con npm run export. La ventaja de estas dos formas es que dan un vocabulario uniforme —make export, make normalize, make check— fácil de recordar y de documentar en el README. No cambian lo que hace el script; le ponen una manija más cómoda. Para Cumbre, con un solo script, correrlo directo con ./scripts/export.sh es perfectamente suficiente; el Makefile empieza a pagar cuando tienes tres o cuatro tareas repetidas.

La alternativa Enterprise: Git nativo de n8n

Todo lo que hemos construido en este módulo —exportar por CLI, normalizar, estructurar, automatizar con un script— logra el resultado del mercado, "version-controlled, documented JSON", usando solo la edición Community, gratis y self-hosted. Pero hay que ser honestos: n8n ofrece una función que hace parte de esto sin que escribas un solo comando, y vive en el plan Enterprise.

Se llama control de versiones con Git (el "environments / source control" de n8n). Conecta tu instancia directamente a un repositorio de Git y te deja empujar (push) y traer (pull) los workflows desde la propia interfaz de n8n, con botones. La instancia sabe hablar con Git nativamente: no hay CLI, no hay script, no hay docker cp. Es más cómodo, y está pensado para equipos que promueven cambios entre entornos con frecuencia.

La pregunta honesta es: ¿cuándo vale pagarla? Aquí el criterio, sin marketing en ninguna dirección:

SituaciónQué conviene
Estás aprendiendo, o es un proyecto personal / de un cliente chicoFlujo CLI + script. Gratis, y produces exactamente el mismo artefacto: JSON versionado, normalizado y documentado.
Un equipo pequeño, cambios ocasionales, presupuesto ajustadoFlujo CLI + script. El script automatiza lo tedioso; la comodidad extra de Enterprise no justifica el costo todavía.
Un equipo que promueve cambios entre dev/staging/prod a diario, con muchas personasConsidera Enterprise. Cuando la fricción de coordinar exportaciones manuales entre varias personas supera el costo de la licencia, el Git nativo se paga solo en tiempo ahorrado.
Requisitos de auditoría, control de acceso fino, cumplimientoEvalúa Enterprise. Trae garantías que el flujo manual no da por sí solo.

La conclusión no es "el flujo CLI es de pobres" ni "Enterprise es un lujo innecesario". Es que los dos producen el mismo entregable, y la diferencia es comodidad y escala, no capacidad. Sabiendo hacer el flujo con script, entiendes exactamente qué hace el Git nativo por dentro —y esa comprensión te sirve tanto si nunca pagas Enterprise como si algún día lo administras—. El Módulo 6 vuelve sobre esta decisión con más detalle, ya con la promoción entre entornos sobre la mesa.

Errores comunes

Confundir el script de shell con un nodo Code y no usar herramientas del sistema (conceptual). Qué pasa: alguien, condicionado por las restricciones del nodo Code de n8n 2.0, evita usar docker, jq o leer archivos en su export.sh, creyendo que están prohibidos. Por qué pasa: la guía insiste tanto en las restricciones del nodo Code que es fácil creerlas universales. Cómo detectarlo: si estás limitando lo que tu script puede hacer "por si acaso", revisa dónde corre. Cómo corregirlo: el script corre en tu terminal, fuera de n8n; ahí tienes acceso total al sistema. Las restricciones del nodo Code son solo para el código dentro de un workflow. Usa las herramientas del sistema con libertad.

Olvidar chmod +x y toparse con "permission denied" (práctico). Qué pasa: escribes el script, corres ./scripts/export.sh y el sistema responde "permission denied". Por qué pasa: un archivo recién creado no tiene permiso de ejecución; el sistema no lo trata como programa hasta que se lo das. Cómo detectarlo: el mensaje "permission denied" al correr un script propio casi siempre es esto. Cómo corregirlo: chmod +x scripts/export.sh una sola vez, y listo. Es un paso que se olvida seguido las primeras veces y después se vuelve automático.

Escribir la salida sobre la entrada dentro del bucle (práctico). Qué pasa: en el paso de normalizar, alguien hace jq ... "$f" > "$f" —leyendo y escribiendo el mismo archivo— y lo vacía, igual que la trampa de la lección 4. Por qué pasa: es el mismo error de redirección > que vacía el archivo antes de que jq lo lea. Cómo detectarlo: si tras correr el script los archivos quedan vacíos, es esto. Cómo corregirlo: el script escribe a una carpeta distinta ($OUT_DIR) de la que lee ($RAW_DIR), justo para evitarlo. Nunca leas y escribas el mismo archivo en un solo comando; separa entrada y salida.

Adoptar el git hook antes de entender sus trampas (conceptual). Qué pasa: alguien pone el export.sh en un hook pre-commit el primer día, y se desconcierta cuando un commit arrastra cambios de workflows que no tocó, o cuando un compañero que clonó el repo no tiene el hook y su repo se desincroniza. Por qué pasa: el hook suena a "automatización total" y se adopta sin conocer sus dos trampas —no se versiona, y re-exporta el estado vivo—. Cómo detectarlo: si aparecen cambios inesperados en tus commits o si el hook no existe para tu equipo, son las trampas conocidas. Cómo corregirlo: empieza corriendo el script a mano como paso deliberado; adopta el hook solo cuando entiendas y aceptes sus dos limitaciones.

Ejercicios

Ejercicio 1 — Lee el script. Sin correrlo, lee el export.sh de esta lección y responde: (a) ¿qué hace la línea set -euo pipefail y por qué conviene? (b) ¿por qué el script usa docker exec -u node sin -it, a diferencia de cuando lo corrías a mano? (c) ¿de dónde saca el script el nombre legible de cada archivo?

Ver solución

(a) set -euo pipefail hace que el script falle temprano y ruidosamente: -e lo detiene si un comando falla, -u si usas una variable inexistente, -o pipefail si falla un comando en medio de una tubería. Conviene porque evita que un error en el paso de exportar continúe silenciosamente hacia el de normalizar sobre datos vacíos. Es el cinturón de seguridad del script.

(b) Porque -i y -t piden una terminal interactiva, pensada para cuando estás tecleando y viendo la salida. En un script, que corre solo sin nadie al teclado, una terminal interactiva no tiene sentido y puede causar problemas. Se deja -u node porque los permisos sí siguen importando.

(c) Del propio JSON: jq -r '.name' "$f" lee el campo name de dentro de cada archivo exportado, que es el nombre real del workflow en n8n. Después lo convierte a kebab-case con tr. Así resuelve el problema de los nombres feos de id de la lección 5, leyendo el nombre bueno de adentro.

Por qué funciona: si pudiste responder las tres, ya puedes leer un script de shell, que es el 80% de saber escribirlos. Un script no tiene magia: es la misma secuencia de comandos que harías a mano, con un cinturón de seguridad y un bucle para repetir.

Ejercicio 2 — Decide CLI o Enterprise. Para cada caso, di si recomendarías el flujo CLI con script o considerar el Git nativo de Enterprise, y por qué en una frase: (a) tú solo, automatizando los workflows de un cliente pequeño; (b) un equipo de ocho personas promoviendo cambios entre tres entornos varias veces al día; (c) un proyecto personal de aprendizaje.

Ver solución

(a) Flujo CLI + script. Produces el mismo artefacto versionado y documentado, gratis; para un cliente chico, la comodidad de Enterprise no justifica su costo.

(b) Considerar Enterprise. Con ocho personas y promociones diarias entre entornos, la fricción de coordinar exportaciones manuales empieza a costar más que la licencia; ahí el Git nativo se paga en tiempo ahorrado.

(c) Flujo CLI + script, sin dudarlo. Aprendiendo, además, hacer el flujo a mano te enseña qué hace el Git nativo por dentro, un conocimiento que te sirve pagues o no pagues después.

Por qué funciona: la decisión no es de capacidad —los dos producen "documented JSON"— sino de escala y fricción. El criterio es "¿el costo de la licencia es menor que el tiempo que pierdo coordinando a mano?". Para una persona o un equipo chico, casi nunca; para un equipo grande con promociones frecuentes, a veces sí.

Ejercicio 3 — Extiende el script. El export.sh actual exporta y normaliza los workflows, pero no toca las credenciales. Piensa (no hace falta que lo escribas completo) qué NO debería hacer el script respecto de las credenciales, y por qué. ¿Podría el script exportar credenciales con --decrypted para "respaldarlas también"?

Ver solución

El script no debe exportar credenciales al repositorio en ninguna forma, y muchísimo menos con --decrypted. Un script que corre export:credentials --decrypted y deja el resultado en la carpeta del repo estaría escribiendo secretos en texto plano justo donde un git add los atraparía —exactamente el desastre que la lección 3 existe para evitar—. Automatizar un error no lo arregla; lo repite más rápido y más seguido.

Si acaso el script tocara credenciales, sería para un respaldo cifrado (sin --decrypted) escrito fuera del árbol del repositorio, a un destino seguro, y aun así con cuidado. Pero lo más limpio es que el script de exportación de workflows no se meta con credenciales en absoluto: son dos flujos distintos con reglas de seguridad distintas, y mezclarlos invita al accidente. El .gitignore de la lección 3 es la red por si algo se cuela, pero la primera línea de defensa es que el script simplemente no genere secretos dentro del repo.

Por qué funciona: este ejercicio prueba que internalizaste la lección 3 al punto de reconocer un mal patrón de automatización. La automatización amplifica lo que le pongas: amplifica una buena práctica hasta volverla un hábito sin esfuerzo, y amplifica un descuido de seguridad hasta volverlo una filtración sistemática. Por eso el script se diseña con la seguridad como restricción, no como una idea posterior.

Resumen y siguiente paso

En esta lección convertiste el trabajo manual de las lecciones 2 a 5 en un solo comando. Entendiste qué es un script de shell —una lista de comandos guardada, la misma secuencia que harías a mano— y su anatomía: el shebang que dice con qué correrlo, set -euo pipefail como cinturón de seguridad, las variables de configuración y el bucle for. Escribiste export.sh, que verifica sus dependencias y avisa claro si falta alguna, exporta con la CLI de la lección 2, saca los archivos del contenedor con docker cp, y en un bucle normaliza (lección 4) y renombra a nombres legibles leyendo el name de cada JSON (lección 5), todo de una pasada. Lo hiciste ejecutable con chmod +x y lo corriste con ./scripts/export.sh. Viste las dos formas de asegurar que corra antes de cada commit —a mano (recomendada para empezar) o con un git hook pre-commit (con sus dos trampas: no se versiona y re-exporta el estado vivo)—, las manijas cómodas de make y npm run, y la alternativa Enterprise del Git nativo de n8n, con el criterio honesto de cuándo vale pagarla: no es cuestión de capacidad, sino de escala y fricción, porque los dos producen el mismo entregable.

Antes de avanzar deberías poder: explicar por qué el script puede usar docker y jq aunque el nodo Code no; leer el export.sh y decir qué hace cada paso; nombrar las dos trampas del git hook; y decidir entre el flujo CLI y Enterprise según la escala.

La lección 8 es el proyecto que cierra el módulo. Vas a tomar una instancia de n8n con varios workflows y credenciales —la de Cumbre completa— y producir, de punta a punta, el repositorio cumbre-automations: workflows exportados, normalizados y bien nombrados; secretos afuera con un .gitignore correcto; estructura profesional; documentación de handoff; y el export.sh que hace todo reproducible. El entregable es un repositorio que pasaría la revisión de otro desarrollador, que es exactamente lo que las ofertas piden cuando escriben "version-controlled, documented JSON".

Recursos