Jenkins/vars/standardMakePipeline.groovy

258 lines
9.6 KiB
Groovy

import org.jenkinsci.plugins.pipeline.modeldefinition.Utils
void call(Map options = [:]) {
Map hooks = options.get('hooks', [
'pre': null,
'pre-test': null,
'post-test': null,
'pre-build': null,
'post-build': null,
'pre-release': null,
'post-release': 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', '5')
String baseDockerfile = options.get('baseDockerfile', '')
String baseImage = options.get('baseImage', 'reg.cadoles.com/proxy_cache/library/ubuntu:22.04')
String dockerfileExtension = options.get('dockerfileExtension', '')
List credentials = options.get('credentials', [])
List<String> releaseBranches = options.get('releaseBranches', ['develop', 'testing', 'stable', 'staging', 'master'])
node {
properties([
buildDiscarder(logRotator(daysToKeepStr: jobHistory, numToKeepStr: jobHistory)),
])
environment {
// Set MKT_PROJECT_VERSION_BRANCH_NAME to Jenkins current branch name by default
// See https://forge.cadoles.com/Cadoles/mktools project
MKT_PROJECT_VERSION_BRANCH_NAME = env.BRANCH_NAME
}
stage('Cancel older jobs') {
int buildNumber = env.BUILD_NUMBER as int
if (buildNumber > 1) {
milestone(buildNumber - 1)
}
milestone(buildNumber)
}
stage('Checkout project') {
checkout(scm)
}
try {
def containerImage = buildContainerImage(baseImage, baseDockerfile, dockerfileExtension)
containerImage.inside('-v /var/run/docker.sock:/var/run/docker.sock --network host') {
String repo = env.JOB_NAME
if (env.BRANCH_NAME ==~ /^PR-.*$/) {
repo = env.JOB_NAME - "/${env.JOB_BASE_NAME}"
}
List<String> environment = prepareEnvironment()
withEnv(environment) {
withCredentials(credentials) {
runHook(hooks, 'pre')
stage('Build project') {
runHook(hooks, 'pre-build')
runTask('buildTask', buildTask)
runHook(hooks, 'post-build')
}
stage('Run tests') {
runHook(hooks, 'pre-test')
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
def ( status, output ) = runAndCaptureTask('testTask', testTask)
if (!!output.trim() && env.CHANGE_ID) {
String gitCommit = sh(script: 'git rev-parse --short HEAD', returnStdout: true)
String report = """
|# Test report for ${gitCommit}
|
|<details ${output.count('\n') <= 10 ? 'open' : ''}>
|
|<summary>Output</summary>
|
|```
|${output}
|```
|
|</details>
|""".trim().stripMargin()
gitea.commentPullRequest(repo, env.CHANGE_ID, report)
}
if (status != 0) {
throw new Exception("Task `${testTask}` failed !")
}
}
runHook(hooks, 'post-test')
}
stage('Release project') {
if (releaseBranches.contains(env.BRANCH_NAME)) {
try {
runHook(hooks, 'pre-release')
runTask('releaseTask', releaseTask)
runHook(hooks, 'post-release')
} catch (Exception ex) {
rocketSend(
message: """
|:warning: Une erreur est survenue lors de la publication de [${repo}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}):
|
| - **Commit:** [${env.GIT_COMMIT}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}/commit/${env.GIT_COMMIT})
| - **Tags:** `${env.PROJECT_VERSION_TAG}` / `${env.PROJECT_VERSION_SHORT_TAG}`
|
| **Erreur**
|```
|${ex}
|```
|
|[Visualiser le job](${env.RUN_DISPLAY_URL})
|
|@${utils.getBuildUser()}
""".stripMargin(),
rawMessage: true
)
throw ex
}
rocketSend(
message: """
|:white_check_mark: Nouvelle publication terminée pour [${repo}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}):
|
| - **Commit:** [${env.GIT_COMMIT}](https://forge.cadoles.com/${repo - env.JOB_BASE_NAME}/commit/${env.GIT_COMMIT})
| - **Tags:** `${env.PROJECT_VERSION_TAG}` / `${env.PROJECT_VERSION_SHORT_TAG}`
|
|[Visualiser le job](${env.RUN_DISPLAY_URL})
|
|@${utils.getBuildUser()}
""".stripMargin(),
rawMessage: true
)
} 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 !")
}
}
void runTask(String name, task) {
if (!task) {
println("No task '${name}' defined. Skipping.")
return [ -1, '' ]
}
sh(script: """#!/bin/bash
make ${task}
""")
}
List runAndCaptureTask(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]
}
List<String> prepareEnvironment() {
List<String> env = []
def ( longTag, shortTag ) = utils.getProjectVersionTags()
env += ["PROJECT_VERSION_TAG=${longTag}"]
env += ["PROJECT_VERSION_SHORT_TAG=${shortTag}"]
String gitCommit = sh(script:'git rev-parse --short HEAD', returnStdout: true).trim()
env += ["GIT_COMMIT=${gitCommit}"]
Boolean isPR = utils.isPR()
env += ["IS_PR=${isPR ? 'true' : 'false'}"]
return env
}