Sintaxis de Jenkins Pipeline: Una Guía Completa para Principiantes

Desmitifique la sintaxis de Jenkins pipeline con esta guía completa para principiantes. Aprenda los elementos esenciales de los pipelines Declarativos y Basados en Scripts, incluyendo agentes, etapas (stages), pasos (steps), acciones posteriores (post-actions), entornos (environments), parámetros y mejores prácticas. Empodérese para construir flujos de trabajo CI/CD robustos de manera efectiva con ejemplos prácticos y consejos aplicables.

Sintaxis de Pipeline de Jenkins: Una Guía Completa para Principiantes

La sintaxis de Pipeline de Jenkins te permite describir tu proceso de compilación, prueba e implementación en un Jenkinsfile que vive con tu código. Esto es importante porque los cambios en tu pipeline pueden ser revisados, versionados y revertidos como el código de la aplicación.

Si eres nuevo en los pipelines de Jenkins, comienza con la sintaxis de Pipeline Declarativo. Es estructurada, legible y cubre la mayoría de los flujos de trabajo CI/CD sin requerir mucho conocimiento de Groovy.

Pipeline Declarativo vs. Scriptado

Jenkins soporta dos estilos de pipeline.

El Pipeline Declarativo utiliza una estructura estricta pipeline { ... }. Es la mejor opción por defecto para la mayoría de los equipos porque Jenkins puede validar la forma del archivo y mostrar las etapas de manera limpia en la interfaz de usuario.

El Pipeline Scriptado utiliza Groovy dentro de bloques node { ... }. Te da más control, pero es más fácil crear pipelines difíciles de mantener si tu equipo no se siente cómodo con Groovy.

Usa Declarativo primero. Recurre a Scriptado solo cuando necesites lógica que Declarativo no pueda expresar de manera limpia.

Un Pipeline Declarativo Mínimo

Un Jenkinsfile básico tiene un agente, etapas y pasos:

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                echo 'Construyendo la aplicación'
                sh 'mvn clean package'
            }
        }

        stage('Test') {
            steps {
                sh 'mvn test'
            }
        }
    }
}

agent any le dice a Jenkins que ejecute el pipeline en cualquier agente disponible. Cada stage aparece por separado en la interfaz de usuario de Jenkins. El bloque steps contiene los comandos que Jenkins ejecuta.

En agentes Windows, usa bat en lugar de sh:

bat 'gradlew.bat test'

La Directiva agent

La directiva agent decide dónde se ejecuta el pipeline o la etapa.

Ejecutar en cualquier agente disponible:

agent any

Ejecutar en un agente con una etiqueta específica:

agent { label 'linux && docker' }

Omitir un agente global y elegir uno por etapa:

pipeline {
    agent none

    stages {
        stage('Build') {
            agent { label 'linux' }
            steps {
                sh './build.sh'
            }
        }
    }
}

agent none es útil cuando diferentes etapas necesitan diferentes entornos, como Linux para compilaciones y Windows para pruebas de instaladores.

Etapas y Pasos

Usa etapas para dividir el pipeline en trabajo que un desarrollador pueda entender de un vistazo: checkout, compilación, prueba, empaquetado, implementación.

stages {
    stage('Checkout') {
        steps {
            checkout scm
        }
    }

    stage('Pruebas Unitarias') {
        steps {
            sh 'npm test'
        }
    }
}

Mantén las etapas significativas. Una etapa llamada Ejecutar con cincuenta comandos es difícil de depurar. Un pipeline con veinte etapas pequeñas es ruidoso. Apunta a etapas que coincidan con puntos de control reales del flujo de trabajo.

Variables de Entorno

Usa environment para valores que varias etapas necesiten:

pipeline {
    agent any

    environment {
        APP_NAME = 'orders-api'
        IMAGE = "registry.example.com/team/orders-api:${env.BUILD_NUMBER}"
    }

    stages {
        stage('Construir Imagen') {
            steps {
                sh 'docker build -t "$IMAGE" .'
            }
        }
    }
}

En cadenas de Groovy, puedes leer variables a través de env.APP_NAME. En pasos de shell, Jenkins exporta variables de entorno para que $APP_NAME y $IMAGE funcionen dentro del shell.

No pongas secretos en environment. Usa Credenciales de Jenkins con withCredentials.

Parámetros

Los parámetros permiten que alguien elija valores al iniciar una compilación manualmente:

pipeline {
    agent any

    parameters {
        string(name: 'BRANCH_NAME', defaultValue: 'main', description: 'Rama de Git a compilar')
        booleanParam(name: 'RUN_TESTS', defaultValue: true, description: 'Ejecutar pruebas unitarias')
        choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: 'Entorno objetivo')
    }

    stages {
        stage('Mostrar Entradas') {
            steps {
                echo "Rama: ${params.BRANCH_NAME}"
                echo "Objetivo de implementación: ${params.DEPLOY_ENV}"
            }
        }
    }
}

Usa parámetros para cosas que deberían variar entre ejecuciones. No los uses para evitar la revisión de cambios en producción.

Etapas Condicionales con when

La directiva when controla si una etapa se ejecuta:

stage('Implementar a Producción') {
    when {
        branch 'main'
    }
    steps {
        sh './deploy-prod.sh'
    }
}

También puedes usar una expresión:

stage('Test') {
    when {
        expression { return params.RUN_TESTS }
    }
    steps {
        sh 'npm test'
    }
}

Pon when en la etapa, no dentro de steps.

Acciones Posteriores

Los bloques post se ejecutan después de que una etapa o pipeline finaliza. Son útiles para publicar informes de prueba, archivar evidencia de compilación y limpiar.

pipeline {
    agent any

    stages {
        stage('Test') {
            steps {
                sh 'mvn test'
            }
            post {
                always {
                    junit 'target/surefire-reports/*.xml'
                }
            }
        }
    }

    post {
        failure {
            echo 'El pipeline falló'
        }
        always {
            cleanWs()
        }
    }
}

junit publica los resultados de las pruebas incluso cuando las pruebas fallan. cleanWs() proviene del plugin de Limpieza del Espacio de Trabajo, así que instala ese plugin antes de usarlo.

Opciones

Usa options para establecer el comportamiento del pipeline:

pipeline {
    agent any

    options {
        timestamps()
        timeout(time: 30, unit: 'MINUTES')
        disableConcurrentBuilds()
        buildDiscarder(logRotator(numToKeepStr: '20'))
    }

    stages {
        stage('Build') {
            steps {
                sh './build.sh'
            }
        }
    }
}

Estas opciones hacen que los registros sean más fáciles de leer, detienen compilaciones colgadas, evitan ejecuciones superpuestas del mismo trabajo y limitan el historial de compilaciones antiguas.

Un Pipeline Práctico para Principiantes

Este ejemplo verifica el código, compila un proyecto Java, publica los resultados de las pruebas y archiva el JAR empaquetado:

pipeline {
    agent { label 'linux' }

    options {
        timestamps()
        timeout(time: 30, unit: 'MINUTES')
        disableConcurrentBuilds()
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }

        stage('Publicar') {
            steps {
                junit 'target/surefire-reports/*.xml'
                archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
            }
        }
    }
}

Este es un mejor punto de partida que un pipeline de implementación gigante. Una vez que la compilación sea confiable, agrega publicación de imágenes, escaneos de seguridad o etapas de implementación.

Conceptos Básicos del Pipeline Scriptado

Un Pipeline Scriptado simple se ve así:

node('linux') {
    stage('Checkout') {
        checkout scm
    }

    stage('Build') {
        sh 'mvn clean package'
    }
}

No envuelvas un bloque pipeline {} Declarativo dentro de un Pipeline Scriptado. Mantén los dos estilos separados a menos que tengas una razón específica y probada para mezclar pequeñas secciones scriptadas dentro de bloques Declarativos script { ... }.

Buenos Hábitos de Pipeline

Almacena el Jenkinsfile en control de versiones. Mantén los secretos en Credenciales de Jenkins. Da a las etapas nombres que coincidan con el trabajo que realizan. Publica informes en bloques post para que los fallos aún dejen evidencia útil. Agrega tiempos de espera antes de que una compilación se cuelgue durante la noche.

La mayoría de los problemas de pipeline para principiantes provienen de suposiciones ocultas: una herramienta existe en un agente pero no en otro, un secreto está codificado, o un informe solo se publica en caso de éxito. Haz esas suposiciones explícitas en el pipeline, y Jenkins se vuelve mucho más confiable.