CI/CD, control de versiones con Git, el build tool Bob, VS Code con Code for i, testing automatizado, estrategias de deploy y el camino hacia una cultura DevOps moderna en el ecosistema IBM i.
DevOps en IBM i significa aplicar las mismas practicas que las organizaciones modernas usan en otras plataformas: control de versiones, builds automatizados, testing continuo y despliegues repetibles. El desafio es adaptar estas practicas a un ecosistema que historicamente ha dependido de PDM/SEU, source physical files y compilaciones manuales.
Flujo tradicional IBM i
Flujo DevOps moderno en IBM i
Plan
Issues en GitHub/GitLab, historias de usuario, sprints con herramientas agiles.
Code
VS Code + Code for i, Git branches, pull requests y code review.
Build & Test
Bob compila, RPGUnit ejecuta tests, pipeline valida calidad.
Deploy
Pipeline mueve objetos a QA/Prod. Rollback automatico si falla.
Code for IBM i es una extension de VS Code que reemplaza a PDM/SEU como entorno de desarrollo principal. Permite editar fuentes en IFS o en source physical files, compilar, depurar y navegar objetos IBM i directamente desde VS Code, con syntax highlighting, autocompletado y terminal integrada.
Instalacion
Extensiones complementarias
// Desde la paleta de comandos (Ctrl+Shift+P): IBM i: Connect to IBM i // Conectar al sistema IBM i: Run Action on Active File // Compilar el archivo actual IBM i: Create New Source Member // Crear miembro en SPF IBM i: Browse Object Browser // Navegar bibliotecas/objetos IBM i: Open Terminal // Abrir terminal PASE SSH // Actions personalizables (compilar desde IFS): // Se configuran en .vscode/actions.json // Shortcut para compilar: Ctrl+E (configurable) // Errores aparecen en la pestana "Problems" de VS Code
[
{
"name": "Compilar RPG (CRTBNDRPG desde IFS)",
"command": "CRTBNDRPG PGM(&CURLIB/&NAME) SRCSTMF('&FULLPATH') DBGVIEW(*SOURCE) OPTION(*SRCSTMT *NODEBUGIO)",
"extensions": ["rpgle", "sqlrpgle"],
"environment": "ile",
"deployFirst": true
},
{
"name": "Compilar CL (CRTBNDCL desde IFS)",
"command": "CRTBNDCL PGM(&CURLIB/&NAME) SRCSTMF('&FULLPATH') DBGVIEW(*SOURCE)",
"extensions": ["clle", "clp"],
"environment": "ile",
"deployFirst": true
},
{
"name": "Compilar Display File",
"command": "CRTDSPF FILE(&CURLIB/&NAME) SRCSTMF('&FULLPATH')",
"extensions": ["dspf"],
"environment": "ile",
"deployFirst": true
},
{
"name": "Compilar SQL Table",
"command": "RUNSQLSTM SRCSTMF('&FULLPATH') COMMIT(*NONE) NAMING(*SQL)",
"extensions": ["sql", "table", "view"],
"environment": "ile",
"deployFirst": true
}
]deployFirst: true esta activo, Code for i automaticamente copia el archivo local al IFS del IBM i antes de compilar. Esto permite trabajar con archivos locales (en tu PC) que se sincronizan al compilar.Bob (Better Object Builder) es una herramienta open source de build para IBM i que funciona como un "make" especializado. Lee archivos de configuracion que definen como compilar cada fuente y ejecuta las compilaciones respetando dependencias. Es la pieza clave para automatizar builds en pipelines CI/CD.
// Bob se instala via yum en PASE $ yum install bob // Verificar instalacion $ makei --version Bob (Better Object Builder) v2.4.2 // Bob se ejecuta con el comando 'makei' // desde el directorio raiz del proyecto $ cd /home/MIUSER/repos/mi-proyecto $ makei build
{
"version": "0.0.1",
"description": "Sistema de Gestion de Clientes",
"objlib": "MILIB",
"curlib": "MILIB",
"includePath": [
"/QSYS.LIB/MILIB.LIB/QRPGLESRC.FILE",
"/home/MIUSER/repos/mi-proyecto/headers"
],
"preUsrlibl": ["MILIB", "UTILLIB"],
"postUsrlibl": ["QTEMP"],
"setIBMiEnvCmd": [],
"repository": "https://github.com/empresa/mi-proyecto",
"license": "MIT"
}# Rules.mk - Reglas de compilacion para Bob
# Este archivo define COMO compilar cada tipo de fuente
# Variables globales
OBJLIB := MILIB
TGTCCSID := *JOB
# Regla para programas RPG (*.rpgle)
%.rpgle:
system -q "CRTBNDRPG PGM($(OBJLIB)/$*) SRCSTMF('$<') DBGVIEW(*SOURCE) OPTION(*SRCSTMT *NODEBUGIO) TGTRLS(*CURRENT)"
# Regla para programas SQL RPG (*.sqlrpgle)
%.sqlrpgle:
system -q "CRTSQLRPGI OBJ($(OBJLIB)/$*) SRCSTMF('$<') DBGVIEW(*SOURCE) OPTION(*SRCSTMT) COMMIT(*NONE)"
# Regla para programas CL (*.clle)
%.clle:
system -q "CRTBNDCL PGM($(OBJLIB)/$*) SRCSTMF('$<') DBGVIEW(*SOURCE)"
# Regla para display files (*.dspf)
%.dspf:
system -q "CRTDSPF FILE($(OBJLIB)/$*) SRCSTMF('$<')"
# Regla para tablas SQL (*.sql)
%.sql:
system -q "RUNSQLSTM SRCSTMF('$<') COMMIT(*NONE) NAMING(*SQL)"
# Regla para service programs
%.rpgle.srvpgm:
system -q "CRTRPGMOD MODULE($(OBJLIB)/$*) SRCSTMF('$<') DBGVIEW(*SOURCE)"
system -q "CRTSRVPGM SRVPGM($(OBJLIB)/$*) MODULE($(OBJLIB)/$*) EXPORT(*ALL)"// Build completo del proyecto $ cd /home/MIUSER/repos/mi-proyecto $ makei build Building GESTCLI.rpgle -> MILIB/GESTCLI *PGM ... OK Building VALCLI.rpgle -> MILIB/VALCLI *PGM ... OK Building CLIENTES.sql -> MILIB/CLIENTES *FILE ... OK Building MENU.dspf -> MILIB/MENU *FILE ... OK Build complete: 4 objects, 0 errors // Build de un objeto especifico $ makei build GESTCLI.rpgle // Build con logging detallado $ makei build -v // Limpiar objetos compilados $ makei clean // Ver que se compilaria sin ejecutar $ makei build --dry-run
Adoptar Git para IBM i requiere definir un flujo de trabajo (workflow) que se adapte a las particularidades de la plataforma: bibliotecas por desarrollador, compilacion en el sistema destino y promover objetos entre entornos.
main (produccion)
|
+-- develop (integracion / QA)
|
+-- feature/nueva-validacion (dev: DEVLIB01)
+-- feature/reporte-ventas (dev: DEVLIB02)
+-- bugfix/calculo-iva (dev: DEVLIB03)
Flujo:
1. Developer crea branch desde 'develop'
2. Trabaja en VS Code, compila en su biblioteca DEVLIB##
3. Hace commits y push al branch
4. Crea Pull Request hacia 'develop'
5. Code review por otro developer
6. Merge a 'develop' -> CI/CD compila en QALIB (QA)
7. QA aprueba -> merge a 'main'
8. CI/CD compila en PRODLIB (produccion)feature/*DEVLIB01-09Desarrollo individualDeveloper manualdevelopQALIBIntegracion y QAPipeline CI/CDrelease/*STGLIBPre-produccion / stagingPipeline CI/CDmainPRODLIBProduccionPipeline CI/CDhotfix/*HFXLIBFix urgente en produccionPipeline CI/CD// 1. Actualizar develop local $ cd /home/MIUSER/repos/mi-proyecto $ git checkout develop $ git pull origin develop // 2. Crear branch de feature $ git checkout -b feature/validacion-email // 3. Editar en VS Code (los archivos estan en IFS) // ... modificar qrpglesrc/gestcli.rpgle ... // 4. Compilar y probar (en biblioteca de desarrollo) $ makei build GESTCLI.rpgle // O desde VS Code: Ctrl+E -> Compilar RPG // 5. Commit y push $ git add qrpglesrc/gestcli.rpgle $ git commit -m "feat(gestcli): agregar validacion de email" $ git push origin feature/validacion-email // 6. Crear Pull Request en GitHub/GitLab // (desde la interfaz web o CLI) $ gh pr create --base develop --title "feat: validacion de email en GESTCLI" --body "Agrega validacion de formato de email..." // 7. Despues del code review, merge a develop $ gh pr merge --squash
Un pipeline CI/CD para IBM i automatiza la secuencia: checkout del codigo, copia al IFS, compilacion con Bob, ejecucion de tests y deploy a la biblioteca destino. Se puede implementar con GitHub Actions, GitLab CI, Jenkins o Azure DevOps, conectandose al IBM i via SSH.
name: IBM i Build & Deploy
on:
push:
branches: [develop, main]
pull_request:
branches: [develop]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout codigo
uses: actions/checkout@v4
- name: Copiar fuentes al IBM i via SSH
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.IBMI_HOST }}
username: ${{ secrets.IBMI_USER }}
key: ${{ secrets.IBMI_SSH_KEY }}
source: "qrpglesrc/,qclsrc/,qddssrc/,qsqlsrc/"
target: "/home/cicd/builds/${{ github.sha }}"
- name: Build con Bob
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.IBMI_HOST }}
username: ${{ secrets.IBMI_USER }}
key: ${{ secrets.IBMI_SSH_KEY }}
script: |
cd /home/cicd/builds/${{ github.sha }}
export PATH=/QOpenSys/pkgs/bin:$PATH
makei build 2>&1
if [ $? -ne 0 ]; then
echo "BUILD FAILED"
exit 1
fi
- name: Ejecutar tests RPGUnit
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.IBMI_HOST }}
username: ${{ secrets.IBMI_USER }}
key: ${{ secrets.IBMI_SSH_KEY }}
script: |
export PATH=/QOpenSys/pkgs/bin:$PATH
system "RUCALLTST TSTPRC(QALIB/TESTGESTCLI)"
system "RUCALLTST TSTPRC(QALIB/TESTVALCLI)"
deploy-qa:
needs: build
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- name: Deploy a QA
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.IBMI_HOST }}
username: ${{ secrets.IBMI_USER }}
key: ${{ secrets.IBMI_SSH_KEY }}
script: |
export PATH=/QOpenSys/pkgs/bin:$PATH
# Copiar objetos de DEVLIB a QALIB
system "CRTDUPOBJ OBJ(GESTCLI) FROMLIB(DEVLIB) OBJTYPE(*PGM) TOLIB(QALIB) NEWOBJ(*SAME) DATA(*YES)"
deploy-prod:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy a Produccion
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.IBMI_HOST }}
username: ${{ secrets.IBMI_USER }}
key: ${{ secrets.IBMI_SSH_KEY }}
script: |
export PATH=/QOpenSys/pkgs/bin:$PATH
# Backup antes de deploy
system "SAVOBJ OBJ(GESTCLI) LIB(PRODLIB) DEV(*SAVF) SAVF(PRODLIB/BKP$(date +%Y%m%d))"
# Deploy
system "CRTDUPOBJ OBJ(GESTCLI) FROMLIB(QALIB) OBJTYPE(*PGM) TOLIB(PRODLIB) NEWOBJ(*SAME) DATA(*YES)"pipeline {
agent any
environment {
IBMI_HOST = credentials('ibmi-host')
IBMI_CREDS = credentials('ibmi-ssh-key')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Sync to IBM i') {
steps {
sh """
rsync -avz --delete \
-e "ssh -i ${IBMI_CREDS}" \
./qrpglesrc/ ./qclsrc/ ./qddssrc/ \
${IBMI_HOST}:/home/cicd/builds/${BUILD_NUMBER}/
"""
}
}
stage('Build') {
steps {
sh """
ssh -i ${IBMI_CREDS} ${IBMI_HOST} \
"cd /home/cicd/builds/${BUILD_NUMBER} && makei build"
"""
}
}
stage('Test') {
steps {
sh """
ssh -i ${IBMI_CREDS} ${IBMI_HOST} \
"system 'RUCALLTST TSTPRC(QALIB/TESTALL)'"
"""
}
}
stage('Deploy QA') {
when { branch 'develop' }
steps {
sh """
ssh -i ${IBMI_CREDS} ${IBMI_HOST} \
"/home/cicd/scripts/deploy.sh QALIB"
"""
}
}
}
}RPGUnit es el framework de testing unitario mas utilizado para RPG. Permite escribir tests automatizados para procedimientos y programas, ejecutarlos desde linea de comandos y generar reportes de resultados para integracion con pipelines CI/CD.
**free
// ---------------------------------------------------------------
// TESTGESTCLI: Tests unitarios para el modulo GESTCLI
// Framework: RPGUnit v3+
// ---------------------------------------------------------------
ctl-opt dftactgrp(*no) actgrp(*caller);
ctl-opt bnddir('RPGUNIT');
/include RPGUNIT/QRPGLESRC,TESTCASE
// Prototipo del programa a testear
dcl-pr altaCliente char(1);
id packed(7:0) const;
nombre varchar(100) const;
email varchar(200) const;
end-pr;
dcl-pr consCliente char(1);
id packed(7:0) const;
nombre varchar(100);
email varchar(200);
end-pr;
// ---------------------------------------------------------------
// Test: Alta de cliente exitosa
// ---------------------------------------------------------------
dcl-proc test_altaCliente_exitosa export;
dcl-s resultado char(1);
resultado = altaCliente(99999 : 'Test User' : 'test@test.com');
aEqual('S' : resultado : 'Alta deberia retornar S');
end-proc;
// ---------------------------------------------------------------
// Test: Consulta de cliente existente
// ---------------------------------------------------------------
dcl-proc test_consultaCliente_existe export;
dcl-s resultado char(1);
dcl-s nombre varchar(100);
dcl-s email varchar(200);
// Primero crear el cliente de prueba
altaCliente(99998 : 'Consulta Test' : 'consulta@test.com');
// Consultar
resultado = consCliente(99998 : nombre : email);
aEqual('S' : resultado : 'Consulta deberia retornar S');
aEqual('Consulta Test' : %trim(nombre) : 'Nombre incorrecto');
aEqual('consulta@test.com' : %trim(email) : 'Email incorrecto');
end-proc;
// ---------------------------------------------------------------
// Test: Consulta de cliente inexistente
// ---------------------------------------------------------------
dcl-proc test_consultaCliente_noExiste export;
dcl-s resultado char(1);
dcl-s nombre varchar(100);
dcl-s email varchar(200);
resultado = consCliente(00001 : nombre : email);
aEqual('N' : resultado : 'Consulta no existente debe dar N');
end-proc;
// ---------------------------------------------------------------
// Cleanup: eliminar datos de prueba
// ---------------------------------------------------------------
dcl-proc tearDown export;
exec sql DELETE FROM MILIB.CLIENTES
WHERE CLI_ID IN (99999, 99998);
end-proc;// Compilar el test
CRTBNDRPG PGM(QALIB/TESTGESTCLI)
SRCSTMF('/home/dev/repos/tests/testgestcli.rpgle')
BNDDIR(RPGUNIT)
DBGVIEW(*SOURCE)
// Ejecutar todos los tests de un programa
RUCALLTST TSTPRC(QALIB/TESTGESTCLI)
// Ejecutar un test especifico
RUCALLTST TSTPRC(QALIB/TESTGESTCLI)
TSTPRC(test_altaCliente_exitosa)
// Ver resultados en formato texto
RUCALLTST TSTPRC(QALIB/TESTGESTCLI) OUTPUT(*PRINT)
// Ejecutar todos los tests del proyecto
RUCALLTST TSTPRC(QALIB/TESTGESTCLI)
RUCALLTST TSTPRC(QALIB/TESTVALCLI)
RUCALLTST TSTPRC(QALIB/TESTREPORTES)aEqualVerifica que dos valores alfanumericos son iguales
iEqualVerifica que dos valores enteros son iguales
nEqualVerifica que dos valores numericos (packed/zoned) son iguales
assertVerifica que una condicion booleana es verdadera
failFuerza la falla del test con un mensaje personalizado
assertJobLogContainsVerifica que el job log contiene un mensaje
El despliegue en IBM i tipicamente involucra mover objetos compilados entre bibliotecas (DEV, QA, PROD). Un buen pipeline automatiza este proceso y agrega validaciones, backups y la posibilidad de rollback.
#!/QOpenSys/pkgs/bin/bash
# deploy.sh - Script de deploy para pipeline CI/CD
# Uso: ./deploy.sh FROMLIB TOLIB [objetos...]
FROMLIB=$1
TOLIB=$2
shift 2
OBJETOS=("$@")
FECHA=$(date +%Y%m%d_%H%M%S)
LOGFILE="/home/cicd/logs/deploy_${FECHA}.log"
SAVF="${TOLIB}/BKP${FECHA}"
echo "=== Deploy: ${FROMLIB} -> ${TOLIB} ===" | tee $LOGFILE
echo "Fecha: ${FECHA}" | tee -a $LOGFILE
# 1. Crear save file de backup
system "CRTSAVF FILE(${SAVF})" 2>/dev/null
# 2. Backup de objetos existentes en destino
for OBJ in "${OBJETOS[@]}"; do
OBJ_NAME=$(echo $OBJ | cut -d. -f1)
OBJ_TYPE=$(echo $OBJ | cut -d. -f2)
echo "Backup: ${TOLIB}/${OBJ_NAME} *${OBJ_TYPE}" | tee -a $LOGFILE
system "SAVOBJ OBJ(${OBJ_NAME}) LIB(${TOLIB}) \
DEV(*SAVF) SAVF(${SAVF}) \
OBJTYPE(*${OBJ_TYPE})" 2>&1 | tee -a $LOGFILE
done
# 3. Copiar objetos nuevos al destino
for OBJ in "${OBJETOS[@]}"; do
OBJ_NAME=$(echo $OBJ | cut -d. -f1)
OBJ_TYPE=$(echo $OBJ | cut -d. -f2)
echo "Deploy: ${OBJ_NAME} *${OBJ_TYPE}" | tee -a $LOGFILE
system "CRTDUPOBJ OBJ(${OBJ_NAME}) FROMLIB(${FROMLIB}) \
OBJTYPE(*${OBJ_TYPE}) TOLIB(${TOLIB}) \
NEWOBJ(*SAME) DATA(*YES)" 2>&1 | tee -a $LOGFILE
if [ $? -ne 0 ]; then
echo "ERROR en deploy de ${OBJ_NAME}" | tee -a $LOGFILE
echo "Iniciando rollback..." | tee -a $LOGFILE
# Rollback desde backup
system "RSTOBJ OBJ(*ALL) SAVLIB(${TOLIB}) \
DEV(*SAVF) SAVF(${SAVF})" 2>&1 | tee -a $LOGFILE
exit 1
fi
done
echo "=== Deploy completado exitosamente ===" | tee -a $LOGFILEDEVLIB01-09Manual (cada developer compila en su lib)INTLIBMerge a develop (pipeline automatico)QALIBPipeline CI/CD tras build exitosoSTGLIBRelease branch o tagPRODLIBMerge a main (con aprobacion)Un iProject es la forma estandar de organizar fuentes IBM i en el IFS para que herramientas como Bob, Code for i y pipelines CI/CD puedan trabajar de forma consistente. La estructura sigue convenciones que mapean directorios a tipos de fuente IBM i.
mi-proyecto/
|-- iproj.json # Configuracion del proyecto
|-- Rules.mk # Reglas de compilacion Bob
|-- .gitignore # Archivos a ignorar en Git
|-- .vscode/
| |-- actions.json # Acciones de compilacion VS Code
| +-- settings.json # Config Code for i
|-- qrpglesrc/ # Fuentes RPG IV
| |-- gestcli.rpgle
| |-- valcli.rpgle
| +-- utillib.rpgle
|-- qsqlrpgle/ # Fuentes SQL RPG
| +-- rptventas.sqlrpgle
|-- qclsrc/ # Fuentes CL
| |-- strsys.clle
| +-- bkplib.clle
|-- qddssrc/ # Display files y printer files
| |-- menuppal.dspf
| +-- rptcli.prtf
|-- qsqlsrc/ # Scripts SQL (DDL)
| |-- clientes.sql
| +-- pedidos.sql
|-- qcmdsrc/ # Definiciones de comandos
| +-- gestcli.cmd
|-- qsrvsrc/ # Binder source (service programs)
| +-- utillib.bnd
|-- headers/ # Copy files / includes
| |-- constantes.rpgleinc
| +-- prototipos.rpgleinc
|-- tests/ # Tests RPGUnit
| |-- testgestcli.rpgle
| +-- testvalcli.rpgle
|-- scripts/ # Scripts de automatizacion
| |-- deploy.sh
| +-- setup-devlib.sh
+-- docs/ # Documentacion del proyecto
+-- api.md# Objetos compilados (no se versionan) *.pgm *.srvpgm *.module *.bnddir # Logs y temporales *.log *.tmp *.joblog # Archivos de save *.savf # Directorios de IDE .theia/ .che/ # Credenciales (nunca subir) .env credentials.json *.pem # OS files .DS_Store Thumbs.db
Arcad iNside
Suite completa de ALM (Application Lifecycle Management) para IBM i. Incluye source control, analisis de impacto, deployment automatizado y audit trail.
Remain API Studio
Herramienta visual para crear APIs REST desde programas RPG. Genera documentacion OpenAPI y maneja autenticacion sin codigo.
MDCMS
Change Management System open source para IBM i. Maneja promocion de objetos entre entornos con historial y aprobaciones.
RDi (Rational Developer for i)
IDE basado en Eclipse de IBM. Alternativa a VS Code con debugger integrado, profiler y analisis estatico de codigo RPG.
SonarQube + RPG plugin
Analisis estatico de codigo RPG. Detecta code smells, complejidad ciclomatica, codigo muerto y vulnerabilidades.
Eradani Connect
Middleware que expone programas RPG como APIs REST, microservicios y conectores. Alternativa comercial a IWS.
La adopcion de DevOps en IBM i es un proceso gradual. No es necesario (ni recomendable) implementar todo de una vez. Este roadmap sugiere un orden incremental basado en la experiencia de la comunidad.
Fase 1: Fundamentos (semanas 1-4)
Fase 2: Versionado (semanas 5-8)
Fase 3: Automatizacion (semanas 9-12)
Fase 4: Madurez (mes 4+)
Code for IBM i es la extension principal de VS Code para desarrollo en IBM i. Con IBM i 7.6, recibe actualizaciones importantes para alinearse con las nuevas capacidades del sistema.
IBM Wazi for i (Merlin) es un entorno de desarrollo cloud-based que corre en contenedores (OpenShift). Provee un IDE completo accesible desde el browser con compilacion, debug y CI/CD integrados.
VS Code + Code for i
Merlin (IBM Wazi for i)