|
1 | 1 | def configurations = [ |
2 | | - [ platform: "docker", jdk: "11" ], |
3 | | - [ platform: "windows", jdk: "11" ] |
| 2 | + [ platform: "linux", jdk: "17" ], |
| 3 | + [ platform: "windows", jdk: "17" ] |
4 | 4 | ] |
5 | 5 |
|
6 | | -buildPlugin(failFast: false, configurations: configurations, timeout: 90, |
| 6 | +def params = [ |
| 7 | + failFast: false, |
| 8 | + configurations: configurations, |
7 | 9 | checkstyle: [qualityGates: [[threshold: 1, type: 'NEW', unstable: true]], |
8 | | - filters:[includePackage('io.jenkins.plugins.coverage.metrics')]], |
| 10 | + filters:[includePackage('io.jenkins.plugins.coverage.metrics')]], |
9 | 11 | pmd: [qualityGates: [[threshold: 1, type: 'NEW', unstable: true]], |
10 | | - filters:[includePackage('io.jenkins.plugins.coverage.metrics')]], |
| 12 | + filters:[includePackage('io.jenkins.plugins.coverage.metrics')]], |
11 | 13 | spotbugs: [qualityGates: [[threshold: 1, type: 'NEW', unstable: true]], |
12 | | - filters:[includePackage('io.jenkins.plugins.coverage.metrics')]]) |
| 14 | + filters:[includePackage('io.jenkins.plugins.coverage.metrics')]], |
| 15 | + jacoco: [sourceCodeRetention: 'MODIFIED', sourceDirectories: [[path: 'plugin/src/main/java']]] |
| 16 | +] |
| 17 | + |
| 18 | + properties([ |
| 19 | + disableConcurrentBuilds(abortPrevious: true), |
| 20 | + buildDiscarder(logRotator(numToKeepStr: '5')), |
| 21 | + ]) |
| 22 | + |
| 23 | + def repo = params.containsKey('repo') ? params.repo : null |
| 24 | + def failFast = params.containsKey('failFast') ? params.failFast : true |
| 25 | + def timeoutValue = params.containsKey('timeout') ? params.timeout : 60 |
| 26 | + def gitDefaultBranch = params.containsKey('gitDefaultBranch') ? params.gitDefaultBranch : null |
| 27 | + def useArtifactCachingProxy = params.containsKey('useArtifactCachingProxy') ? params.useArtifactCachingProxy : true |
| 28 | + |
| 29 | + def useContainerAgent = params.containsKey('useContainerAgent') ? params.useContainerAgent : false |
| 30 | + if (params.containsKey('useAci')) { |
| 31 | + infra.publishDeprecationCheck('Replace useAci with useContainerAgent', 'The parameter "useAci" is deprecated. Please use "useContainerAgent" instead as per https://issues.jenkins.io/browse/INFRA-2918.') |
| 32 | + useContainerAgent = params.containsKey('useAci') |
| 33 | + } |
| 34 | + if (timeoutValue > 180) { |
| 35 | + echo "Timeout value requested was $timeoutValue, lowering to 180 to avoid Jenkins project's resource abusive consumption" |
| 36 | + timeoutValue = 180 |
| 37 | + } |
| 38 | + |
| 39 | + boolean publishingIncrementals = false |
| 40 | + boolean archivedArtifacts = false |
| 41 | + Map tasks = [failFast: failFast] |
| 42 | + getConfigurations(params).each { config -> |
| 43 | + String label = '' |
| 44 | + String platform = config.platform |
| 45 | + String jdk = config.jdk |
| 46 | + String jenkinsVersion = config.jenkins |
| 47 | + if (config.containsKey('javaLevel')) { |
| 48 | + infra.publishDeprecationCheck('Remove javaLevel', 'Ignoring deprecated "javaLevel" parameter. This parameter should be removed from your "Jenkinsfile".') |
| 49 | + } |
| 50 | + |
| 51 | + String stageIdentifier = "${platform}-${jdk}${jenkinsVersion ? '-' + jenkinsVersion : ''}" |
| 52 | + boolean first = tasks.size() == 1 |
| 53 | + boolean skipTests = params?.tests?.skip |
| 54 | + boolean addToolEnv = !useContainerAgent |
| 55 | + |
| 56 | + if (useContainerAgent) { |
| 57 | + if (platform == 'linux' || platform == 'windows') { |
| 58 | + def agentContainerLabel = jdk == '8' ? 'maven' : 'maven-' + jdk |
| 59 | + if (platform == 'windows') { |
| 60 | + agentContainerLabel += '-windows' |
| 61 | + } |
| 62 | + label = agentContainerLabel |
| 63 | + } |
| 64 | + } else { |
| 65 | + switch(platform) { |
| 66 | + case 'windows': |
| 67 | + label = 'docker-windows' |
| 68 | + break |
| 69 | + case 'linux': |
| 70 | + label = 'vm && linux' |
| 71 | + break |
| 72 | + default: |
| 73 | + echo "WARNING: Unknown platform '${platform}'. Agent label set to fallback value 'linux'" |
| 74 | + label = 'linux' |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + tasks[stageIdentifier] = { |
| 79 | + retry(count: 3, conditions: [kubernetesAgent(handleNonKubernetes: true), nonresumable()]) { |
| 80 | + node(label) { |
| 81 | + try { |
| 82 | + timeout(timeoutValue) { |
| 83 | + boolean isMaven |
| 84 | + // Archive artifacts once with pom declared baseline |
| 85 | + boolean doArchiveArtifacts = !jenkinsVersion && !archivedArtifacts |
| 86 | + if (doArchiveArtifacts) { |
| 87 | + archivedArtifacts = true |
| 88 | + } |
| 89 | + |
| 90 | + boolean incrementals // cf. JEP-305 |
| 91 | + |
| 92 | + stage("Checkout (${stageIdentifier})") { |
| 93 | + infra.checkoutSCM(repo) |
| 94 | + isMaven = !fileExists('gradlew') |
| 95 | + incrementals = fileExists('.mvn/extensions.xml') && |
| 96 | + readFile('.mvn/extensions.xml').contains('git-changelist-maven-extension') |
| 97 | + final String gitUnavailableMessage = '[buildPlugin] Git CLI may not be available' |
| 98 | + withEnv(["GITUNAVAILABLEMESSAGE=${gitUnavailableMessage}"]) { |
| 99 | + if (incrementals) { // Incrementals needs 'git status -s' to be empty at start of job |
| 100 | + if (isUnix()) { |
| 101 | + sh 'git clean -xffd || echo "$GITUNAVAILABLEMESSAGE"' |
| 102 | + } else { |
| 103 | + bat 'git clean -xffd || echo %GITUNAVAILABLEMESSAGE%' |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + if (gitDefaultBranch) { |
| 108 | + withEnv(["GITDEFAULTBRANCH=${gitDefaultBranch}"]) { |
| 109 | + if (isUnix()) { |
| 110 | + sh 'git config --global init.defaultBranch "$GITDEFAULTBRANCH" || echo "$GITUNAVAILABLEMESSAGE"' |
| 111 | + } else { |
| 112 | + bat 'git config --global init.defaultBranch %GITDEFAULTBRANCH% || echo %GITUNAVAILABLEMESSAGE%' |
| 113 | + } |
| 114 | + } |
| 115 | + } |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + String changelistF |
| 120 | + String m2repo |
| 121 | + |
| 122 | + stage("Build (${stageIdentifier})") { |
| 123 | + String command |
| 124 | + if (isMaven) { |
| 125 | + m2repo = "${pwd tmp: true}/m2repo" |
| 126 | + List<String> mavenOptions = [ |
| 127 | + '--update-snapshots', |
| 128 | + "-Dmaven.repo.local=$m2repo", |
| 129 | + '-Dmaven.test.failure.ignore', |
| 130 | + '-Dspotbugs.failOnError=false', |
| 131 | + '-Dcheckstyle.failOnViolation=false', |
| 132 | + '-Dcheckstyle.failsOnError=false', |
| 133 | + ] |
| 134 | + // jacoco had file locking issues on Windows, so only running on linux |
| 135 | + if (isUnix()) { |
| 136 | + mavenOptions += '-Penable-jacoco' |
| 137 | + } |
| 138 | + if (incrementals) { // set changelist and activate produce-incrementals profile |
| 139 | + mavenOptions += '-Dset.changelist' |
| 140 | + if (doArchiveArtifacts) { // ask Maven for the value of -rc999.abc123def456 |
| 141 | + changelistF = "${pwd tmp: true}/changelist" |
| 142 | + mavenOptions += "help:evaluate -Dexpression=changelist -Doutput=$changelistF" |
| 143 | + } |
| 144 | + } |
| 145 | + if (jenkinsVersion) { |
| 146 | + mavenOptions += "-Djenkins.version=${jenkinsVersion} -Daccess-modifier-checker.failOnError=false" |
| 147 | + } |
| 148 | + if (skipTests) { |
| 149 | + mavenOptions += '-DskipTests' |
| 150 | + } |
| 151 | + mavenOptions += 'clean install' |
| 152 | + try { |
| 153 | + infra.runMaven(mavenOptions, jdk, null, null, addToolEnv, useArtifactCachingProxy) |
| 154 | + } finally { |
| 155 | + if (!skipTests) { |
| 156 | + junit('**/target/surefire-reports/**/*.xml,**/target/failsafe-reports/**/*.xml,**/target/invoker-reports/**/*.xml') |
| 157 | + if (first) { |
| 158 | + discoverReferenceBuild() |
| 159 | + // Default configuration for JaCoCo can be overwritten using a `jacoco` parameter (map). |
| 160 | + // Configuration see: https://www.jenkins.io/doc/pipeline/steps/code-coverage-api/#recordcoverage-record-code-coverage-results |
| 161 | + Map jacocoArguments = [tools: [[parser: 'JACOCO', pattern: '**/jacoco/jacoco.xml']]] |
| 162 | + if (params?.jacoco) { |
| 163 | + jacocoArguments.putAll(params.jacoco as Map) |
| 164 | + } |
| 165 | + recordCoverage jacocoArguments |
| 166 | + |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + } else { |
| 171 | + infra.publishDeprecationCheck('Replace buildPlugin with buildPluginWithGradle', 'Gradle mode for buildPlugin() is deprecated, please use buildPluginWithGradle()') |
| 172 | + List<String> gradleOptions = [ |
| 173 | + '--no-daemon', |
| 174 | + 'cleanTest', |
| 175 | + 'build', |
| 176 | + ] |
| 177 | + if (skipTests) { |
| 178 | + gradleOptions += '--exclude-task test' |
| 179 | + } |
| 180 | + command = "gradlew ${gradleOptions.join(' ')}" |
| 181 | + if (isUnix()) { |
| 182 | + command = './' + command |
| 183 | + } |
| 184 | + |
| 185 | + try { |
| 186 | + infra.runWithJava(command, jdk, null, addToolEnv) |
| 187 | + } finally { |
| 188 | + if (!skipTests) { |
| 189 | + junit('**/build/test-results/**/*.xml') |
| 190 | + } |
| 191 | + } |
| 192 | + } |
| 193 | + } |
| 194 | + |
| 195 | + stage("Archive (${stageIdentifier})") { |
| 196 | + if (failFast && currentBuild.result == 'UNSTABLE') { |
| 197 | + error 'There were test failures; halting early' |
| 198 | + } |
| 199 | + |
| 200 | + if (first) { |
| 201 | + if (skipTests) { // otherwise the reference build has been computed already |
| 202 | + discoverReferenceBuild() |
| 203 | + } |
| 204 | + echo "Recording static analysis results on '${stageIdentifier}'" |
| 205 | + |
| 206 | + recordIssues( |
| 207 | + enabledForFailure: true, |
| 208 | + tool: mavenConsole(), |
| 209 | + skipBlames: true, |
| 210 | + trendChartType: 'TOOLS_ONLY' |
| 211 | + ) |
| 212 | + recordIssues( |
| 213 | + enabledForFailure: true, |
| 214 | + tools: [java(), javaDoc()], |
| 215 | + filters: [excludeFile('.*Assert.java')], |
| 216 | + sourceCodeEncoding: 'UTF-8', |
| 217 | + skipBlames: true, |
| 218 | + trendChartType: 'TOOLS_ONLY' |
| 219 | + ) |
| 220 | + |
| 221 | + // Default configuration for SpotBugs can be overwritten using a `spotbugs`, `checkstyle', etc. parameter (map). |
| 222 | + // Configuration see: https://github.com/jenkinsci/warnings-ng-plugin/blob/master/doc/Documentation.md#configuration |
| 223 | + Map spotbugsArguments = [tool: spotBugs(pattern: '**/target/spotbugsXml.xml,**/target/findbugsXml.xml'), |
| 224 | + sourceCodeEncoding: 'UTF-8', |
| 225 | + skipBlames: true, |
| 226 | + trendChartType: 'TOOLS_ONLY', |
| 227 | + qualityGates: [[threshold: 1, type: 'NEW', unstable: true]]] |
| 228 | + if (params?.spotbugs) { |
| 229 | + spotbugsArguments.putAll(params.spotbugs as Map) |
| 230 | + } |
| 231 | + recordIssues spotbugsArguments |
| 232 | + |
| 233 | + Map checkstyleArguments = [tool: checkStyle(pattern: '**/target/checkstyle-result.xml'), |
| 234 | + sourceCodeEncoding: 'UTF-8', |
| 235 | + skipBlames: true, |
| 236 | + trendChartType: 'TOOLS_ONLY', |
| 237 | + qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]]] |
| 238 | + if (params?.checkstyle) { |
| 239 | + checkstyleArguments.putAll(params.checkstyle as Map) |
| 240 | + } |
| 241 | + recordIssues checkstyleArguments |
| 242 | + |
| 243 | + Map pmdArguments = [tool: pmdParser(pattern: '**/target/pmd.xml'), |
| 244 | + sourceCodeEncoding: 'UTF-8', |
| 245 | + skipBlames: true, |
| 246 | + trendChartType: 'NONE'] |
| 247 | + if (params?.pmd) { |
| 248 | + pmdArguments.putAll(params.pmd as Map) |
| 249 | + } |
| 250 | + recordIssues pmdArguments |
| 251 | + |
| 252 | + Map cpdArguments = [tool: cpd(pattern: '**/target/cpd.xml'), |
| 253 | + sourceCodeEncoding: 'UTF-8', |
| 254 | + skipBlames: true, |
| 255 | + trendChartType: 'NONE'] |
| 256 | + if (params?.cpd) { |
| 257 | + cpdArguments.putAll(params.cpd as Map) |
| 258 | + } |
| 259 | + recordIssues cpdArguments |
| 260 | + |
| 261 | + recordIssues( |
| 262 | + enabledForFailure: true, tool: taskScanner( |
| 263 | + includePattern:'**/*.java', |
| 264 | + excludePattern:'**/target/**', |
| 265 | + highTags:'FIXME', |
| 266 | + normalTags:'TODO'), |
| 267 | + sourceCodeEncoding: 'UTF-8', |
| 268 | + skipBlames: true, |
| 269 | + trendChartType: 'NONE' |
| 270 | + ) |
| 271 | + if (failFast && currentBuild.result == 'UNSTABLE') { |
| 272 | + error 'Static analysis quality gates not passed; halting early' |
| 273 | + } |
| 274 | + } else { |
| 275 | + echo "Skipping static analysis results for ${stageIdentifier}" |
| 276 | + } |
| 277 | + if (doArchiveArtifacts) { |
| 278 | + if (incrementals) { |
| 279 | + String changelist = readFile(changelistF) |
| 280 | + dir(m2repo) { |
| 281 | + fingerprint '**/*-rc*.*/*-rc*.*' // includes any incrementals consumed |
| 282 | + archiveArtifacts artifacts: "**/*$changelist/*$changelist*", |
| 283 | + excludes: '**/*.lastUpdated', |
| 284 | + allowEmptyArchive: true // in case we forgot to reincrementalify |
| 285 | + } |
| 286 | + publishingIncrementals = true |
| 287 | + } else { |
| 288 | + String artifacts |
| 289 | + if (isMaven) { |
| 290 | + artifacts = '**/target/*.hpi,**/target/*.jpi,**/target/*.jar' |
| 291 | + } else { |
| 292 | + artifacts = '**/build/libs/*.hpi,**/build/libs/*.jpi' |
| 293 | + } |
| 294 | + archiveArtifacts artifacts: artifacts, fingerprint: true |
| 295 | + } |
| 296 | + } |
| 297 | + } |
| 298 | + } |
| 299 | + } finally { |
| 300 | + if (hasDockerLabel()) { |
| 301 | + if (isUnix()) { |
| 302 | + sh 'docker system prune --force --all || echo "Failed to cleanup docker images"' |
| 303 | + } else { |
| 304 | + bat 'docker system prune --force --all || echo "Failed to cleanup docker images"' |
| 305 | + } |
| 306 | + } |
| 307 | + } |
| 308 | + } |
| 309 | + } |
| 310 | + } |
| 311 | + } |
| 312 | + |
| 313 | + parallel(tasks) |
| 314 | + if (publishingIncrementals) { |
| 315 | + infra.maybePublishIncrementals() |
| 316 | + } |
| 317 | + |
| 318 | +private void discoverReferenceBuild() { |
| 319 | + folders = env.JOB_NAME.split('/') |
| 320 | + if (folders.length > 1) { |
| 321 | + discoverGitReferenceBuild(scm: folders[1]) |
| 322 | + } |
| 323 | +} |
| 324 | + |
| 325 | +boolean hasDockerLabel() { |
| 326 | + env.NODE_LABELS?.contains('docker') |
| 327 | +} |
| 328 | + |
| 329 | +List<Map<String, String>> getConfigurations(Map params) { |
| 330 | + boolean explicit = params.containsKey('configurations') && params.configurations != null |
| 331 | + boolean implicit = params.containsKey('platforms') || params.containsKey('jdkVersions') || params.containsKey('jenkinsVersions') |
| 332 | + |
| 333 | + if (explicit && implicit) { |
| 334 | + error '"configurations" option can not be used with either "platforms", "jdkVersions" or "jenkinsVersions"' |
| 335 | + } |
| 336 | + |
| 337 | + def configs = params.configurations |
| 338 | + configs.each { c -> |
| 339 | + if (!c.platform) { |
| 340 | + error("Configuration field \"platform\" must be specified: $c") |
| 341 | + } |
| 342 | + if (!c.jdk) { |
| 343 | + error("Configuration field \"jdk\" must be specified: $c") |
| 344 | + } |
| 345 | + } |
| 346 | + |
| 347 | + if (explicit) { |
| 348 | + return params.configurations |
| 349 | + } |
| 350 | + |
| 351 | + def platforms = params.containsKey('platforms') ? params.platforms : ['linux', 'windows'] |
| 352 | + def jdkVersions = params.containsKey('jdkVersions') ? params.jdkVersions : ['8'] |
| 353 | + def jenkinsVersions = params.containsKey('jenkinsVersions') ? params.jenkinsVersions : [null] |
| 354 | + |
| 355 | + def ret = [] |
| 356 | + for (p in platforms) { |
| 357 | + for (jdk in jdkVersions) { |
| 358 | + for (jenkins in jenkinsVersions) { |
| 359 | + ret << [ |
| 360 | + 'platform': p, |
| 361 | + 'jdk': jdk, |
| 362 | + 'jenkins': jenkins, |
| 363 | + ] |
| 364 | + } |
| 365 | + } |
| 366 | + } |
| 367 | + return ret |
| 368 | +} |
| 369 | + |
| 370 | +/** |
| 371 | + * @deprecated no longer recommended |
| 372 | + */ |
| 373 | +static List<Map<String, String>> recommendedConfigurations() { |
| 374 | + null |
| 375 | +} |
0 commit comments