import org.jenkinsci.plugins.pipeline.modeldefinition.Utils void call(Map options = [:]) { Map hooks = options.get('hooks', [ 'pre': null, 'post-success': null, 'post-always': null, 'post-failure': null, ]) String testTask = options.get('testTask', 'test') String buildTask = options.get('buildTask', 'build') String releaseTask = options.get('releaseTask', 'release') String jobHistory = options.get('jobHistory', '10') String baseImage = options.get('baseImage', 'reg.cadoles.com/proxy_cache/library/ubuntu:22.04') String baseDockerfile = options.get('baseDockerfile', '') String dockerfileExtension = options.get('dockerfileExtension', '') List releaseBranches = options.get('releaseBranches', ['develop', 'testing', 'stable']) node { properties([ buildDiscarder(logRotator(daysToKeepStr: jobHistory, numToKeepStr: jobHistory)), ]) stage('Cancel older jobs') { int buildNumber = env.BUILD_NUMBER as int if (buildNumber > 1) { milestone(buildNumber - 1) } milestone(buildNumber) } stage('Checkout project') { checkout(scm) } stage('Run in container') { try { def containerImage = buildContainerImage(baseImage, baseDockerfile, dockerfileExtension) containerImage.inside('-v /var/run/docker.sock:/var/run/docker.sock') { String repo = env.JOB_NAME if (env.BRANCH_NAME ==~ /^PR-.*$/) { repo = env.JOB_NAME - "/${env.JOB_BASE_NAME}" } stage('Run pre hooks') { runHook(hooks, 'pre') } stage('Run tests') { catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { def ( status, output ) = runTask('testTask', testTask) if (!!output.trim()) { if (env.CHANGE_ID) { gitea.commentPullRequest(repo, env.CHANGE_ID, "# Test report\n\n ${output}") } else { print output } } if (status != 0) { throw new Exception('Task failed !') } } } stage('Build project') { def ( status ) = runTask('buildTask', buildTask) if (status != 0) { throw new Exception('Task failed !') } } stage('Release project') { if (releaseBranches.contains(env.BRANCH_NAME)) { def ( status ) = runTask('releaseTask', releaseTask) if (status != 0) { throw new Exception('Task failed !') } } else { println("Current branch '${env.BRANCH_NAME}' not in releases branches (${releaseBranches}). Skipping.") Utils.markStageSkippedForConditional('Release project') } } } } catch(Exception ex) { runHook(hooks, 'post-failure', [ex]) throw ex } finally { runHook(hooks, 'post-always') cleanWs() } runHook(hooks, 'post-success') } } } void buildContainerImage(String baseImage, String baseDockerfile, String dockerfileExtension) { String imageName = 'cadoles-standard-make-ci' dir(".${imageName}") { String dockerfile = '' if (baseDockerfile) { dockerfile = baseDockerfile } else { dockerfile = libraryResource 'com/cadoles/standard-make/Dockerfile' dockerfile = "FROM ${baseImage}\n" + dockerfile } dockerfile = """ ${dockerfile} ${dockerfileExtension} """ writeFile file:'Dockerfile', text: dockerfile String addLetsEncryptCA = libraryResource 'com/cadoles/common/add-letsencrypt-ca.sh' writeFile file:'add-letsencrypt-ca.sh', text:addLetsEncryptCA String safeJobName = URLDecoder.decode(env.JOB_NAME).toLowerCase().replace('/', '-').replace(' ', '-') String imageTag = "${safeJobName}-${env.BUILD_ID}" return docker.build("${imageName}:${imageTag}", '.') } } void runHook(Map hooks, String name, List args = []) { if (!hooks[name]) { println("No hook '${name}' defined. Skipping.") return } if (hooks[name] instanceof Closure) { hooks[name](*args) } else { error("Hook '${name}' seems to be defined but is not a closure !") } } List runTask(String name, task) { if (!task) { println("No task '${name}' defined. Skipping.") return [ -1, '' ] } String outputFile = ".${name}-output" int status = sh(script: """#!/bin/bash set -eo pipefail make ${task} 2>&1 | tee '${outputFile}' """, returnStatus: true) String output = readFile(outputFile) sh(script: "rm -f '${outputFile}'") return [status, output] }