Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Jenkins declarative pipeline to build and test on multiple platforms

I'm trying to do something that I feel should be simple to do, but I can't figure out how.

Basically I have a Jenkins master (running on Linux) and two slaves, one on Windows and the other on macOS.

I want to build my project on all 3 platforms and run GTest tests on all 3 platforms too.

I can build and run the test, but the junit step doesn't seem to collect any test results.

I tried to put the post block everywhere, but it just doesn't work. If I try to put the post block in the Test stage or as a sibling of stages, I get the following error:

Required context class hudson.FilePath is missing Perhaps you forgot to surround the code with a step that provides this, such as: node which is caused by agent none - the post block doesn't know where to run.

So I tried to put the post block inside the node block in my parallel step for the Test stage, but it doesn't seem to do anything - it doesn't even show up in the console output.

Here's my Jenkinsfile:

pipeline {
    agent none
    stages {
        stage ('Clean') {
            steps {
                parallel (
                    "linux" : {
                        node ("linux") {
                            dir("build") {
                                deleteDir()
                                writeFile file:'dummy', text:'' // Creates the directory
                            }
                        }
                    },
                    "windows" : {
                        node('windows') {
                            dir("build") {
                                deleteDir()
                                writeFile file:'dummy', text:'' // Creates the directory
                            }
                        }
                    },
                    "mac" : {
                        node('mac') {
                            dir("build") {
                                deleteDir()
                                writeFile file:'dummy', text:''  // Creates the directory
                            }
                        }
                    }
                )
            }
        }

        stage ('Build') {
            steps {
                parallel (
                    "linux" : {
                        node ("linux") {
                            checkout scm
                            dir("build") {
                                sh '/opt/cmake/bin/cmake .. -DCMAKE_BUILD_TYPE=Release'
                                sh 'make'
                            }
                        }
                    },
                    "windows" : {
                        node('windows') {
                            checkout(changelog: false, scm: scm) // Changelog to false, otherwise Jenkins shows duplicates. Only linux (the Jenkins master) has the changelog enabled.
                            dir("build") {
                                bat 'cmake .. -G "Visual Studio 15 2017 Win64" -DCMAKE_PREFIX_PATH=C:/Qt/5.9.1/msvc2017_64'
                                bat "\"${tool 'MSBuild'}\" project.sln /p:Configuration=Release /p:Platform=\"x64\" /p:ProductVersion=1.0.0.${env.BUILD_NUMBER} /m"
                            }
                        }
                    },
                    "mac" : {
                        node('mac') {
                            checkout(changelog: false, scm: scm) // Changelog to false, otherwise Jenkins shows duplicates. Only linux (the Jenkins master) has the changelog enabled.
                            dir("build") {
                                sh 'cmake .. -DCMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.9.1 -DCMAKE_BUILD_TYPE=Release'
                                sh 'make'
                            }
                        }
                    }
                )
            }
        }

        stage ('Test') {
            steps {
                parallel (
                    "linux" : {
                        node ("linux") {
                            dir('Build') {
                                sh './bin/project-tests --gtest_output=xml:project-tests-results.xml'
                                // Add other test executables here.
                            }

                            post {
                                always {
                                    junit '*-tests-results.xml'
                                }
                            }
                        }
                    },
                    "windows" : {
                        node('windows') {
                            dir("build") {
                                bat 'tests\\project\\Release\\project-tests --gtest_output=xml:project-tests-results.xml'
                                // Add other test executables here.
                            }

                            post {
                                always {
                                    junit '*-tests-results.xml'
                                }
                            }
                        }
                    },
                    "mac" : {
                        node('mac') {
                            dir("build") {
                                sh './bin/project-tests --gtest_output=xml:project-tests-results.xml'
                                // Add other test executables here.
                            }
                            post {
                                always {
                                    junit '*-tests-results.xml'
                                }
                            }
                        }
                    }
                )
            }
        }
    }

}

What am I doing wrong?

like image 682
Kevin Doyon Avatar asked Sep 12 '17 00:09

Kevin Doyon


People also ask

Can a single Jenkins job run on multiple nodes?

Step 1− If multi node selection was enabled, you get the chance to select multiple nodes to run the job on. The job will then be executed on each of the nodes, one after the other or concurrent - depending on the configuration.

What are the 3 types of pipelines in Jenkins?

Different Types of Jenkins CI/CD Pipelines. Scripted Pipeline. Declarative Pipeline.

What is multistage pipeline in Jenkins?

Jenkins Pipeline allows you to compose multiple steps in an easy way that can help you model any sort of automation process. Think of a "step" like a single command which performs a single action.


1 Answers

  1. post{} block should only follow steps{} or parallel{} (for parallel stages) to take effect.

  2. If you require post to be executed in a node environment, you should provide a node to the entire stage (agent{} statement).

You could try to use parallel stages execution. Also I'd suggest to use functions to shorten the code.

Something like this:

void Clean() {
    dir("build") {
        deleteDir()
        writeFile file:'dummy', text:'' // Creates the directory
    }
}

void SmthElse(def optionalParams) {
    // some actions here
}

pipeline {
    agent none
    options {
        skipDefaultCheckout(true)   // to avoid force checkouts on every node in a first stage
        disableConcurrentBuilds()   // to avoid concurrent builds on same nodes
    }
    stages {
        stage('Clean') {
            failfast false
            parallel {
                    stage('Linux') {
                        agent {label 'linux'}
                        steps {Clean()}
                        post {
                            // post statements for 'linux' node
                            SmthElse(someParameter)
                        }
                    }
                    stage('Windows') {
                        agent {label 'windows'}
                        steps {Clean()}
                        post {
                            // post statements for 'windows' node
                        }
                    }
                    stage('MacOS') {
                        agent {label 'mac'}
                        steps {Clean()}
                        post {
                            // post statements for 'mac' node
                        }
                    }
            }
            post {
                // Post statements OUTSIDE of nodes (i.e. send e-mail of a stage completion)
            }
        }

        // other stages (Build/Test/Etc.)
    }
}

Alternatively you can use node in post statements:

stage('Test') {
    steps {
        // your parallel Test steps
    }
    post {
        always {
            script {
                parallel (
                    "linux" : {
                        node('linux') {
                            // 'linux' node post steps
                        }
                    },
                    "windows" : {
                        node('windows') {
                            // 'windows' node post steps
                        }
                    }

                    // etc
                )
            }
        }
    }
}
like image 108
n01d Avatar answered Oct 25 '22 03:10

n01d