|
| 1 | +/* |
| 2 | + * Copyright OpenSearch Contributors |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + * |
| 5 | + * The OpenSearch Contributors require contributions made to |
| 6 | + * this file be licensed under the Apache-2.0 license or a |
| 7 | + * compatible open source license. |
| 8 | + */ |
| 9 | + |
| 10 | +// @job-name: gradle-check |
| 11 | +// @description: Runs Gradle check on OpenSearch core repository for a given branch or commit. |
| 12 | + |
| 13 | +def secret_dockerhub_readonly = [ |
| 14 | + [envVar: 'DOCKER_USERNAME', secretRef: 'op://opensearch-infra-secrets/dockerhub-production-readonly-credentials/username'], |
| 15 | + [envVar: 'DOCKER_PASSWORD', secretRef: 'op://opensearch-infra-secrets/dockerhub-production-readonly-credentials/password'] |
| 16 | +] |
| 17 | + |
| 18 | +lib = library(identifier: 'jenkins@11.6.0', retriever: modernSCM([ |
| 19 | + $class: 'GitSCMSource', |
| 20 | + remote: 'https://github.com/opensearch-project/opensearch-build-libraries.git', |
| 21 | +])) |
| 22 | + |
| 23 | +pipeline { |
| 24 | + agent { label AGENT_LABEL } |
| 25 | + options { |
| 26 | + timeout(time: 2, unit: 'HOURS') |
| 27 | + buildDiscarder(logRotator(daysToKeepStr: '90')) |
| 28 | + throttleJobProperty( |
| 29 | + categories: [], |
| 30 | + limitOneJobWithMatchingParams: false, |
| 31 | + maxConcurrentPerNode: 0, |
| 32 | + maxConcurrentTotal: 45, |
| 33 | + paramsToUseForLimit: '', |
| 34 | + throttleEnabled: true, |
| 35 | + throttleOption: 'project', |
| 36 | + ) |
| 37 | + } |
| 38 | + parameters { |
| 39 | + string( |
| 40 | + name: 'GIT_REPO_URL', |
| 41 | + description: 'OpenSearch core repository url on git, can be either the official upstream url or your fork url.', |
| 42 | + defaultValue: 'https://github.com/opensearch-project/OpenSearch.git', |
| 43 | + trim: true |
| 44 | + ) |
| 45 | + string( |
| 46 | + name: 'GIT_REFERENCE', |
| 47 | + description: 'Git branch, tag, commitid for reference to checkout commit of OpenSearch core before running the gradle check.', |
| 48 | + defaultValue: 'main', |
| 49 | + trim: true |
| 50 | + ) |
| 51 | + string( |
| 52 | + name: 'GRADLE_CHECK_COMMAND', |
| 53 | + description: '<Optional> Custom command to pass to runGradleCheck.', |
| 54 | + defaultValue: 'check -Dtests.coverage=true', |
| 55 | + trim: true |
| 56 | + ) |
| 57 | + // Must use agent with 1 executor or gradle check will show a lot of java-related errors |
| 58 | + // The c524xlarge is the instance type that has the least amount of errors during gradle check |
| 59 | + // https://github.com/opensearch-project/OpenSearch/issues/1975 |
| 60 | + // |
| 61 | + // Update 20230724: Recent investigation shows gradle check is memory-bound thus switch to a new |
| 62 | + // runner of M58xlarge for more stable runs |
| 63 | + // https://github.com/opensearch-project/opensearch-ci/issues/321 |
| 64 | + choice( |
| 65 | + name: 'AGENT_LABEL', |
| 66 | + description: '<Optional> Choose which jenkins agent to run gradle check on. Defaults to Jenkins-Agent-Ubuntu2404-X64-M58xlarge-Single-Host.', |
| 67 | + choices: ['Jenkins-Agent-Ubuntu2404-X64-M7a8xlarge-Single-Host', 'Jenkins-Agent-Windows2019-X64-C524xlarge-Single-Host'], |
| 68 | + ) |
| 69 | + } |
| 70 | + triggers { |
| 71 | + GenericTrigger( |
| 72 | + genericVariables: [ |
| 73 | + [key: 'pr_from_sha', value: '$.pr_from_sha'], |
| 74 | + [key: 'pr_from_clone_url', value: '$.pr_from_clone_url'], |
| 75 | + [key: 'pr_to_clone_url', value: '$.pr_to_clone_url'], |
| 76 | + [key: 'pr_title', value: '$.pr_title'], |
| 77 | + [key: 'pr_number', value: '$.pr_number'], |
| 78 | + [key: 'post_merge_action', value: '$.post_merge_action'], |
| 79 | + [key: 'pr_owner', value: '$.pr_owner'], |
| 80 | + [key: 'gradle_check_command', value: '$.gradle_check_command'] |
| 81 | + ], |
| 82 | + tokenCredentialId: 'jenkins-gradle-check-generic-webhook-token', |
| 83 | + causeString: 'Triggered by PR on OpenSearch core repository', |
| 84 | + printContributedVariables: false, |
| 85 | + printPostContent: false |
| 86 | + ) |
| 87 | + parameterizedCron ''' |
| 88 | + H */2 * * * %GIT_REFERENCE=main;AGENT_LABEL=Jenkins-Agent-Ubuntu2404-X64-M58xlarge-Single-Host |
| 89 | + H 6 * * * %GIT_REFERENCE=2.19;AGENT_LABEL=Jenkins-Agent-Ubuntu2404-X64-M58xlarge-Single-Host |
| 90 | + ''' |
| 91 | + } |
| 92 | + environment { |
| 93 | + BUILD_CAUSE = currentBuild.getBuildCauses() |
| 94 | + } |
| 95 | + stages { |
| 96 | + stage('Run Gradle Check') { |
| 97 | + steps { |
| 98 | + script { |
| 99 | + |
| 100 | + // Use webhook value if provided, otherwise fall back to pipeline parameter default |
| 101 | + if (binding.hasVariable('gradle_check_command') && gradle_check_command?.trim()) { |
| 102 | + env.GRADLE_CHECK_COMMAND = gradle_check_command |
| 103 | + } |
| 104 | + |
| 105 | + if (!(env.GRADLE_CHECK_COMMAND ==~ /^[a-zA-Z0-9\-._=: \/*#]+$/)) { |
| 106 | + error("Invalid GRADLE_CHECK_COMMAND '${env.GRADLE_CHECK_COMMAND}': contains disallowed characters") |
| 107 | + } |
| 108 | + |
| 109 | + sh """ |
| 110 | + set +x |
| 111 | + set -e |
| 112 | + JAVA_HOME_LIST=`env | grep JAVA | grep HOME` |
| 113 | + echo "JAVA_HOME_LIST \$JAVA_HOME_LIST" |
| 114 | + |
| 115 | + if [ -n "\$JAVA_HOME_LIST" ] && [ "\$JAVA_HOME_LIST" != "" ]; then |
| 116 | + for java_version in \$JAVA_HOME_LIST; do |
| 117 | + echo \$java_version |
| 118 | + java_path="`echo \$java_version | cut -d= -f2`/bin/java -version" |
| 119 | + eval \$java_path |
| 120 | + done |
| 121 | + else |
| 122 | + echo "Missing JAVA_HOME information in env vars, exit 1" |
| 123 | + exit 1 |
| 124 | + fi |
| 125 | + """ |
| 126 | + |
| 127 | + def agent_name_array = params.AGENT_LABEL.tokenize('-') |
| 128 | + def agent_name = agent_name_array[2] + " " + agent_name_array[4] |
| 129 | + |
| 130 | + echo("Build Cause: ${BUILD_CAUSE}") |
| 131 | + withSecrets(secrets: secret_dockerhub_readonly){ |
| 132 | + def bwc_checkout_align = "false" |
| 133 | + |
| 134 | + def dockerLogin = sh(returnStdout: true, script: "set +x && (echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin) || echo docker error").trim() |
| 135 | + |
| 136 | + if (!env.BUILD_CAUSE.contains('Started by user') && !env.BUILD_CAUSE.contains('Started by timer')) { |
| 137 | + def pr_url = "${pr_to_clone_url}".replace(".git", "/pull/${pr_number}") |
| 138 | + println("Triggered by GitHub: ${pr_to_clone_url}") |
| 139 | + if ("$post_merge_action" == "true") { |
| 140 | + currentBuild.description = """runner: ${agent_name}<br><a href="${pr_to_clone_url}">Others</a>: ${pr_title}""" |
| 141 | + } |
| 142 | + else { |
| 143 | + currentBuild.description = """runner: ${agent_name}<br><a href="${pr_url}">PR #${pr_number}</a>: ${pr_title} with bwc.checkout.align=true""" |
| 144 | + bwc_checkout_align = "true" |
| 145 | + } |
| 146 | + |
| 147 | + abortStaleJenkinsJobs(jobName: 'gradle-check', lookupTime: 3) |
| 148 | + |
| 149 | + runGradleCheck( |
| 150 | + gitRepoUrl: "${pr_from_clone_url}", |
| 151 | + gitReference: "${pr_from_sha}", |
| 152 | + bwcCheckoutAlign: "${bwc_checkout_align}", |
| 153 | + command: "${GRADLE_CHECK_COMMAND}" |
| 154 | + ) |
| 155 | + } |
| 156 | + else { |
| 157 | + println("Triggered by User or Triggered by Timer") |
| 158 | + def repo_url = "${GIT_REPO_URL}".replace(".git", "/commit") |
| 159 | + currentBuild.description = """runner: ${agent_name}<br>git: <a href="${GIT_REPO_URL}">${GIT_REPO_URL}</a><br>ref: <a href="${repo_url}/${GIT_REFERENCE}">${GIT_REFERENCE}</a>""" |
| 160 | + |
| 161 | + runGradleCheck( |
| 162 | + gitRepoUrl: "${GIT_REPO_URL}", |
| 163 | + gitReference: "${GIT_REFERENCE}", |
| 164 | + bwcCheckoutAlign: "${bwc_checkout_align}", |
| 165 | + command: "${GRADLE_CHECK_COMMAND}" |
| 166 | + ) |
| 167 | + } |
| 168 | + |
| 169 | + sh("docker logout || echo docker error") |
| 170 | + } |
| 171 | + } |
| 172 | + } |
| 173 | + post() { |
| 174 | + failure { |
| 175 | + archiveArtifacts artifacts: '**/build/heapdump/*.hprof', allowEmptyArchive: true |
| 176 | + } |
| 177 | + always { |
| 178 | + sh ("cp -v `find search/build/reports/jacoco/ -name '*.xml' | head -n 1` codeCoverage.xml || echo") |
| 179 | + junit allowEmptyResults: true, testResults: '**/build/test-results/**/*.xml' |
| 180 | + archiveArtifacts artifacts: 'codeCoverage.xml', onlyIfSuccessful: true |
| 181 | + script { |
| 182 | + def invokedBy |
| 183 | + def pullRequest |
| 184 | + def pullRequestTitle |
| 185 | + def gitReference |
| 186 | + def pullRequestOwner |
| 187 | + switch (true) { |
| 188 | + case env.BUILD_CAUSE.contains('Started by user'): |
| 189 | + invokedBy = 'User' |
| 190 | + pullRequest = "null" |
| 191 | + pullRequestTitle = "null" |
| 192 | + gitReference = "${GIT_REFERENCE}" |
| 193 | + pullRequestOwner = "null" |
| 194 | + break |
| 195 | + case env.BUILD_CAUSE.contains('Started by timer'): |
| 196 | + invokedBy = 'Timer' |
| 197 | + pullRequest = "null" |
| 198 | + pullRequestTitle = "null" |
| 199 | + gitReference = "${GIT_REFERENCE}" |
| 200 | + pullRequestOwner = "null" |
| 201 | + break |
| 202 | + case "${post_merge_action}" == "true": |
| 203 | + invokedBy = 'Post Merge Action' |
| 204 | + pullRequest = "${pr_number}" |
| 205 | + pullRequestTitle = "${pr_title}" |
| 206 | + gitReference = "${pr_from_sha}" |
| 207 | + pullRequestOwner = "${pr_owner}" |
| 208 | + break |
| 209 | + default: |
| 210 | + invokedBy = 'Pull Request' |
| 211 | + pullRequest = "${pr_number}" |
| 212 | + pullRequestTitle = "${pr_title}" |
| 213 | + gitReference = "${pr_from_sha}" |
| 214 | + pullRequestOwner = "${pr_owner}" |
| 215 | + } |
| 216 | + publishGradleCheckTestResults(prNumber: "${pullRequest}" , prTitle: "${pullRequestTitle}", prOwner: "${pullRequestOwner}", invokeType: "${invokedBy}", gitReference: "${gitReference}", command: "${GRADLE_CHECK_COMMAND}") |
| 217 | + sh("rm -rf *") |
| 218 | + postCleanup() |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + } |
| 223 | + } |
| 224 | + post() { |
| 225 | + always { |
| 226 | + script { |
| 227 | + postCleanup() |
| 228 | + sh "(docker logout && docker image prune -f --all) || echo docker error" |
| 229 | + } |
| 230 | + } |
| 231 | + } |
| 232 | +} |
0 commit comments