From c42985576c24a522fb1361258235e46624ab239a Mon Sep 17 00:00:00 2001 From: William Petit Date: Thu, 17 Aug 2023 07:43:26 -0600 Subject: [PATCH] feat(standard-make): create standard make-based pipeline --- .../com/cadoles/standard-make/Dockerfile | 14 ++ vars/standardMakePipeline.groovy | 132 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 resources/com/cadoles/standard-make/Dockerfile create mode 100644 vars/standardMakePipeline.groovy diff --git a/resources/com/cadoles/standard-make/Dockerfile b/resources/com/cadoles/standard-make/Dockerfile new file mode 100644 index 0000000..642b8fa --- /dev/null +++ b/resources/com/cadoles/standard-make/Dockerfile @@ -0,0 +1,14 @@ +ARG JQ_VERSION=1.6 + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + wget tar curl ca-certificates \ + openssl bash git unzip build-essential + +COPY add-letsencrypt-ca.sh /root/add-letsencrypt-ca.sh + +RUN bash /root/add-letsencrypt-ca.sh \ + && rm -f /root/add-letsencrypt-ca.sh + +RUN wget -O /usr/local/bin/jq https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64 \ + && chmod +x /usr/local/bin/jq \ No newline at end of file diff --git a/vars/standardMakePipeline.groovy b/vars/standardMakePipeline.groovy new file mode 100644 index 0000000..22d78d0 --- /dev/null +++ b/vars/standardMakePipeline.groovy @@ -0,0 +1,132 @@ +import org.jenkinsci.plugins.pipeline.modeldefinition.Utils + +def call(Map options = [:]) { + String baseImage = options.get('baseImage', 'reg.cadoles.com/proxy_cache/library/ubuntu:22.04') + Map hooks = options.get('hooks', [ + 'pre': null, + 'post-success': null, + 'post-always': null, + 'post-failure': null, + ]) + Map tasks = options.get('tasks', [ + 'test': 'test', + 'build': 'build', + 'release': 'release' + ]) + String jobHistory = options.get('jobHistory', '10') + String dockerfileExtension = options.get('dockerfileExtension', '') + + 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 pre hooks') { + runHook(hooks, 'pre') + } + + stage('Run in container') { + def containerImage = buildContainerImage(baseImage, 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 tests') { + catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { + String testReport = runTask(tasks, 'test', true) + + if (!!testReport?.trim()) { + if (env.CHANGE_ID) { + gitea.commentPullRequest(repo, env.CHANGE_ID, "# Test report\n\n ${testReport}") + } else { + print testReport + } + } + } + } + + stage('Build project') { + runTask(tasks, 'build') + } + + stage('Release project') { + runTask(tasks, 'release') + } + } + + post { + success { + runHook(hooks, 'post-success') + } + always { + runHook(hooks, 'post-always') + cleanWs() + } + failure { + runHook(hooks, 'post-failure') + } + } + } + } +} + +void buildContainerImage(String baseImage, String dockerfileExtension) { + String imageName = 'cadoles-standard-make-ci' + dir(".${imageName}") { + String dockerfile = libraryResource 'com/cadoles/standard-make/Dockerfile' + + dockerfile = """ + ${dockerfile} + ${dockerfileExtension} + """ + + writeFile file:'Dockerfile', text: "FROM ${baseImage}\n\n" + 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) { + if (!hooks[name]) { + println("No hook '${name}' defined. Skipping.") + return + } + + if (hooks[name] instanceof Closure) { + hooks[name]() + } else { + error("Hook '${name}' seems to be defined but is not a closure !") + } +} + +String runTask(Map tasks, String name, Boolean returnStdout = false) { + if (!tasks[name]) { + println("No task '${name}' defined. Skipping.") + return + } + + String result = sh(script: "make ${tasks[name]}", returnStdout: returnStdout) + + return result +}