Configuring cmake to build in in Jenkins Multibranch pipeline

457 Views Asked by At

I'm having difficulty configuring cmake to work in a declarative Jenkins multi branch pipeline to build and run unit tests.

Below is the Jenkins log output.

Obtained Jenkinsfile from ee03d9be78e0bf8585e6e122fcc03f6e13365cff
[Pipeline] Start of Pipeline
[Pipeline] node
Running on Jenkins in /Users/mattwalsh/.jenkins/workspace/matt-wash-projects_main
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Declarative: Checkout SCM)
[Pipeline] checkout
The recommended git tool is: NONE
using credential mattwalsh-github-creds
Cloning the remote Git repository
Using shallow clone with depth 2
Cloning repository https://github.com/mysticrecords/out-of-tree-builds.git
 > git init /Users/mattwalsh/.jenkins/workspace/matt-wash-projects_main # timeout=10
Fetching upstream changes from https://github.com/mysticrecords/out-of-tree-builds.git
 > git --version # timeout=10
 > git --version # 'git version 2.30.1 (Apple Git-130)'
using GIT_ASKPASS to set credentials mattwalsh-github-creds
 > git fetch --tags --force --progress --depth=2 -- https://github.com/mysticrecords/out-of-tree-builds.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git config remote.origin.url https://github.com/mysticrecords/out-of-tree-builds.git # timeout=10
 > git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
Avoid second fetch
Checking out Revision ee03d9be78e0bf8585e6e122fcc03f6e13365cff (main)
 > git config core.sparsecheckout # timeout=10
 > git checkout -f ee03d9be78e0bf8585e6e122fcc03f6e13365cff # timeout=1
Commit message: "jenkinsfile"
 > git rev-list --no-walk ee03d9be78e0bf8585e6e122fcc03f6e13365cff # timeout=10
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Configure)
[Pipeline] dir
Running in /Users/mattwalsh/.jenkins/workspace/matt-wash-projects_main/build
[Pipeline] {
[Pipeline] cmake
[Pipeline] }
[Pipeline] // dir
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build)
Stage "Build" skipped due to earlier failure(s)
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Test)
Stage "Test" skipped due to earlier failure(s)
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] archiveArtifacts
Archiving artifacts
[Pipeline] xunit
INFO: Processing CTest-Version 3.x (default)
INFO: [CTest-Version 3.x (default)] - No test report file(s) were found with the pattern 'build/*.xml' relative to '/Users/mattwalsh/.jenkins/workspace/matt-wash-projects_main' for the testing framework 'CTest-Version 3.x (default)'.
Did you enter a pattern relative to (and within) the workspace directory?
Did you generate the result report(s) for 'CTest-Version 3.x (default)'?"
INFO: Check 'Skipped Tests' threshold.
INFO: Check 'Failed Tests' threshold.
[Pipeline] deleteDir
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: There is no Cmake installation selected. Please review the build step configuration and make sure the installation is configured on the Global Tool Configuration page.

GitHub has been notified of this commit’s build result

Finished: FAILURE

Jenkinsfile declarative pipeline. I have tested the shell script commands in each stage in my local environment which all work.

pipeline {
  agent any
  stages {
    stage('Configure') {
      steps {
        dir('build') {
          cmake(
            installation: 'InSearchPath'
          )
          sh 'cmake .'
        }
      }
    }
    stage('Build') {
      steps {
        dir('build') {
          sh 'cmake --build .'
        }
      }
    }  
    stage('Test') {
      steps {
        dir('build') {
          sh 'ctest -C checkin --output-junit unittest.xml'
        }
      }
    }
  }
  post {
    always {
      // Archive the CTest xml output
      archiveArtifacts (
        artifacts: 'build/*.xml',
        fingerprint: true
      )

      // Process the CTest xml output with the xUnit plugin
      xunit (
        testTimeMargin: '3000',
        thresholdMode: 1,
        thresholds: [
          skipped(failureThreshold: '0'),
          failed(failureThreshold: '0')
        ],
      tools: [CTest(
          pattern: 'build/*.xml',
          deleteOutputFiles: true,
          failIfNotNew: false,
          skipNoTestFiles: true,
          stopProcessingIfError: true
        )]
      )

      // Clear the source and build dirs before next run
      deleteDir()
    }
  }
}

I have the cmake plugin configured in jenkins

cmake plugin configuration in jenkins

Is there anything else I could try to get this to work?

I'm trying to build this on the built in node if this has an impact on it?

I'm pretty new to using Jenkins so any help is greatly appreciated. This one has got me truly stuck.

1

There are 1 best solutions below

0
Corristo On

The repository you're cloning according to the Jenkins log file does not have a build directory, which is why the dir('build') step creates an empty directory before switching to that directory. You then try to call cmake . in that empty directory, which fails because there is no CMakeLists.txt file in that directory and you also do not provide additional arguments to point CMake to the sources.

Moreover, the cmake, ctest and cpack steps provided by the CMake plugin call these tools directly and do not modify the environment. So you do not need to use the sh step to run cmake again.

The following Jenkinsfile should work correctly, assuming you have correctly configured a CMake installation with the name InSearchPath:

pipeline {
  agent any
  stages {
    stage('Configure') {
      steps {
        cmake arguments: '''
          -S projects
          -B build
         ''', installation: 'InSearchPath'
      }
    }
    stage('Build') {
      steps {
        cmake arguments: '--build build', installation: 'InSearchPath'
      }
    }  
    stage('Test') {
      steps {
        ctest arguments: '''
          --test-dir build
          --output-junit unittest.xml
        ''', installation: 'InSearchPath'
      }
    }
  }
  post {
    always {
      // Archive the CTest xml output
      archiveArtifacts (
        artifacts: '**/unittest.xml',
        fingerprint: true
      )

      // Process the CTest xml output with the xUnit plugin
      xunit (
        testTimeMargin: '3000',
        thresholdMode: 1,
        thresholds: [
          skipped(failureThreshold: '0'),
          failed(failureThreshold: '0')
        ],
        tools: [CTest(
          pattern: '**/unittest.xml',
          deleteOutputFiles: true,
          failIfNotNew: false,
          skipNoTestFiles: true,
          stopProcessingIfError: true
        )]
      )

      // Clear the source and build dirs before next run
      deleteDir()
    }
  }
}

I omitted the -C checkin flag for CTest because I don't think this will work: -C is used to specify the configuration that was built, but checkin is not a valid configuration name (should be Release, RelWithDebInfo, MinSizeRel or Debug). If you actually added a configuration named checkin than go ahead and put it back in, but adding configurations is a terrible idea and should be avoided.

One last tip: You end the pipeline with the deleteDir step to clean before the next run. This is unreliable, as the pipeline might be aborted and not properly clean up if abortion is forced. If you really need clean builds every time you should run deleteDir as the very first step before manually checking out the code from git via the scm step.