HBASE-20314 Precommit build for master branch fails because of surefire fork fails
[hbase.git] / dev-support / Jenkinsfile
blobe8bf8c9f80a848abecfefdeb57674f5d9ad80f55
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements.  See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.  The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License.  You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied.  See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 pipeline {
18   agent {
19     node {
20       label 'ubuntu'
21     }
22   }
23   triggers {
24     cron('@daily')
25   }
26   options {
27     buildDiscarder(logRotator(numToKeepStr: '30'))
28     timeout (time: 9, unit: 'HOURS')
29     timestamps()
30     skipDefaultCheckout()
31   }
32   environment {
33     YETUS_RELEASE = '0.7.0'
34     // where we'll write everything from different steps. Need a copy here so the final step can check for success/failure.
35     OUTPUT_DIR_RELATIVE_GENERAL = 'output-general'
36     OUTPUT_DIR_RELATIVE_JDK7 = 'output-jdk7'
37     OUTPUT_DIR_RELATIVE_HADOOP2 = 'output-jdk8-hadoop2'
38     OUTPUT_DIR_RELATIVE_HADOOP3 = 'output-jdk8-hadoop3'
40     PROJECT = 'hbase'
41     PROJECT_PERSONALITY = 'https://raw.githubusercontent.com/apache/hbase/master/dev-support/hbase-personality.sh'
42     PERSONALITY_FILE = 'tools/personality.sh'
43     // This section of the docs tells folks not to use the javadoc tag. older branches have our old version of the check for said tag.
44     AUTHOR_IGNORE_LIST = 'src/main/asciidoc/_chapters/developer.adoc,dev-support/test-patch.sh'
45     WHITESPACE_IGNORE_LIST = '.*/generated/.*'
46     // output from surefire; sadly the archive function in yetus only works on file names.
47     ARCHIVE_PATTERN_LIST = 'TEST-*.xml,org.apache.h*.txt,*.dumpstream,*.dump'
48     // These tests currently have known failures. Once they burn down to 0, remove from here so that new problems will cause a failure.
49     TESTS_FILTER = 'cc,checkstyle,javac,javadoc,pylint,shellcheck,whitespace,perlcritic,ruby-lint,rubocop,mvnsite'
50     // Flaky urls for different branches. Replace '-' and '.' in branch name by '_' because those
51     // characters are not allowed in bash variable name.
52     // Not excluding flakies from the nightly build for now.
53     // EXCLUDE_TESTS_URL_master = 'https://builds.apache.org/job/HBase-Find-Flaky-Tests/lastSuccessfulBuild/artifact/excludes/'
54     // EXCLUDE_TESTS_URL_branch_2 = 'https://builds.apache.org/job/HBase-Find-Flaky-Tests-branch2.0/lastSuccessfulBuild/artifact/excludes/'
55   }
56   parameters {
57     booleanParam(name: 'USE_YETUS_PRERELEASE', defaultValue: false, description: '''Check to use the current HEAD of apache/yetus rather than our configured release.
59     Should only be used manually when e.g. there is some non-work-aroundable issue in yetus we are checking a fix for.''')
60     booleanParam(name: 'DEBUG', defaultValue: false, description: 'Produce a lot more meta-information.')
61   }
62   stages {
63     stage ('yetus install') {
64       steps {
65         sh  '''#!/usr/bin/env bash
66 echo "Ensure we have a copy of Apache Yetus."
67 if [[ true !=  "${USE_YETUS_PRERELEASE}" ]]; then
68   YETUS_DIR="${WORKSPACE}/yetus-${YETUS_RELEASE}"
69   echo "Checking for Yetus ${YETUS_RELEASE} in '${YETUS_DIR}'"
70   if [ ! -d "${YETUS_DIR}" ]; then
71     echo "New download of Apache Yetus version ${YETUS_RELEASE}."
72     rm -rf "${WORKSPACE}/.gpg"
73     mkdir -p "${WORKSPACE}/.gpg"
74     chmod -R 700 "${WORKSPACE}/.gpg"
76     echo "install yetus project KEYS"
77     curl -L --fail -o "${WORKSPACE}/KEYS_YETUS" https://dist.apache.org/repos/dist/release/yetus/KEYS
78     gpg --homedir "${WORKSPACE}/.gpg" --import "${WORKSPACE}/KEYS_YETUS"
80     echo "download yetus release ${YETUS_RELEASE}"
81     curl -L --fail -O "https://dist.apache.org/repos/dist/release/yetus/${YETUS_RELEASE}/yetus-${YETUS_RELEASE}-bin.tar.gz"
82     curl -L --fail -O "https://dist.apache.org/repos/dist/release/yetus/${YETUS_RELEASE}/yetus-${YETUS_RELEASE}-bin.tar.gz.asc"
83     echo "verifying yetus release"
84     gpg --homedir "${WORKSPACE}/.gpg" --verify "yetus-${YETUS_RELEASE}-bin.tar.gz.asc"
85     mv "yetus-${YETUS_RELEASE}-bin.tar.gz" yetus.tar.gz
86   else
87     echo "Reusing cached download of Apache Yetus version ${YETUS_RELEASE}."
88   fi
89 else
90   YETUS_DIR="${WORKSPACE}/yetus-git"
91   rm -rf "${YETUS_DIR}"
92   echo "downloading from github"
93   curl -L --fail https://api.github.com/repos/apache/yetus/tarball/HEAD -o yetus.tar.gz
95 if [ ! -d "${YETUS_DIR}" ]; then
96   echo "unpacking yetus into '${YETUS_DIR}'"
97   mkdir -p "${YETUS_DIR}"
98   gunzip -c yetus.tar.gz | tar xpf - -C "${YETUS_DIR}" --strip-components 1
100         '''
101         // Set up the file we need at PERSONALITY_FILE location
102         dir ("tools") {
103           sh """#!/usr/bin/env bash
104 echo "Downloading Project personality."
105 curl -L  -o personality.sh "${env.PROJECT_PERSONALITY}"
106           """
107         }
108         stash name: 'yetus', includes: "yetus-*/*,yetus-*/**/*,tools/personality.sh"
109       }
110     }
111     stage ('init health results') {
112       steps {
113         // stash with given name for all tests we might run, so that we can unstash all of them even if
114         // we skip some due to e.g. branch-specific JDK or Hadoop support
115         stash name: 'general-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_GENERAL}/doesn't-match"
116         stash name: 'jdk7-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_JDK7}/doesn't-match"
117         stash name: 'hadoop2-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_HADOOP2}/doesn't-match"
118         stash name: 'hadoop3-result', allowEmpty: true, includes: "${OUTPUT_DIR_RELATIVE_HADOOP3}/doesn't-match"
119         stash name: 'srctarball-result', allowEmpty: true, includes: "output-srctarball/doesn't-match"
120       }
121     }
122     stage ('health checks') {
123       parallel {
124         stage ('yetus general check') {
125           agent {
126             node {
127               label 'Hadoop'
128             }
129           }
130           environment {
131             BASEDIR = "${env.WORKSPACE}/component"
132             // TODO does hadoopcheck need to be jdk specific?
133             // Should be things that work with multijdk
134             TESTS = 'all,-unit,-findbugs'
135             // on branches that don't support jdk7, this will already be JAVA_HOME, so we'll end up not
136             // doing multijdk there.
137             MULTIJDK = '/usr/lib/jvm/java-8-openjdk-amd64'
138             OUTPUT_DIR_RELATIVE = "${env.OUTPUT_DIR_RELATIVE_GENERAL}"
139             OUTPUT_DIR = "${env.WORKSPACE}/${env.OUTPUT_DIR_RELATIVE_GENERAL}"
140           }
141           steps {
142             unstash 'yetus'
143             dir('component') {
144               checkout scm
145             }
146             sh '''#!/usr/bin/env bash
147               rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
148               rm -rf "${OUTPUT_DIR}/machine" && mkdir "${OUTPUT_DIR}/machine"
149               "${BASEDIR}/dev-support/gather_machine_environment.sh" "${OUTPUT_DIR_RELATIVE}/machine"
151             // TODO roll this into the hbase_nightly_yetus script
152             sh '''#!/usr/bin/env bash
153               rm -rf "${OUTPUT_DIR}/commentfile}"
154               declare -i status=0
155               if "${BASEDIR}/dev-support/hbase_nightly_yetus.sh" ; then
156                 echo '(/) {color:green}+1 general checks{color}' >> "${OUTPUT_DIR}/commentfile"
157               else
158                 echo '(x) {color:red}-1 general checks{color}' >> "${OUTPUT_DIR}/commentfile"
159                 status=1
160               fi
161               echo "-- For more information [see general report|${BUILD_URL}/General_Nightly_Build_Report/]" >> "${OUTPUT_DIR}/commentfile"
162               exit "${status}"
163             '''
164           }
165           post {
166             always {
167               stash name: 'general-result', includes: "${OUTPUT_DIR_RELATIVE}/commentfile"
168               // Has to be relative to WORKSPACE.
169               archive "${env.OUTPUT_DIR_RELATIVE}/*"
170               archive "${env.OUTPUT_DIR_RELATIVE}/**/*"
171               publishHTML target: [
172                 allowMissing: true,
173                 keepAll: true,
174                 alwaysLinkToLastBuild: true,
175                 // Has to be relative to WORKSPACE
176                 reportDir: "${env.OUTPUT_DIR_RELATIVE}",
177                 reportFiles: 'console-report.html',
178                 reportName: 'General Nightly Build Report'
179               ]
180             }
181           }
182         }
183         stage ('yetus jdk7 checks') {
184           agent {
185             node {
186               label 'Hadoop'
187             }
188           }
189           when {
190             branch 'branch-1*'
191           }
192           environment {
193             BASEDIR = "${env.WORKSPACE}/component"
194             TESTS = 'mvninstall,compile,javac,unit,htmlout'
195             OUTPUT_DIR_RELATIVE = "${env.OUTPUT_DIR_RELATIVE_JDK7}"
196             OUTPUT_DIR = "${env.WORKSPACE}/${env.OUTPUT_DIR_RELATIVE_JDK7}"
197             // On branches where we do jdk7 checks, jdk7 will be JAVA_HOME already.
198           }
199           steps {
200             unstash 'yetus'
201             dir('component') {
202               checkout scm
203             }
204             sh '''#!/usr/bin/env bash
205               rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
206               rm -rf "${OUTPUT_DIR}/machine" && mkdir "${OUTPUT_DIR}/machine"
207               "${BASEDIR}/dev-support/gather_machine_environment.sh" "${OUTPUT_DIR_RELATIVE}/machine"
209             sh '''#!/usr/bin/env bash
210               rm -rf "${OUTPUT_DIR}/commentfile}"
211               declare -i status=0
212               if "${BASEDIR}/dev-support/hbase_nightly_yetus.sh" ; then
213                 echo '(/) {color:green}+1 jdk7 checks{color}' >> "${OUTPUT_DIR}/commentfile"
214               else
215                 echo '(x) {color:red}-1 jdk7 checks{color}' >> "${OUTPUT_DIR}/commentfile"
216                 status=1
217               fi
218               echo "-- For more information [see jdk7 report|${BUILD_URL}/JDK7_Nightly_Build_Report/]" >> "${OUTPUT_DIR}/commentfile"
219               exit "${status}"
220             '''
221           }
222           post {
223             always {
224               stash name: 'jdk7-result', includes: "${OUTPUT_DIR_RELATIVE}/commentfile"
225               junit testResults: "${env.OUTPUT_DIR_RELATIVE}/**/target/**/TEST-*.xml", allowEmptyResults: true
226               // zip surefire reports.
227               sh '''#!/bin/bash -e
228                 if [ -d "${OUTPUT_DIR}/archiver" ]; then
229                   count=$(find "${OUTPUT_DIR}/archiver" -type f | wc -l)
230                   if [[ 0 -ne ${count} ]]; then
231                     echo "zipping ${count} archived files"
232                     zip -q -m -r "${OUTPUT_DIR}/test_logs.zip" "${OUTPUT_DIR}/archiver"
233                   else
234                     echo "No archived files, skipping compressing."
235                   fi
236                 else
237                   echo "No archiver directory, skipping compressing."
238                 fi
240               // Has to be relative to WORKSPACE.
241               archive "${env.OUTPUT_DIR_RELATIVE}/*"
242               archive "${env.OUTPUT_DIR_RELATIVE}/**/*"
243               publishHTML target: [
244                 allowMissing         : true,
245                 keepAll              : true,
246                 alwaysLinkToLastBuild: true,
247                 // Has to be relative to WORKSPACE.
248                 reportDir            : "${env.OUTPUT_DIR_RELATIVE}",
249                 reportFiles          : 'console-report.html',
250                 reportName           : 'JDK7 Nightly Build Report'
251               ]
252             }
253           }
254         }
255         stage ('yetus jdk8 hadoop2 checks') {
256           agent {
257             node {
258               label 'Hadoop'
259             }
260           }
261           environment {
262             BASEDIR = "${env.WORKSPACE}/component"
263             TESTS = 'mvninstall,compile,javac,unit,findbugs,htmlout'
264             OUTPUT_DIR_RELATIVE = "${env.OUTPUT_DIR_RELATIVE_HADOOP2}"
265             OUTPUT_DIR = "${env.WORKSPACE}/${env.OUTPUT_DIR_RELATIVE_HADOOP2}"
266             // This isn't strictly needed on branches that only support jdk8, but doesn't hurt
267             // and is needed on branches that do both jdk7 and jdk8
268             SET_JAVA_HOME = '/usr/lib/jvm/java-8-openjdk-amd64'
269           }
270           steps {
271             unstash 'yetus'
272             dir('component') {
273               checkout scm
274             }
275             sh '''#!/usr/bin/env bash
276               rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
277               rm -rf "${OUTPUT_DIR}/machine" && mkdir "${OUTPUT_DIR}/machine"
278               "${BASEDIR}/dev-support/gather_machine_environment.sh" "${OUTPUT_DIR_RELATIVE}/machine"
280             sh '''#!/usr/bin/env bash
281               rm -rf "${OUTPUT_DIR}/commentfile}"
282               declare -i status=0
283               if "${BASEDIR}/dev-support/hbase_nightly_yetus.sh" ; then
284                 echo '(/) {color:green}+1 jdk8 hadoop2 checks{color}' >> "${OUTPUT_DIR}/commentfile"
285               else
286                 echo '(x) {color:red}-1 jdk8 hadoop2 checks{color}' >> "${OUTPUT_DIR}/commentfile"
287                 status=1
288               fi
289               echo "-- For more information [see jdk8 (hadoop2) report|${BUILD_URL}/JDK8_Nightly_Build_Report_(Hadoop2)/]" >> "${OUTPUT_DIR}/commentfile"
290               exit "${status}"
291             '''
292           }
293           post {
294             always {
295               stash name: 'hadoop2-result', includes: "${OUTPUT_DIR_RELATIVE}/commentfile"
296               junit testResults: "${env.OUTPUT_DIR_RELATIVE}/**/target/**/TEST-*.xml", allowEmptyResults: true
297               // zip surefire reports.
298               sh '''#!/bin/bash -e
299                 if [ -d "${OUTPUT_DIR}/archiver" ]; then
300                   count=$(find "${OUTPUT_DIR}/archiver" -type f | wc -l)
301                   if [[ 0 -ne ${count} ]]; then
302                     echo "zipping ${count} archived files"
303                     zip -q -m -r "${OUTPUT_DIR}/test_logs.zip" "${OUTPUT_DIR}/archiver"
304                   else
305                     echo "No archived files, skipping compressing."
306                   fi
307                 else
308                   echo "No archiver directory, skipping compressing."
309                 fi
311               // Has to be relative to WORKSPACE.
312               archive "${env.OUTPUT_DIR_RELATIVE}/*"
313               archive "${env.OUTPUT_DIR_RELATIVE}/**/*"
314               publishHTML target: [
315                 allowMissing         : true,
316                 keepAll              : true,
317                 alwaysLinkToLastBuild: true,
318                 // Has to be relative to WORKSPACE.
319                 reportDir            : "${env.OUTPUT_DIR_RELATIVE}",
320                 reportFiles          : 'console-report.html',
321                 reportName           : 'JDK8 Nightly Build Report (Hadoop2)'
322               ]
323             }
324           }
325         }
326         stage ('yetus jdk8 hadoop3 checks') {
327           agent {
328             node {
329               label 'Hadoop'
330             }
331           }
332           when {
333             not {
334               branch 'branch-1*'
335             }
336           }
337           environment {
338             BASEDIR = "${env.WORKSPACE}/component"
339             TESTS = 'mvninstall,compile,javac,unit,htmlout'
340             OUTPUT_DIR_RELATIVE = "${env.OUTPUT_DIR_RELATIVE_HADOOP3}"
341             OUTPUT_DIR = "${env.WORKSPACE}/${env.OUTPUT_DIR_RELATIVE_HADOOP3}"
342             // This isn't strictly needed on branches that only support jdk8, but doesn't hurt
343             // and is needed on branches that do both jdk7 and jdk8
344             SET_JAVA_HOME = '/usr/lib/jvm/java-8-openjdk-amd64'
345             // Activates hadoop 3.0 profile in maven runs.
346             HADOOP_PROFILE = '3.0'
347           }
348           steps {
349             unstash 'yetus'
350             dir('component') {
351               checkout scm
352             }
353             sh '''#!/usr/bin/env bash
354               rm -rf "${OUTPUT_DIR}" && mkdir "${OUTPUT_DIR}"
355               rm -rf "${OUTPUT_DIR}/machine" && mkdir "${OUTPUT_DIR}/machine"
356               "${BASEDIR}/dev-support/gather_machine_environment.sh" "${OUTPUT_DIR_RELATIVE}/machine"
358             sh '''#!/usr/bin/env bash
359               rm -rf "${OUTPUT_DIR}/commentfile}"
360               declare -i status=0
361               if "${BASEDIR}/dev-support/hbase_nightly_yetus.sh" ; then
362                 echo '(/) {color:green}+1 jdk8 hadoop3 checks{color}' >> "${OUTPUT_DIR}/commentfile"
363               else
364                 echo '(x) {color:red}-1 jdk8 hadoop3 checks{color}' >> "${OUTPUT_DIR}/commentfile"
365                 status=1
366               fi
367               echo "-- For more information [see jdk8 (hadoop3) report|${BUILD_URL}/JDK8_Nightly_Build_Report_(Hadoop3)/]" >> "${OUTPUT_DIR}/commentfile"
368               exit "${status}"
369             '''
370           }
371           post {
372             always {
373               stash name: 'hadoop3-result', includes: "${OUTPUT_DIR_RELATIVE}/commentfile"
374               // Not sure how two junit test reports will work. Disabling this for now.
375               // junit testResults: "${env.OUTPUT_DIR_RELATIVE}/**/target/**/TEST-*.xml", allowEmptyResults: true
376               // zip surefire reports.
377               sh '''#!/bin/bash -e
378                 if [ -d "${OUTPUT_DIR}/archiver" ]; then
379                   count=$(find "${OUTPUT_DIR}/archiver" -type f | wc -l)
380                   if [[ 0 -ne ${count} ]]; then
381                     echo "zipping ${count} archived files"
382                     zip -q -m -r "${OUTPUT_DIR}/test_logs.zip" "${OUTPUT_DIR}/archiver"
383                   else
384                     echo "No archived files, skipping compressing."
385                   fi
386                 else
387                   echo "No archiver directory, skipping compressing."
388                 fi
390               // Has to be relative to WORKSPACE.
391               archive "${env.OUTPUT_DIR_RELATIVE}/*"
392               archive "${env.OUTPUT_DIR_RELATIVE}/**/*"
393               publishHTML target: [
394                 allowMissing         : true,
395                 keepAll              : true,
396                 alwaysLinkToLastBuild: true,
397                 // Has to be relative to WORKSPACE.
398                 reportDir            : "${env.OUTPUT_DIR_RELATIVE}",
399                 reportFiles          : 'console-report.html',
400                 reportName           : 'JDK8 Nightly Build Report (Hadoop3)'
401               ]
402             }
403           }
404         }
405         // This is meant to mimic what a release manager will do to create RCs.
406         // See http://hbase.apache.org/book.html#maven.release
407         stage ('create source tarball') {
408           tools {
409             maven 'Maven (latest)'
410             // this needs to be set to the jdk that ought to be used to build releases on the branch the Jenkinsfile is stored in.
411             jdk "JDK 1.8 (latest)"
412           }
413           environment {
414             BASEDIR = "${env.WORKSPACE}/component"
415           }
416           steps {
417             sh '''#!/bin/bash -e
418               echo "Setting up directories"
419               rm -rf "output-srctarball" && mkdir "output-srctarball"
420               rm -rf "unpacked_src_tarball" && mkdir "unpacked_src_tarball"
421               rm -rf ".m2-for-repo" && mkdir ".m2-for-repo"
422               rm -rf ".m2-for-src" && mkdir ".m2-for-src"
424             dir('component') {
425               checkout scm
426             }
427             sh '''#!/usr/bin/env bash
428               rm -rf "output-srctarball/machine" && mkdir "output-srctarball/machine"
429               "${BASEDIR}/dev-support/gather_machine_environment.sh" "output-srctarball/machine"
431             sh """#!/bin/bash -e
432               if "${env.BASEDIR}/dev-support/hbase_nightly_source-artifact.sh" \
433                   --intermediate-file-dir output-srctarball \
434                   --unpack-temp-dir unpacked_src_tarball \
435                   --maven-m2-initial .m2-for-repo \
436                   --maven-m2-src-build .m2-for-src \
437                   --clean-source-checkout \
438                   "${env.BASEDIR}" ; then
439                 echo '(/) {color:green}+1 source release artifact{color}\n-- See build output for details.' >output-srctarball/commentfile
440               else
441                 echo '(x) {color:red}-1 source release artifact{color}\n-- See build output for details.' >output-srctarball/commentfile
442               fi
444           }
445           post {
446             always {
447               stash name: 'srctarball-result', includes: "output-srctarball/commentfile"
448               archive 'output-srctarball/*'
449             }
450           }
451         }
452       }
453     }
454   }
455   post {
456     always {
457       script {
458          try {
459            unstash 'general-result'
460            unstash 'jdk7-result'
461            unstash 'hadoop2-result'
462            unstash 'hadoop3-result'
463            unstash 'srctarball-result'
464            sh "printenv"
465            def results = ["${env.OUTPUT_DIR_RELATIVE_GENERAL}/commentfile",
466                           "${env.OUTPUT_DIR_RELATIVE_JDK7}/commentfile",
467                           "${env.OUTPUT_DIR_RELATIVE_HADOOP2}/commentfile",
468                           "${env.OUTPUT_DIR_RELATIVE_HADOOP3}/commentfile",
469                           'output-srctarball/commentfile']
470            echo env.BRANCH_NAME
471            echo env.BUILD_URL
472            echo currentBuild.result
473            echo currentBuild.durationString
474            def comment = "Results for branch ${env.BRANCH_NAME}\n"
475            comment += "\t[build ${currentBuild.displayName} on builds.a.o|${env.BUILD_URL}]: "
476            if (currentBuild.result == "SUCCESS") {
477               comment += "(/) *{color:green}+1 overall{color}*\n"
478            } else {
479               comment += "(x) *{color:red}-1 overall{color}*\n"
480               // Ideally get the committer our of the change and @ mention them in the per-jira comment
481            }
482            comment += "----\ndetails (if available):\n\n"
483            echo ""
484            echo "[DEBUG] trying to aggregate step-wise results"
485            comment += results.collect { fileExists(file: it) ? readFile(file: it) : "" }.join("\n\n")
486            echo "[INFO] Comment:"
487            echo comment
488            echo ""
489            echo "[INFO] There are ${currentBuild.changeSets.size()} change sets."
490            getJirasToComment(currentBuild).each { currentIssue ->
491              jiraComment issueKey: currentIssue, body: comment
492            }
493         } catch (Exception exception) {
494           echo "Got exception: ${exception}"
495           echo "    ${exception.getStackTrace()}"
496         }
497       }
498     }
499   }
501 import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper
502 @NonCPS
503 List<String> getJirasToComment(RunWrapper thisBuild) {
504   def seenJiras = []
505   thisBuild.changeSets.each { cs ->
506     cs.getItems().each { change ->
507       CharSequence msg = change.msg
508       echo "change: ${change}"
509       echo "     ${msg}"
510       echo "     ${change.commitId}"
511       echo "     ${change.author}"
512       echo ""
513       msg.eachMatch("HBASE-[0-9]+") { currentIssue ->
514         echo "[DEBUG] found jira key: ${currentIssue}"
515         if (currentIssue in seenJiras) {
516           echo "[DEBUG] already commented on ${currentIssue}."
517         } else {
518           echo "[INFO] commenting on ${currentIssue}."
519           seenJiras << currentIssue
520         }
521       }
522     }
523   }
524   return seenJiras