github.com/verrazzano/verrazzano@v1.7.1/ci/JenkinsfileTestTrigger (about) 1 // Copyright (c) 2020, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 import groovy.transform.Field 5 6 @Field 7 def SUSPECT_LIST = "" 8 9 pipeline { 10 options { 11 timeout(time: 5, unit: 'HOURS') 12 skipDefaultCheckout true 13 } 14 15 agent { 16 docker { 17 image "${RUNNER_DOCKER_IMAGE}" 18 args "${RUNNER_DOCKER_ARGS}" 19 registryUrl "${RUNNER_DOCKER_REGISTRY_URL}" 20 registryCredentialsId 'ocir-pull-and-push-account' 21 label "pipeline-job-large" 22 } 23 } 24 25 // Use cases: 26 // 1) (automatic) master, release* will trigger this job by default on successful runs and supply GIT_COMMIT_TO_USE with the exact GIT commit to use for all testing (same as the upstream build) 27 // 2) (automatic) branch builds with TRIGGER_FULL_TESTS enabled will trigger this job by default on successful runs and supply GIT_COMMIT_TO_USE with the exact GIT commit to use for all testing (same as the upstream build) 28 // 3) (manual) any branch should be able to call this “trigger” job with a commit that was previously built and has a valid GIT commit hash. In this case the manual job 29 // must be started from the desired branch using Build with Parameters, the GIT_COMMIT_TO_USE must supply the GIT commit hash from the previous build, and VERRAZZANO_OPERATOR_IMAGE must NOT BE SPECIFIED or be NONE 30 // This allows one to rerun the tests without rerunning the upstream build (ie: if intermittent test issue occurred) 31 // 4) (manual) any branch should be able to call this “trigger” job with the current head of their branch, pointing to a previously built operator image. This is useful if you are adding/fixing test cases where the 32 // operator image was built already (from master, or your branch) and only want to run the tests using it without running the full build. This is not a super likely situation (more likely individual test jobs 33 // will be manually kicked off rather than all of them). To accomplish this, specify GIT_COMMIT_TO_USE=NONE, and VERRAZZANO_OPERATOR_IMAGE=image-to-use 34 parameters { 35 string (name: 'GIT_COMMIT_TO_USE', 36 defaultValue: 'NONE', 37 description: 'This is the full git commit hash from the source build to be used for all jobs. A full pipeline specifies a valid commit hash here. NONE can be used for manually triggered jobs, however even for those a commit hash value is preferred to be supplied', 38 trim: true) 39 choice (description: 'Predefined config permutations for Verrazzano installation used by upgrade path pipeline. Prod profile is the default profile for NONE', name: 'VZ_INSTALL_CONFIG', 40 choices: ["NONE", "dev-kind-persistence"]) 41 string (name: 'VERRAZZANO_OPERATOR_IMAGE', 42 defaultValue: 'NONE', 43 description: 'This is for manually testing only where someone needs to use a specific operator image, otherwise the default value of NONE is used', 44 trim: true) 45 string (name: 'WILDCARD_DNS_DOMAIN', 46 defaultValue: 'nip.io', 47 description: 'This is the wildcard DNS domain', 48 trim: true) 49 string (name: 'TAGGED_TESTS', 50 defaultValue: '', 51 description: 'A comma separated list of build tags for tests that should be executed (e.g. unstable_test). Default:', 52 trim: true) 53 string (name: 'INCLUDED_TESTS', 54 defaultValue: '.*', 55 description: 'A regex matching any fully qualified test file that should be executed (e.g. examples/helidon/). Default: .*', 56 trim: true) 57 string (name: 'EXCLUDED_TESTS', 58 defaultValue: '_excluded_test', 59 description: 'A regex matching any fully qualified test file that should not be executed (e.g. multicluster/|_excluded_test). Default: _excluded_test', 60 trim: true) 61 string (name: 'CONSOLE_REPO_BRANCH', 62 defaultValue: '', 63 description: 'The branch to check out after cloning the console repository.', 64 trim: true) 65 booleanParam (description: 'This will FORCE a stable commit update without running any tests. This is normally ONLY used for debugging, it can be used to force a manual value into object storage', name: 'FORCE_STABLE_COMMIT_UPDATE', defaultValue: false) 66 } 67 68 environment { 69 CLEAN_BRANCH_NAME = "${env.BRANCH_NAME.replace("/", "%2F")}" 70 GOPATH = '/home/opc/go' 71 GO_REPO_PATH = "${GOPATH}/src/github.com/verrazzano" 72 OCI_CLI_AUTH="instance_principal" 73 OCI_OS_NAMESPACE = credentials('oci-os-namespace') 74 PROMETHEUS_GW_URL = credentials('prometheus-dev-url') 75 SERVICE_KEY = credentials('PAGERDUTY_SERVICE_KEY') 76 } 77 78 stages { 79 stage('Clean workspace and checkout') { 80 steps { 81 sh """ 82 echo "${NODE_LABELS}" 83 """ 84 85 // REVIEW: I'm not sure that we actually need to fetch the sources here, but I'm doing here as it was easier 86 // to test working with the SCM checkout settings starting from this job. We should be able to trigger this job 87 // with parameters directly (ie: based on a previous build), in that situation doing this gives us a single point 88 // to ensure the commit matches what was intended before triggering a bunch of downstream jobs that will 89 // all fail if it wasn't correct. So we may want to keep it here unless there is a compelling reason not to do so. 90 // I haven't looked at the executor resource usage yet in all of this, so it may be that could have constraints for 91 // using flyweight executors (still need to look at that) 92 script { 93 if (params.GIT_COMMIT_TO_USE == "NONE") { 94 echo "Specific GIT commit was not specified, use current head" 95 def scmInfo = checkout([ 96 $class: 'GitSCM', 97 branches: [[name: env.BRANCH_NAME]], 98 doGenerateSubmoduleConfigurations: false, 99 extensions: [], 100 submoduleCfg: [], 101 userRemoteConfigs: [[url: env.SCM_VERRAZZANO_GIT_URL]]]) 102 env.GIT_COMMIT = scmInfo.GIT_COMMIT 103 env.GIT_BRANCH = scmInfo.GIT_BRANCH 104 } else { 105 echo "SCM checkout of ${params.GIT_COMMIT_TO_USE}" 106 def scmInfo = checkout([ 107 $class: 'GitSCM', 108 branches: [[name: params.GIT_COMMIT_TO_USE]], 109 doGenerateSubmoduleConfigurations: false, 110 extensions: [], 111 submoduleCfg: [], 112 userRemoteConfigs: [[url: env.SCM_VERRAZZANO_GIT_URL]]]) 113 env.GIT_COMMIT = scmInfo.GIT_COMMIT 114 env.GIT_BRANCH = scmInfo.GIT_BRANCH 115 // If the commit we were handed is not what the SCM says we are using, fail 116 if (!env.GIT_COMMIT.equals(params.GIT_COMMIT_TO_USE)) { 117 echo "SCM didn't checkout the commit we expected. Expected: ${params.GIT_COMMIT_TO_USE}, Found: ${scmInfo.GIT_COMMIT}" 118 exit 1 119 } 120 } 121 echo "SCM checkout of ${env.GIT_BRANCH} at ${env.GIT_COMMIT}" 122 } 123 124 script { 125 echo "Generate git tags and save it to tags.txt file in the workspace" 126 sh """ 127 cd ${workspace} 128 git tag | awk '/v1[.]/' > tags.txt 129 """ 130 def props = readProperties file: '.verrazzano-development-version' 131 VERRAZZANO_DEV_VERSION = props['verrazzano-development-version'] 132 LATEST_RELEASE_VERSION = sh(returnStdout: true, script: "go run ${WORKSPACE}/ci/tools/derive_upgrade_version.go ${workspace} latest-version-for-branch ${VERRAZZANO_DEV_VERSION}").trim() 133 TIMESTAMP = sh(returnStdout: true, script: "date +%Y%m%d%H%M%S").trim() 134 SHORT_COMMIT_HASH = sh(returnStdout: true, script: "git rev-parse --short=8 HEAD").trim() 135 // update the description with some meaningful info 136 currentBuild.description = SHORT_COMMIT_HASH + " : " + env.GIT_COMMIT + " : " + params.GIT_COMMIT_TO_USE 137 def currentCommitHash = env.GIT_COMMIT 138 def commitList = getCommitList() 139 withCredentials([file(credentialsId: 'jenkins-to-slack-users', variable: 'JENKINS_TO_SLACK_JSON')]) { 140 def userMappings = readJSON file: JENKINS_TO_SLACK_JSON 141 SUSPECT_LIST = getSuspectList(commitList, userMappings) 142 echo "Suspect list: ${SUSPECT_LIST}" 143 } 144 } 145 } 146 } 147 148 stage ('Kick off parallel tests') { 149 when { 150 allOf { 151 not { buildingTag() } 152 expression {params.FORCE_STABLE_COMMIT_UPDATE == false} 153 } 154 } 155 parallel { 156 stage('Multi Cluster Tests') { 157 steps { 158 retry(count: JOB_PROMOTION_RETRIES) { 159 script { 160 build job: "/verrazzano-multi-cluster-acceptance-tests/${CLEAN_BRANCH_NAME}", 161 parameters: [ 162 string(name: 'GIT_COMMIT_TO_USE', value: env.GIT_COMMIT), 163 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 164 string(name: 'WILDCARD_DNS_DOMAIN', value: params.WILDCARD_DNS_DOMAIN), 165 string(name: 'TAGGED_TESTS', value: params.TAGGED_TESTS), 166 string(name: 'INCLUDED_TESTS', value: params.INCLUDED_TESTS), 167 string(name: 'EXCLUDED_TESTS', value: params.EXCLUDED_TESTS), 168 string(name: 'CONSOLE_REPO_BRANCH', value: params.CONSOLE_REPO_BRANCH) 169 ], wait: true 170 } 171 } 172 } 173 } 174 stage('Upgrade Path Tests with External ES') { 175 steps { 176 retry(count: JOB_PROMOTION_RETRIES) { 177 script { 178 def latestRelease = LATEST_RELEASE_VERSION 179 build job: "/verrazzano-upgrade-path-tests/${CLEAN_BRANCH_NAME}", 180 parameters: [ 181 string(name: 'GIT_COMMIT_TO_USE', value: env.GIT_COMMIT), 182 booleanParam(name: 'EXTERNAL_ELASTICSEARCH', value: true), 183 string(name: 'VERSION_FOR_INSTALL', value: latestRelease), 184 string(name: 'VZ_INSTALL_CONFIG', value: params.VZ_INSTALL_CONFIG), 185 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 186 string(name: 'WILDCARD_DNS_DOMAIN', value: params.WILDCARD_DNS_DOMAIN), 187 string(name: 'TAGGED_TESTS', value: params.TAGGED_TESTS), 188 string(name: 'INCLUDED_TESTS', value: params.INCLUDED_TESTS), 189 string(name: 'EXCLUDED_TESTS', value: params.EXCLUDED_TESTS), 190 string(name: 'CONSOLE_REPO_BRANCH', value: params.CONSOLE_REPO_BRANCH), 191 ], wait: true 192 } 193 } 194 } 195 } 196 stage('Uninstall Tests') { 197 steps { 198 retry(count: JOB_PROMOTION_RETRIES) { 199 script { 200 build job: "/verrazzano-uninstall-test/${CLEAN_BRANCH_NAME}", 201 parameters: [ 202 string(name: 'GIT_COMMIT_TO_USE', value: env.GIT_COMMIT), 203 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 204 string(name: 'WILDCARD_DNS_DOMAIN', value: params.WILDCARD_DNS_DOMAIN), 205 string(name: 'TAGGED_TESTS', value: params.TAGGED_TESTS), 206 string(name: 'INCLUDED_TESTS', value: params.INCLUDED_TESTS), 207 string(name: 'EXCLUDED_TESTS', value: params.EXCLUDED_TESTS), 208 string(name: 'CONSOLE_REPO_BRANCH', value: params.CONSOLE_REPO_BRANCH) 209 ], wait: true 210 } 211 } 212 } 213 } 214 stage('OCI DNS tests') { 215 steps { 216 retry(count: JOB_PROMOTION_RETRIES) { 217 script { 218 build job: "/verrazzano-new-oci-dns-acceptance-tests/${CLEAN_BRANCH_NAME}", 219 parameters: [ 220 string(name: 'GIT_COMMIT_TO_USE', value: env.GIT_COMMIT), 221 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 222 booleanParam(name: 'CREATE_CLUSTER_USE_CALICO', value: true), 223 string(name: 'TAGGED_TESTS', value: params.TAGGED_TESTS), 224 string(name: 'INCLUDED_TESTS', value: params.INCLUDED_TESTS), 225 string(name: 'EXCLUDED_TESTS', value: params.EXCLUDED_TESTS), 226 ], wait: true 227 } 228 } 229 } 230 } 231 stage('Kind No Istio Injection Tests') { 232 steps { 233 retry(count: JOB_PROMOTION_RETRIES) { 234 script { 235 build job: "/verrazzano-no-injection-tests/${CLEAN_BRANCH_NAME}", 236 parameters: [ 237 string(name: 'KUBERNETES_CLUSTER_VERSION', value: '1.27'), 238 string(name: 'GIT_COMMIT_TO_USE', value: env.GIT_COMMIT), 239 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 240 string(name: 'WILDCARD_DNS_DOMAIN', value: params.WILDCARD_DNS_DOMAIN), 241 string(name: 'TAGGED_TESTS', value: params.TAGGED_TESTS), 242 string(name: 'INCLUDED_TESTS', value: params.INCLUDED_TESTS), 243 string(name: 'EXCLUDED_TESTS', value: params.EXCLUDED_TESTS), 244 booleanParam(name: 'RUN_COHERENCE_TESTS', value: true), 245 string(name: 'CONSOLE_REPO_BRANCH', value: params.CONSOLE_REPO_BRANCH) 246 ], wait: true 247 } 248 } 249 } 250 } 251 stage('Upgrade Path Tests') { 252 steps { 253 retry(count: JOB_PROMOTION_RETRIES) { 254 script { 255 def latestRelease = LATEST_RELEASE_VERSION 256 echo "Printing latest release version: ${latestRelease}" 257 build job: "/verrazzano-upgrade-path-tests/${CLEAN_BRANCH_NAME}", 258 parameters: [ 259 string(name: 'GIT_COMMIT_TO_USE', value: env.GIT_COMMIT), 260 string(name: 'VERSION_FOR_INSTALL', value: latestRelease), 261 string(name: 'VZ_INSTALL_CONFIG', value: params.VZ_INSTALL_CONFIG), 262 string(name: 'VERRAZZANO_OPERATOR_IMAGE', value: params.VERRAZZANO_OPERATOR_IMAGE), 263 string(name: 'WILDCARD_DNS_DOMAIN', value: params.WILDCARD_DNS_DOMAIN), 264 string(name: 'TAGGED_TESTS', value: params.TAGGED_TESTS), 265 string(name: 'INCLUDED_TESTS', value: params.INCLUDED_TESTS), 266 string(name: 'EXCLUDED_TESTS', value: params.EXCLUDED_TESTS), 267 string(name: 'CONSOLE_REPO_BRANCH', value: params.CONSOLE_REPO_BRANCH), 268 ], wait: true 269 } 270 } 271 } 272 } 273 } 274 } 275 } 276 post { 277 success { 278 // WARNING: Only do this object storage update here, do not copy to other jobs 279 storePipelineArtifacts() 280 } 281 failure { 282 script { 283 failedOrAborted() 284 } 285 } 286 aborted { 287 script { 288 failedOrAborted() 289 } 290 } 291 } 292 } 293 294 def failedOrAborted() { 295 if (env.JOB_NAME == "verrazzano-push-triggered-acceptance-tests/master" || env.JOB_NAME ==~ "verrazzano-push-triggered-acceptance-tests/release-1.*") { 296 if (isPagerDutyEnabled()) { 297 pagerduty(resolve: false, serviceKey: "$SERVICE_KEY", incDescription: "Verrazzano: ${env.JOB_NAME} - Failed", incDetails: "Job Failed - \"${env.JOB_NAME}\" build: ${env.BUILD_NUMBER}\n\nView the log at:\n ${env.BUILD_URL}\n\nBlue Ocean:\n${env.RUN_DISPLAY_URL}") 298 } 299 slackSend ( channel: "$SLACK_ALERT_CHANNEL", message: "Job Failed - \"${env.JOB_NAME}\" build: ${env.BUILD_NUMBER}\n\nView the log at:\n ${env.BUILD_URL}\n\nBlue Ocean:\n${env.RUN_DISPLAY_URL}\n\nSuspects:\n${SUSPECT_LIST}" ) 300 } 301 } 302 303 def isPagerDutyEnabled() { 304 // this controls whether PD alerts are enabled 305 if (NOTIFY_PAGERDUTY_TRIGGERED_FAILURES.equals("true")) { 306 echo "Pager-Duty notifications enabled via global override setting" 307 return true 308 } 309 return false 310 } 311 312 // Called in final post success block of pipeline 313 // WARNING: Only do this object storage update here, do not copy to other jobs 314 def storePipelineArtifacts() { 315 script { 316 // If this was clean, record the commit in object store so the periodic test jobs can run against that rather than the head of the branch 317 // NOTE: Normally master and release-* branches are the only ones doing this, but when we need to test out pipeline changes we can make use 318 // as well 319 LAST_STABLE_COMMIT=getLastStableCommit() 320 IS_ANCESTOR=isAncestor() 321 if (LAST_STABLE_COMMIT == null || IS_ANCESTOR) { 322 sh """ 323 echo "git-commit=${env.GIT_COMMIT}" > $WORKSPACE/last-stable-commit.txt 324 if [ "true" == "${params.FORCE_STABLE_COMMIT_UPDATE}" ]; then 325 echo "forced-by-job=${env.BUILD_URL}" >> $WORKSPACE/last-stable-commit.txt 326 fi 327 cat $WORKSPACE/last-stable-commit.txt 328 """ 329 putLastStableCommit() 330 } 331 } 332 } 333 334 // Sets Job Display Name based on last-stable-commit.txt put status 335 def putLastStableCommit() { 336 putLastStableCommitCommandOutput = sh ( 337 label: "Put last stable commit text file", 338 script: "oci --region us-phoenix-1 os object put --force --namespace ${OCI_OS_NAMESPACE} -bn ${OCI_OS_BUCKET} --name ${CLEAN_BRANCH_NAME}/last-stable-commit.txt --file $WORKSPACE/last-stable-commit.txt 2>&1 || true", 339 returnStdout: true 340 ).trim() 341 echo "command out: ${putLastStableCommitCommandOutput}" 342 if (putLastStableCommitCommandOutput.length() > 0) { 343 if (putLastStableCommitCommandOutput =~ /(.*)status(.*)\d{1,4}(.*)/) { 344 currentBuild.displayName = "${currentBuild.displayName} : Put Last Stable Commit Failed" 345 slackSend ( channel: "$SLACK_ALERT_CHANNEL", message: "Job Failed - \"${env.JOB_NAME}\" build: ${env.BUILD_NUMBER}\n\nView the log at:\n ${env.BUILD_URL}\n\nBlue Ocean:\n${env.RUN_DISPLAY_URL}\n\nFailed to put last-stable-commit.txt in Object Store\n" ) 346 } 347 } 348 } 349 350 // Returns true if current commit is ancestor of last stable commit 351 def isAncestor() { 352 LAST_STABLE_COMMIT=getLastStableCommit() 353 ANCESTOR='' 354 if (LAST_STABLE_COMMIT != null) { 355 ANCESTOR = sh ( 356 label: "Check for Ancestry", 357 script: "git rev-list ${env.GIT_COMMIT} | grep \$(git rev-parse $LAST_STABLE_COMMIT) 2>&1 || true", 358 returnStdout: true 359 ).trim() 360 } 361 if (ANCESTOR.length() > 0) { 362 return true 363 } else { 364 return false 365 } 366 } 367 368 // Returns the last stable commit for the branch, or null if the commit file does not exist yet. 369 // - fails the pipeline if any error other than 404 is returned by the OCI CLI 370 def getLastStableCommit() { 371 lastStableCommitCommandOutput = sh ( 372 label: "Get last stable commit text file", 373 script: "oci --region us-phoenix-1 os object get --namespace ${OCI_OS_NAMESPACE} -bn ${OCI_OS_BUCKET} --name ${CLEAN_BRANCH_NAME}/last-stable-commit.txt --file ${WORKSPACE}/stored-stable-commit.txt 2>&1 || true", 374 returnStdout: true 375 ).trim() 376 echo "command out: ${lastStableCommitCommandOutput}" 377 if (lastStableCommitCommandOutput.length() > 0) { 378 // We can get warning messages here as well even when the command succeeded, so be more precise on the checking 379 if (lastStableCommitCommandOutput =~ /(.*)status(.*)\d{1,4}(.*)/) { 380 // If we think we had a status: NNN, we ignore 404 and fail for others 381 assert lastStableCommitCommandOutput =~ /(.*)status(.*)404(.*)/ : "An unexpected error occurred getting last stable commit from ObjectStore: ${lastStableCommitCommandOutput}" 382 } else { 383 // If we got here, we have some message that may or may not be an error. If we don't see the file, we assume it was an error 384 sh """ 385 if [ ! -f $WORKSPACE/stored-stable-commit.txt ]; then 386 echo "An unexpected error occurred getting last stable commit from ObjectStore: ${lastStableCommitCommandOutput}" 387 exit 1 388 fi 389 """ 390 } 391 } 392 // Get the commit ID for the last stable commit 393 def lastStableCommitProps = readProperties file: "$WORKSPACE/stored-stable-commit.txt" 394 return lastStableCommitProps['git-commit'] 395 } 396 397 // Called in Stage Clean workspace and checkout steps 398 @NonCPS 399 def getCommitList() { 400 echo "Checking for change sets" 401 def commitList = [] 402 def changeSets = currentBuild.changeSets 403 for (int i = 0; i < changeSets.size(); i++) { 404 echo "get commits from change set" 405 def commits = changeSets[i].items 406 for (int j = 0; j < commits.length; j++) { 407 def commit = commits[j] 408 def id = commit.commitId 409 echo "Add commit id: ${id}" 410 commitList.add(id) 411 } 412 } 413 return commitList 414 } 415 416 def trimIfGithubNoreplyUser(userIn) { 417 if (userIn == null) { 418 echo "Not a github noreply user, not trimming: ${userIn}" 419 return userIn 420 } 421 if (userIn.matches(".*\\+.*@users.noreply.github.com.*")) { 422 def userOut = userIn.substring(userIn.indexOf("+") + 1, userIn.indexOf("@")) 423 return userOut; 424 } 425 if (userIn.matches(".*<.*@users.noreply.github.com.*")) { 426 def userOut = userIn.substring(userIn.indexOf("<") + 1, userIn.indexOf("@")) 427 return userOut; 428 } 429 if (userIn.matches(".*@users.noreply.github.com")) { 430 def userOut = userIn.substring(0, userIn.indexOf("@")) 431 return userOut; 432 } 433 echo "Not a github noreply user, not trimming: ${userIn}" 434 return userIn 435 } 436 437 def getSuspectList(commitList, userMappings) { 438 def retValue = "" 439 def suspectList = [] 440 if (commitList == null || commitList.size() == 0) { 441 echo "No commits to form suspect list" 442 } else { 443 for (int i = 0; i < commitList.size(); i++) { 444 def id = commitList[i] 445 try { 446 def gitAuthor = sh( 447 script: "git log --format='%ae' '$id^!'", 448 returnStdout: true 449 ).trim() 450 if (gitAuthor != null) { 451 def author = trimIfGithubNoreplyUser(gitAuthor) 452 echo "DEBUG: author: ${gitAuthor}, ${author}, id: ${id}" 453 if (userMappings.containsKey(author)) { 454 def slackUser = userMappings.get(author) 455 if (!suspectList.contains(slackUser)) { 456 echo "Added ${slackUser} as suspect" 457 retValue += " ${slackUser}" 458 suspectList.add(slackUser) 459 } 460 } else { 461 // If we don't have a name mapping use the commit.author, at least we can easily tell if the mapping gets dated 462 if (!suspectList.contains(author)) { 463 echo "Added ${author} as suspect" 464 retValue += " ${author}" 465 suspectList.add(author) 466 } 467 } 468 } else { 469 echo "No author returned from git" 470 } 471 } catch (Exception e) { 472 echo "INFO: Problem processing commit ${id}, skipping commit: " + e.toString() 473 } 474 } 475 } 476 def startedByUser = ""; 477 def causes = currentBuild.getBuildCauses() 478 echo "causes: " + causes.toString() 479 for (cause in causes) { 480 def causeString = cause.toString() 481 echo "current cause: " + causeString 482 def causeInfo = readJSON text: causeString 483 if (causeInfo.userId != null) { 484 startedByUser = causeInfo.userId 485 } 486 } 487 488 if (startedByUser.length() > 0) { 489 echo "Build was started by a user, adding them to the suspect notification list: ${startedByUser}" 490 def author = trimIfGithubNoreplyUser(startedByUser) 491 echo "DEBUG: author: ${startedByUser}, ${author}" 492 if (userMappings.containsKey(author)) { 493 def slackUser = userMappings.get(author) 494 if (!suspectList.contains(slackUser)) { 495 echo "Added ${slackUser} as suspect" 496 retValue += " ${slackUser}" 497 suspectList.add(slackUser) 498 } 499 } else { 500 // If we don't have a name mapping use the commit.author, at least we can easily tell if the mapping gets dated 501 if (!suspectList.contains(author)) { 502 echo "Added ${author} as suspect" 503 retValue += " ${author}" 504 suspectList.add(author) 505 } 506 } 507 } else { 508 echo "Build not started by a user, not adding to notification list" 509 } 510 echo "returning suspect list: ${retValue}" 511 return retValue 512 }