Jenkins入门教程(七):Pipeline条件判断与并行执行

本文将详细介绍Pipeline中的条件判断和并行执行,让你的CI/CD流程更加灵活和高效,包括完整的示例和执行结果。

when条件指令

when指令用于控制stage是否执行,只有满足条件时stage才会运行。

branch条件

pipeline {
    agent any
    
    stages {
        stage('Build') {
            steps {
                sh 'make build'
            }
        }
        
        stage('Deploy to Dev') {
            when {
                branch 'develop'
            }
            steps {
                echo 'Deploying to development environment...'
                sh './deploy.sh dev'
            }
        }
        
        stage('Deploy to Staging') {
            when {
                branch 'release/*'  // 支持通配符
            }
            steps {
                echo 'Deploying to staging environment...'
                sh './deploy.sh staging'
            }
        }
        
        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                echo 'Deploying to production environment...'
                sh './deploy.sh prod'
            }
        }
    }
}

// 在main分支执行时的输出
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] sh
+ make build
...
[Pipeline] stage
[Pipeline] { (Deploy to Dev)
Stage "Deploy to Dev" skipped due to when conditional
[Pipeline] stage
[Pipeline] { (Deploy to Staging)
Stage "Deploy to Staging" skipped due to when conditional
[Pipeline] stage
[Pipeline] { (Deploy to Production)
[Pipeline] echo
Deploying to production environment...
[Pipeline] sh
+ ./deploy.sh prod

expression条件

pipeline {
    agent any
    
    parameters {
        booleanParam(name: 'RUN_TESTS', defaultValue: true, description: '是否运行测试')
        choice(name: 'DEPLOY_ENV', choices: ['none', 'dev', 'staging', 'prod'], description: '部署环境')
    }
    
    stages {
        stage('Test') {
            when {
                expression { params.RUN_TESTS == true }
            }
            steps {
                echo 'Running tests...'
                sh 'make test'
            }
        }
        
        stage('Deploy') {
            when {
                expression { params.DEPLOY_ENV != 'none' }
            }
            steps {
                echo "Deploying to ${params.DEPLOY_ENV}..."
                sh "./deploy.sh ${params.DEPLOY_ENV}"
            }
        }
        
        stage('Production Approval') {
            when {
                expression { params.DEPLOY_ENV == 'prod' }
            }
            steps {
                input message: 'Approve production deployment?', ok: 'Deploy'
                sh './deploy.sh prod --confirm'
            }
        }
    }
}

// 当 RUN_TESTS=false, DEPLOY_ENV=dev 时
[Pipeline] stage
[Pipeline] { (Test)
Stage "Test" skipped due to when conditional
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
Deploying to dev...
[Pipeline] sh
+ ./deploy.sh dev

environment条件

pipeline {
    agent any
    
    environment {
        DEPLOY_TO = 'production'
    }
    
    stages {
        stage('Deploy') {
            when {
                environment name: 'DEPLOY_TO', value: 'production'
            }
            steps {
                echo 'Deploying to production because DEPLOY_TO=production'
            }
        }
    }
}

changeset条件

pipeline {
    agent any
    
    stages {
        stage('Build Frontend') {
            when {
                changeset 'frontend/**'  // 只有frontend目录有变更时执行
            }
            steps {
                echo 'Frontend files changed, rebuilding...'
                dir('frontend') {
                    sh 'npm install && npm run build'
                }
            }
        }
        
        stage('Build Backend') {
            when {
                changeset 'backend/**'  // 只有backend目录有变更时执行
            }
            steps {
                echo 'Backend files changed, rebuilding...'
                dir('backend') {
                    sh 'mvn clean package'
                }
            }
        }
        
        stage('Build Docs') {
            when {
                changeset pattern: '.*\\.md$', comparator: 'REGEXP'
            }
            steps {
                echo 'Documentation changed, rebuilding docs...'
                sh 'mkdocs build'
            }
        }
    }
}

组合条件

pipeline {
    agent any
    
    parameters {
        booleanParam(name: 'FORCE_DEPLOY', defaultValue: false)
    }
    
    stages {
        stage('Deploy to Production') {
            when {
                // allOf: 所有条件都满足
                allOf {
                    branch 'main'
                    expression { currentBuild.result == null || currentBuild.result == 'SUCCESS' }
                }
            }
            steps {
                echo 'All conditions met, deploying...'
            }
        }
        
        stage('Emergency Deploy') {
            when {
                // anyOf: 任一条件满足
                anyOf {
                    branch 'hotfix/*'
                    expression { params.FORCE_DEPLOY == true }
                }
            }
            steps {
                echo 'Emergency deployment triggered'
            }
        }
        
        stage('Skip on Docs') {
            when {
                // not: 条件取反
                not {
                    changeset 'docs/**'
                }
            }
            steps {
                echo 'Not a docs-only change, running full build'
            }
        }
    }
}

beforeAgent选项

pipeline {
    agent none
    
    stages {
        stage('Expensive Stage') {
            when {
                branch 'main'
                beforeAgent true  // 在分配agent之前评估条件
            }
            agent {
                label 'expensive-gpu-agent'
            }
            steps {
                echo 'Running on expensive agent only for main branch'
            }
        }
    }
}

// 如果不是main分支,不会占用expensive-gpu-agent

并行执行 (parallel)

基本并行

pipeline {
    agent any
    
    stages {
        stage('Build') {
            steps {
                sh 'make build'
            }
        }
        
        stage('Test') {
            parallel {
                stage('Unit Tests') {
                    steps {
                        sh '''
                            echo "Starting Unit Tests..."
                            sleep 10
                            echo "Unit Tests completed"
                        '''
                    }
                }
                stage('Integration Tests') {
                    steps {
                        sh '''
                            echo "Starting Integration Tests..."
                            sleep 15
                            echo "Integration Tests completed"
                        '''
                    }
                }
                stage('E2E Tests') {
                    steps {
                        sh '''
                            echo "Starting E2E Tests..."
                            sleep 20
                            echo "E2E Tests completed"
                        '''
                    }
                }
            }
        }
    }
}

// 执行结果 - 三个测试同时运行
[Pipeline] parallel
[Pipeline] { (Branch: Unit Tests)
[Pipeline] { (Branch: Integration Tests)
[Pipeline] { (Branch: E2E Tests)
[Pipeline] sh
+ echo 'Starting Unit Tests...'
Starting Unit Tests...
[Pipeline] sh
+ echo 'Starting Integration Tests...'
Starting Integration Tests...
[Pipeline] sh
+ echo 'Starting E2E Tests...'
Starting E2E Tests...
...
// 总耗时约20秒(最长的E2E),而非45秒(串行)

不同节点并行

pipeline {
    agent none
    
    stages {
        stage('Multi-Platform Build') {
            parallel {
                stage('Linux Build') {
                    agent { label 'linux' }
                    steps {
                        sh '''
                            echo "Building on Linux: $(uname -a)"
                            make build-linux
                        '''
                    }
                }
                stage('Windows Build') {
                    agent { label 'windows' }
                    steps {
                        bat '''
                            echo Building on Windows
                            msbuild solution.sln /p:Configuration=Release
                        '''
                    }
                }
                stage('macOS Build') {
                    agent { label 'macos' }
                    steps {
                        sh '''
                            echo "Building on macOS: $(sw_vers -productVersion)"
                            xcodebuild -project MyApp.xcodeproj
                        '''
                    }
                }
            }
        }
    }
}

failFast选项

pipeline {
    agent any
    
    stages {
        stage('Parallel Tests') {
            failFast true  // 任一分支失败立即终止其他分支
            parallel {
                stage('Test A') {
                    steps {
                        sh 'make test-a'
                    }
                }
                stage('Test B') {
                    steps {
                        sh 'make test-b'  // 如果这个失败
                    }
                }
                stage('Test C') {
                    steps {
                        sh 'make test-c'  // 这个会被中止
                    }
                }
            }
        }
    }
}

// 输出示例
[Pipeline] parallel
[Pipeline] { (Branch: Test A)
[Pipeline] { (Branch: Test B)
[Pipeline] { (Branch: Test C)
...
[Pipeline] // Branch: Test B failed
Failing parallel stages due to failFast
[Pipeline] // Branch: Test C aborted

矩阵构建 (matrix)

pipeline {
    agent none
    
    stages {
        stage('Matrix Build') {
            matrix {
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows', 'macos'
                    }
                    axis {
                        name 'JAVA_VERSION'
                        values '11', '17', '21'
                    }
                }
                
                excludes {
                    // 排除某些组合
                    exclude {
                        axis {
                            name 'PLATFORM'
                            values 'windows'
                        }
                        axis {
                            name 'JAVA_VERSION'
                            values '21'  // Windows不测试Java 21
                        }
                    }
                }
                
                agent {
                    label "${PLATFORM}"
                }
                
                stages {
                    stage('Build') {
                        steps {
                            echo "Building on ${PLATFORM} with Java ${JAVA_VERSION}"
                            sh "java -version"
                            sh "make build"
                        }
                    }
                    stage('Test') {
                        steps {
                            echo "Testing on ${PLATFORM} with Java ${JAVA_VERSION}"
                            sh "make test"
                        }
                    }
                }
            }
        }
    }
}

// 会自动生成以下组合并行执行:
// linux + Java 11
// linux + Java 17
// linux + Java 21
// windows + Java 11
// windows + Java 17
// (windows + Java 21 被排除)
// macos + Java 11
// macos + Java 17
// macos + Java 21

错误处理

pipeline {
    agent any
    
    stages {
        stage('Retry Example') {
            steps {
                retry(3) {
                    sh '''
                        echo "Attempt ${RANDOM}"
                        # 模拟偶发失败
                        [ $((RANDOM % 2)) -eq 0 ] && exit 1
                        echo "Success!"
                    '''
                }
            }
        }
        
        stage('Timeout Example') {
            steps {
                timeout(time: 5, unit: 'MINUTES') {
                    sh '''
                        echo "Starting long running task..."
                        # 如果超过5分钟会被中止
                        make long-task
                    '''
                }
            }
        }
        
        stage('Continue on Error') {
            steps {
                catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
                    sh 'exit 1'  // 失败但继续
                }
                echo 'This still runs even after error above'
            }
        }
        
        stage('Try-Catch') {
            steps {
                script {
                    try {
                        sh 'might-fail-command'
                    } catch (Exception e) {
                        echo "Command failed: ${e.message}"
                        echo 'Running fallback...'
                        sh 'fallback-command'
                    }
                }
            }
        }
    }
}

完整实战示例

pipeline {
    agent any
    
    parameters {
        choice(name: 'ENV', choices: ['dev', 'staging', 'prod'], description: 'Deploy environment')
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Build') {
            steps {
                sh 'make build'
            }
        }
        
        stage('Parallel Tests') {
            when {
                not { changeset 'docs/**' }
            }
            failFast true
            parallel {
                stage('Unit Tests') {
                    steps {
                        sh 'make test-unit'
                    }
                    post {
                        always {
                            junit 'reports/unit/*.xml'
                        }
                    }
                }
                stage('Integration Tests') {
                    steps {
                        sh 'make test-integration'
                    }
                    post {
                        always {
                            junit 'reports/integration/*.xml'
                        }
                    }
                }
                stage('Security Scan') {
                    steps {
                        sh 'make security-scan'
                    }
                }
            }
        }
        
        stage('Deploy') {
            when {
                anyOf {
                    branch 'main'
                    branch 'release/*'
                    expression { params.ENV == 'prod' }
                }
            }
            steps {
                echo "Deploying to ${params.ENV}"
                timeout(time: 10, unit: 'MINUTES') {
                    retry(2) {
                        sh "./deploy.sh ${params.ENV}"
                    }
                }
            }
        }
    }
    
    post {
        always {
            cleanWs()
        }
    }
}

总结

本文详细介绍了Pipeline的条件判断(when)、并行执行(parallel)、矩阵构建(matrix)和错误处理。这些特性让Pipeline更加灵活强大,能够处理各种复杂的CI/CD场景。

下一篇我们将学习Pipeline与Git的集成。

发表回复

后才能评论