Sintaxe Completa de Pipelines no Jenkins: Declarativo vs Scripted

O Jenkins oferece duas abordagens principais para definição de pipelines: declarativa e scripted. Ambas utilizam o mecanismo do Groovy, mas diferem significativamente em sintaxe, legibilidade e flexibilidade.

Comparação entre Pipeline Declarativo e Scripted

Pontos em comum:

  • Ambos são persistentes e podem usar steps fornecidos por plugins ou bibliotecas compartilhadas.
  • Suportam extensão via bibliotecas globais do Jenkins.

Diferenças:

  • O pipeline declarativo possui uma estrutura rígida, facilitando a leitura e validação prévia de erros de sintaxe. Ideal para cenários padrão.
  • O pipeline scripted, baseado diretamente no Groovy, oferece maior liberdade para lógica complexa, controle de fluxo avannçado e manipulação dinâmica.

O pipeline declarativo é construído sobre a base do scripted e permite incorporar blocos script para recuperar flexibilidade quando necessário.

Estrutura Básica do Pipeline Declarativo

Um pipeline declarativo válido deve conter os seguintes blocos obrigatórios:

  • agent
  • stages
  • Um ou mais stage
  • steps dentro de cada stage

Além disso, suporta diretivas opcionais como: environment, parameters, options, triggers, post, tools, input, when e parallel.

agent

Define onde o pipeline (ou estágio) será executado. Pode ser colocado no nível raiz (pipeline) ou dentro de um stage.

pipeline {
    agent none
    stages {
        stage('Build') {
            agent { docker 'maven:3.8-jdk-11' }
            steps {
                sh 'mvn clean package'
            }
        }
        stage('Test') {
            agent { label 'linux-worker' }
            steps {
                sh 'npm test'
            }
        }
    }
}

// Exemplo com workspace personalizado
agent {
    node {
        label 'k8s-agent'
        customWorkspace '/build/workspace/project-x'
    }
}

options

Configurações globais do pipeline, como tempo limite, descarte de builds antigos ou tentativas de repetição.

pipeline {
    agent any
    options {
        timeout(time: 30, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '10'))
        disableConcurrentBuilds()
        timestamps()
    }
    stages {
        stage('Run') {
            steps {
                echo 'Executando com opções configuradas'
            }
        }
    }
}

parameters

Permite que o usuário forneça entradas ao acionar o pipeline. Os valores ficam acessíveis via params.NOME.

pipeline {
    agent any
    parameters {
        string(name: 'VERSION', defaultValue: '1.0.0', description: 'Versão da aplicação')
        choice(name: 'ENVIRONMENT', choices: ['dev', 'staging', 'prod'], description: 'Ambiente alvo')
        booleanParam(name: 'RUN_TESTS', defaultValue: true, description: 'Executar testes?')
    }
    stages {
        stage('Deploy') {
            steps {
                echo "Implantando versão ${params.VERSION} no ambiente ${params.ENVIRONMENT}"
                script {
                    if (params.RUN_TESTS) {
                        sh './run-tests.sh'
                    }
                }
            }
        }
    }
}

environment

Define variáveis de ambiente no nível do pipeline ou de um estágio específico. Suporta injeção segura de credenciais via credentials().

pipeline {
    agent any
    environment {
        DB_HOST = 'db.prod.internal'
        API_KEY = credentials('my-api-secret')
    }
    stages {
        stage('Use Env') {
            steps {
                sh 'echo "Conectando a $DB_HOST com chave secreta"'
            }
        }
    }
}

input

Pausa a execução até que um usuário autorizado confirme a continuação.

stage('Approval') {
    input {
        message "Continuar implantação em produção?"
        ok "Sim, implantar"
        submitter "admin,deploy-team"
        parameters {
            string(name: 'APPROVER_NOTES', defaultValue: '', description: 'Justificativa')
        }
    }
    steps {
        echo "Aprovado por: ${APPROVER_NOTES}"
    }
}

parallel

Permite execução simultânea de múltiplos estágios.

stage('Testes Paralelos') {
    parallel {
        stage('Linux') {
            agent { label 'linux' }
            steps { sh './test-linux.sh' }
        }
        stage('Windows') {
            agent { label 'windows' }
            steps { bat 'test-windows.bat' }
        }
    }
}

post

Define ações a serem executadas após a conclusão do pipeline ou estágio, com base no status final.

post {
    success {
        echo 'Pipeline concluído com sucesso!'
        emailext subject: 'Sucesso!', body: 'Build OK', recipientProviders: [[$class: 'DevelopersRecipientProvider']]
    }
    failure {
        echo 'Falha na execução!'
        slackSend channel: '#alerts', message: 'Pipeline falhou!'
    }
    always {
        cleanWs()
    }
}

when

Controla a execução condicional de um estágio com base em critérios como branch, variáveis de ambiente ou expressões Groovy.

stage('Deploy to Prod') {
    when {
        allOf {
            branch 'main'
            environment name: 'DEPLOY_ENV', value: 'production'
            expression { return params.DEPLOY_ENABLED }
        }
    }
    steps {
        sh './deploy-prod.sh'
    }
}

tools

Garante que versões específicas de ferramentas (JDK, Maven, Gradle) estejam disponíveis, desde que configuradas em Gerenciar Jenkins → Configuração de Ferramentas Globais.

pipeline {
    agent any
    tools {
        jdk 'openjdk-17'
        maven 'maven-3.9'
    }
    stages {
        stage('Build') {
            steps {
                sh 'mvn --version'
                sh 'java -version'
            }
        }
    }
}

triggers

Define gatilhos automáticos para execução do pipeline.

triggers {
    cron('H 2 * * 1-5') // Executa às 2h nos dias úteis
    // pollSCM('H/15 * * * *') // Verifica SCM a cada 15 minutos
    // upstream(upstreamProjects: 'build-job', threshold: SUCCESS)
}

script

Permite inserir código Groovy arbitrário dantro de um pipeline declarativo, útil para lógica complexa ou iterações.

stage('Dynamic Steps') {
    steps {
        script {
            def services = ['auth', 'payment', 'user']
            services.each { svc ->
                echo "Construindo serviço: ${svc}"
                sh "./build-${svc}.sh"
            }
        }
    }
}

Pipeline Scripted: Controle Total com Groovy

O pipeline scripted oferece liberdade total com a sintaxe do Groovy, incluindo estruturas de controle nativas.

Condicionais com if/else

node('worker') {
    stage('Conditional') {
        if (env.GIT_BRANCH == 'origin/main') {
            sh 'echo "Branch principal"'
        } else {
            sh 'echo "Branch de feature"'
        }
    }
}

Tratamento de Erros com try/catch

node {
    stage('Risky Operation') {
        try {
            sh 'flaky-command || exit 1'
        } catch (Exception e) {
            echo "Erro capturado: ${e.message}"
            currentBuild.result = 'UNSTABLE'
        } finally {
            sh 'cleanup.sh'
        }
    }
}

Laços com for ou each

node {
    stage('Loop Example') {
        def regions = ['us-east', 'eu-west', 'ap-southeast']
        regions.each { region ->
            echo "Processando região: ${region}"
            sh "./deploy.sh --region ${region}"
        }
    }
}

Embora o pipeline declarativo seja recomendado para a maioria dos casos de uso devido à sua clareza e validação antecipada, o scripted permanece essencial para cenários que exigem lógica dinâmica, manipulação avançada de dados ou integração profunda com APIs externas.

Tags: Jenkins Pipeline Groovy CI/CD Declarative Pipeline

Publicado em 10-7 04:33