1#!/usr/bin/env groovy 2 3@Library('apm@current') _ 4 5pipeline { 6 agent { label 'linux && immutable' } 7 environment { 8 REPO = 'apm-agent-go' 9 BASE_DIR = "src/go.elastic.co/apm" 10 NOTIFY_TO = credentials('notify-to') 11 JOB_GCS_BUCKET = credentials('gcs-bucket') 12 CODECOV_SECRET = 'secret/apm-team/ci/apm-agent-go-codecov' 13 GO111MODULE = 'on' 14 GOPATH = "${env.WORKSPACE}" 15 GOPROXY = 'https://proxy.golang.org' 16 HOME = "${env.WORKSPACE}" 17 GITHUB_CHECK_ITS_NAME = 'Integration Tests' 18 ITS_PIPELINE = 'apm-integration-tests-selector-mbp/master' 19 OPBEANS_REPO = 'opbeans-go' 20 SLACK_CHANNEL = '#apm-agent-go' 21 } 22 options { 23 timeout(time: 1, unit: 'HOURS') 24 buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20', daysToKeepStr: '30')) 25 timestamps() 26 ansiColor('xterm') 27 disableResume() 28 durabilityHint('PERFORMANCE_OPTIMIZED') 29 rateLimitBuilds(throttle: [count: 60, durationName: 'hour', userBoost: true]) 30 quietPeriod(10) 31 } 32 triggers { 33 issueCommentTrigger('(?i).*(?:jenkins\\W+)?run\\W+(?:the\\W+)?(?:benchmark\\W+)?tests(?:\\W+please)?.*') 34 } 35 parameters { 36 string(name: 'GO_VERSION', defaultValue: "1.15.10", description: "Go version to use.") 37 booleanParam(name: 'Run_As_Master_Branch', defaultValue: false, description: 'Allow to run any steps on a PR, some steps normally only run on master branch.') 38 booleanParam(name: 'test_ci', defaultValue: true, description: 'Enable test') 39 booleanParam(name: 'docker_test_ci', defaultValue: true, description: 'Enable run docker tests') 40 booleanParam(name: 'bench_ci', defaultValue: true, description: 'Enable benchmarks') 41 } 42 stages { 43 stage('Initializing'){ 44 options { skipDefaultCheckout() } 45 environment { 46 GO_VERSION = "${params.GO_VERSION}" 47 PATH = "${env.PATH}:${env.WORKSPACE}/bin" 48 } 49 stages { 50 /** 51 Checkout the code and stash it, to use it on other stages. 52 */ 53 stage('Checkout') { 54 options { skipDefaultCheckout() } 55 steps { 56 pipelineManager([ cancelPreviousRunningBuilds: [ when: 'PR' ] ]) 57 deleteDir() 58 gitCheckout(basedir: "${BASE_DIR}", githubNotifyFirstTimeContributor: true, reference: '/var/lib/jenkins/.git-references/apm-agent-go.git') 59 stash allowEmpty: true, name: 'source', useDefaultExcludes: false 60 script { 61 dir("${BASE_DIR}"){ 62 // Skip all the stages except docs for PR's with asciidoc and md changes only 63 env.ONLY_DOCS = isGitRegionMatch(patterns: [ '.*\\.(asciidoc|md)' ], shouldMatchAll: true) 64 } 65 } 66 } 67 } 68 /** 69 Execute unit tests. 70 */ 71 stage('Tests') { 72 options { skipDefaultCheckout() } 73 when { 74 beforeAgent true 75 allOf { 76 expression { return env.ONLY_DOCS == "false" } 77 expression { return params.test_ci } 78 } 79 } 80 steps { 81 withGithubNotify(context: 'Tests', tab: 'tests') { 82 deleteDir() 83 unstash 'source' 84 dir("${BASE_DIR}"){ 85 script { 86 def go = readYaml(file: '.jenkins.yml') 87 def parallelTasks = [:] 88 go['GO_VERSION'].each{ version -> 89 parallelTasks["Go-${version}"] = generateStep(version) 90 } 91 // For the cutting edge 92 def edge = readYaml(file: '.jenkins-edge.yml') 93 edge['GO_VERSION'].each{ version -> 94 parallelTasks["Go-${version}"] = generateStepAndCatchError(version) 95 } 96 parallel(parallelTasks) 97 } 98 } 99 } 100 } 101 } 102 stage('Coverage') { 103 options { skipDefaultCheckout() } 104 when { 105 beforeAgent true 106 allOf { 107 expression { return env.ONLY_DOCS == "false" } 108 expression { return params.docker_test_ci } 109 } 110 } 111 steps { 112 withGithubNotify(context: 'Coverage') { 113 deleteDir() 114 unstash 'source' 115 dir("${BASE_DIR}"){ 116 sh script: './scripts/jenkins/before_install.sh', label: 'Install dependencies' 117 sh script: './scripts/jenkins/docker-test.sh', label: 'Docker tests' 118 } 119 } 120 } 121 post { 122 always { 123 coverageReport("${BASE_DIR}/build/coverage") 124 codecov(repo: env.REPO, basedir: "${BASE_DIR}", 125 flags: "-f build/coverage/coverage.cov -X search", 126 secret: "${CODECOV_SECRET}") 127 junit(allowEmptyResults: true, 128 keepLongStdio: true, 129 testResults: "${BASE_DIR}/build/junit-*.xml") 130 } 131 } 132 } 133 stage('Benchmark') { 134 agent { label 'linux && immutable' } 135 options { skipDefaultCheckout() } 136 when { 137 beforeAgent true 138 allOf { 139 anyOf { 140 branch 'master' 141 tag pattern: 'v\\d+\\.\\d+\\.\\d+.*', comparator: 'REGEXP' 142 expression { return params.Run_As_Master_Branch } 143 expression { return env.GITHUB_COMMENT?.contains('benchmark tests') } 144 } 145 expression { return params.bench_ci } 146 } 147 } 148 steps { 149 withGithubNotify(context: 'Benchmark', tab: 'tests') { 150 deleteDir() 151 unstash 'source' 152 dir("${BASE_DIR}"){ 153 sh script: './scripts/jenkins/before_install.sh', label: 'Install dependencies' 154 sh script: './scripts/jenkins/bench.sh', label: 'Benchmarking' 155 sendBenchmarks(file: 'build/bench.out', index: 'benchmark-go') 156 } 157 } 158 } 159 } 160 } 161 } 162 stage('More OS') { 163 when { 164 beforeAgent true 165 expression { return env.ONLY_DOCS == "false" } 166 } 167 parallel { 168 stage('Windows') { 169 agent { label 'windows-2019-immutable' } 170 options { skipDefaultCheckout() } 171 environment { 172 GO_VERSION = "${params.GO_VERSION}" 173 } 174 steps { 175 withGithubNotify(context: 'Build-Test - Windows') { 176 cleanDir("${WORKSPACE}/${BASE_DIR}") 177 unstash 'source' 178 withGoEnv(version: "${env.GO_VERSION}"){ 179 dir("${BASE_DIR}"){ 180 bat script: 'scripts/jenkins/windows/build-test.bat', label: 'Build and test' 181 } 182 } 183 } 184 } 185 post { 186 always { 187 junit(allowEmptyResults: true, keepLongStdio: true, testResults: "${BASE_DIR}/build/junit-*.xml") 188 } 189 } 190 } 191 stage('OSX') { 192 agent { label 'macosx && x86_64' } 193 options { skipDefaultCheckout() } 194 environment { 195 GO_VERSION = "${params.GO_VERSION}" 196 PATH = "${env.PATH}:${env.WORKSPACE}/bin" 197 } 198 steps { 199 withGithubNotify(context: 'Build-Test - OSX') { 200 retry(3) { 201 deleteDir() 202 unstash 'source' 203 dir("${BASE_DIR}"){ 204 sh script: './scripts/jenkins/before_install.sh', label: 'Install dependencies' 205 } 206 } 207 retry(3) { 208 dir("${BASE_DIR}"){ 209 sh script: './scripts/jenkins/build.sh', label: 'Build' 210 } 211 } 212 dir("${BASE_DIR}"){ 213 sh script: './scripts/jenkins/test.sh', label: 'Test' 214 } 215 } 216 } 217 post { 218 always { 219 junit(allowEmptyResults: true, keepLongStdio: true, testResults: "${BASE_DIR}/build/junit-*.xml") 220 deleteDir() 221 } 222 } 223 } 224 } 225 } 226 stage('Integration Tests') { 227 agent none 228 when { 229 beforeAgent true 230 allOf { 231 expression { return env.ONLY_DOCS == "false" } 232 anyOf { 233 changeRequest() 234 expression { return !params.Run_As_Master_Branch } 235 } 236 } 237 } 238 steps { 239 build(job: env.ITS_PIPELINE, propagate: false, wait: false, 240 parameters: [string(name: 'INTEGRATION_TEST', value: 'Go'), 241 string(name: 'BUILD_OPTS', value: "--go-agent-version ${env.GIT_BASE_COMMIT} --opbeans-go-agent-branch ${env.GIT_BASE_COMMIT}"), 242 string(name: 'GITHUB_CHECK_NAME', value: env.GITHUB_CHECK_ITS_NAME), 243 string(name: 'GITHUB_CHECK_REPO', value: env.REPO), 244 string(name: 'GITHUB_CHECK_SHA1', value: env.GIT_BASE_COMMIT)]) 245 githubNotify(context: "${env.GITHUB_CHECK_ITS_NAME}", description: "${env.GITHUB_CHECK_ITS_NAME} ...", status: 'PENDING', targetUrl: "${env.JENKINS_URL}search/?q=${env.ITS_PIPELINE.replaceAll('/','+')}") 246 } 247 } 248 stage('Release') { 249 options { skipDefaultCheckout() } 250 when { 251 beforeAgent true 252 tag pattern: 'v\\d+\\.\\d+\\.\\d+', comparator: 'REGEXP' 253 } 254 stages { 255 stage('Opbeans') { 256 environment { 257 REPO_NAME = "${OPBEANS_REPO}" 258 GO_VERSION = "${params.GO_VERSION}" 259 } 260 steps { 261 deleteDir() 262 dir("${OPBEANS_REPO}"){ 263 git credentialsId: 'f6c7695a-671e-4f4f-a331-acdce44ff9ba', 264 url: "git@github.com:elastic/${OPBEANS_REPO}.git" 265 sh script: ".ci/bump-version.sh ${env.BRANCH_NAME}", label: 'Bump version' 266 // The opbeans-go pipeline will trigger a release for the master branch 267 gitPush() 268 // The opbeans-go pipeline will trigger a release for the release tag 269 gitCreateTag(tag: "${env.BRANCH_NAME}") 270 } 271 } 272 } 273 stage('Notify') { 274 steps { 275 notifyStatus(slackStatus: 'good', subject: "[${env.REPO}] Release *${env.BRANCH_NAME}* published", body: "Great news, the release has finished successfully. (<${env.RUN_DISPLAY_URL}|Open>).") 276 } 277 } 278 } 279 } 280 } 281 post { 282 cleanup { 283 notifyBuildResult() 284 } 285 } 286} 287 288def generateStep(version){ 289 return { 290 node('linux && immutable'){ 291 try { 292 echo "${version}" 293 withEnv(["GO_VERSION=${version}"]) { 294 // Another retry in case there are any environmental issues 295 // See https://issuetracker.google.com/issues/146072599 for more context 296 retry(3) { 297 deleteDir() 298 unstash 'source' 299 dir("${BASE_DIR}"){ 300 sh script: './scripts/jenkins/before_install.sh', label: 'Install dependencies' 301 } 302 } 303 retry(3) { 304 dir("${BASE_DIR}"){ 305 sh script: './scripts/jenkins/build.sh', label: 'Build' 306 } 307 } 308 dir("${BASE_DIR}"){ 309 sh script: './scripts/jenkins/test.sh', label: 'Test' 310 } 311 } 312 } catch(e){ 313 error(e.toString()) 314 } finally { 315 junit(allowEmptyResults: true, 316 keepLongStdio: true, 317 testResults: "${BASE_DIR}/build/junit-*.xml") 318 } 319 } 320 } 321} 322 323def generateStepAndCatchError(version){ 324 return { 325 catchError(buildResult: 'SUCCESS', message: 'Cutting Edge Tests', stageResult: 'UNSTABLE') { 326 generateStep(version) 327 } 328 } 329} 330 331def cleanDir(path){ 332 powershell label: "Clean ${path}", script: "Remove-Item -Recurse -Force ${path}" 333} 334 335def notifyStatus(def args = [:]) { 336 releaseNotification(slackChannel: "${env.SLACK_CHANNEL}", 337 slackColor: args.slackStatus, 338 slackCredentialsId: 'jenkins-slack-integration-token', 339 to: "${env.NOTIFY_TO}", 340 subject: args.subject, 341 body: args.body) 342} 343