Implement matrix config in Jenkins pipeline

自古美人都是妖i 提交于 2019-12-23 01:57:38

问题


I've recently moved to the Pipeline plugin in Jenkins. I've successfully used freestyle jobs before for my project, but now would like to test something new.

My project builds for Windows and Linux, in release and in debug mode, and uses a parameter, called device, to configure some C preprocessor macros: globally #defined frame_width and frame_height differ, depending on device value.

Here is my Jenkinsfile:

def device_config(device) {
    def device_config = "";
    switch(device) {
        case ~/^dev_[Aa]$/:
            device_config="""-DGLOBAL_FRAME_WIDTH=640\
                             -DGLOBAL_FRAME_HEIGHT=480"""
        break;
    case ~/^dev_[Ss]$/:
        device_config="""-DGLOBAL_FRAME_WIDTH=320\
                         -DGLOBAL_FRAME_HEIGHT=240"""
        break;
    default: 
        echo "warning: Unknown device \"$device\" using default config from CMake"
        break;
    }
    return device_config
}

pipeline {
    agent {
        label 'project_device_linux'
    }
    environment {
        device='dev_A'
    }
    stages {
        stage('Configure') {
            steps {
                script {
                    dc = device_config("${env.device}")
                }
                dir('build') {
                    sh """cmake .. -DOpenCV_DIR="/usr/local" -DCMAKE_BUILD_TYPE="Debug"\
                               -DCHECK_MEMORY_LEAKS=ON\
                               -DENABLE_DEVELOPER_MODE=OFF\
                               -DUNIT_TEST_RAW_PATH=${env.tmpfs_path}\
                               $dc"""
               }
            }
        }
        stage('Build') {
            steps { 
                dir('build') { 
                    sh "make -j 16"
                }
            }
        }
        stage('Test'){
            steps {
                dir('build') {
                   sh "make check"
                }
            }
        }
    }
}

Now I'd like to repeat all those stages for another device, dev_s, for "Release" build type, and for Windows also. There are also some minor differences, depending on parameters: for example, "Release" builds should have included publishing of compiled binaries and excluded check for memory leaks. Also, if I've got it correctly, Windows slave does not understand sh build step and uses bat for that purpose.

How can I do it without copy-pasteing of code and in parallel on 2 nodes, one running Linux, and another one, running Windows?

Obviously, there should be several nested loops, but it is not clear for me, what to emit on each loop iteration.

Forgot to mention, I'd like to run everything from the Gitlab trigger on Push events.

UPDATE

Currently I end up with something like the following

#!/usr/bin/env groovy

def device_config(device) {
    def result = "";
    switch(device) {
        case ~/^dev_[Aa]$/:
            result ="""-DFRAME_WIDTH=640\
                       -DFRAME_HEIGHT=480"""
            break;
        case ~/^dev_[Ss]$/:
            result ="""-DFRAME_WIDTH=320\
                       -DFRAME_HEIGHT=240"""
            break;
        default:
            echo "warning: Unknown device \"$device\" using default config from CMake"
            break;
    }
    return result;
}


oses = ['linux', 'windows']
devices = ['dev_A', 'dev_S']
build_types = ['Debug', 'Release']


node {
    stage('Checkout') {
        checkout_steps = [:]
        for (os in oses) {
            for (device in devices) {
                for (build_type in build_types) {
                    def label = "co-${os}-${device}-${build_type}"
                    def node_label = "project && ${os}"

                    checkout_steps[label] = {
                        node(node_label) {
                            checkout scm
                        }
                    }
                }
            }
        }

        parallel checkout_steps

    }


    stage('Configure') {

        config_steps = [:]

        for (os in oses) {
            for (device in devices) {
                for (build_type in build_types) {
                    def label = "configure-${os}-${device}-${build_type}"
                    def node_label = "project && ${os}"
                    def dc = device_config("${device}")

                    cmake_parameters = """-DCMAKE_BUILD_TYPE="${build_type}"\
                                          -DCHECK_MEMORY_LEAKS=ON\
                                          $dc"""

                    if(os == 'linux') {
                        config_steps[label] = {
                            node(node_label) {
                                dir('build') {
                                    sh """cmake .. -DOpenCV_DIR=/usr/local ${cmake_parameters}"""
                                }
                            }
                        }
                    } else {
                        config_steps[label] = {
                            node(node_label) {
                                dir('build') {
                                    bat """cmake .. -G"Ninja" -DOpenCV_DIR=G:/opencv_2_4_11/build ${cmake_parameters}"""
                                }
                            }
                        }
                    }
                }
            }
        }

        parallel config_steps
    }

}

What I don't like is that some node-specific settings, like paths, are set in the Jenkinsfile. Hope to figure out, how to set them in node settings in Jenkins.

I also see in logs, that only Release + dev_S configuration is applied - there is some kind of closure and late binding. Search reveals that it is a known and already fixed issue - I have to plan to figure out how to deal with closures.

来源:https://stackoverflow.com/questions/47814891/implement-matrix-config-in-jenkins-pipeline

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!