From 129f9c9a4d69871adebe706604e6c489e7a48bfa Mon Sep 17 00:00:00 2001 From: Joaquim Alvino de Mesquita Neto Date: Thu, 9 Jun 2022 23:17:16 +0200 Subject: [PATCH] check step opinionations are now on scripts on vars/ dir this is part of a effort to make this lib more generic and easier to extend --- build.gradle | 1 + .../jenkins/pipeline/BuildVersion.groovy | 3 +- .../jenkins/pipeline/PipelineTools.groovy | 2 +- .../pipeline/check/CheckCreator.groovy | 61 ---------- .../jenkins/pipeline/check/Checks.groovy | 57 +++++---- .../jenkins/pipeline/check/Coveralls.groovy | 19 --- .../pipeline/check/EnclosureCreator.groovy | 2 +- .../jenkins/pipeline/check/Enclosures.groovy | 22 +++- .../jenkins/pipeline/check/JSChecks.groovy | 53 --------- .../jenkins/pipeline/check/JavaChecks.groovy | 52 --------- .../jenkins/pipeline/check/Sonarqube.groovy | 10 -- .../jenkins/pipeline/check/WDKChecks.groovy | 58 ---------- .../pipeline/check/steps/GradleSteps.groovy | 66 ----------- .../jenkins/pipeline/check/steps/Step.groovy | 2 + .../jenkins/pipeline/config/BaseConfig.groovy | 6 +- .../jenkins/pipeline/config/CheckArgs.groovy | 12 +- .../jenkins/pipeline/config/Config.groovy | 48 ++++++++ .../jenkins/pipeline/config/JSConfig.groovy | 49 ++------ .../jenkins/pipeline/config/JavaConfig.groovy | 83 ++------------ .../jenkins/pipeline/config/Platform.groovy | 77 ++++++------- .../config/UnityVersionPlatform.groovy | 49 -------- .../jenkins/pipeline/config/WDKConfig.groovy | 49 +++----- .../pipeline/publish/Publishers.groovy | 1 - .../pipeline/config/PlatformSpec.groovy | 108 +++++++++--------- .../scripts/BuildGradlePluginSpec.groovy | 2 +- .../scripts/BuildJavaLibraryOSSRHSpec.groovy | 2 +- .../scripts/BuildJavaLibrarySpec.groovy | 4 +- test/groovy/scripts/BuildWDKJSSpec.groovy | 56 +++++---- .../config => scripts}/JSConfigSpec.groovy | 23 +++- test/groovy/scripts/JavaCheckSpec.groovy | 73 +++++++----- .../config => scripts}/JavaConfigSpec.groovy | 22 +++- test/groovy/scripts/WDKCheckSpec.groovy | 68 ++++++----- .../config => scripts}/WDKConfigSpec.groovy | 40 ++++--- .../tools/DeclarativeJenkinsSpec.groovy | 62 +++++++--- .../sandbox/GroovyClassLoaderWhitelist.groovy | 59 ++++++++++ .../sandbox/SandboxPipelineTestHelper.groovy | 28 ++++- test/resources/scripts/checkTest.groovy | 37 +++--- vars/buildGradlePlugin.groovy | 4 +- vars/buildJavaLibrary.groovy | 4 +- vars/buildJavaLibraryOSSRH.groovy | 4 +- vars/buildPrivateGradlePlugin.groovy | 4 +- vars/buildPrivateJavaLibrary.groovy | 4 +- vars/buildWDKAutoSwitch.groovy | 32 +++--- vars/buildWDKJS.groovy | 12 +- vars/checkCreator.groovy | 13 +++ vars/configs.groovy | 70 ++++++++++++ vars/gradleWrapper.groovy | 3 + vars/javaCheckTemplate.groovy | 70 ++++++++++++ vars/javaLibs.groovy | 13 +-- vars/jsCheckTemplate.groovy | 14 +++ vars/parallelize.groovy | 14 +++ vars/staticAnalysis.groovy | 58 ++++++++++ vars/wdkCheckTemplate.groovy | 34 ++++++ 53 files changed, 872 insertions(+), 847 deletions(-) delete mode 100644 src/net/wooga/jenkins/pipeline/check/CheckCreator.groovy delete mode 100644 src/net/wooga/jenkins/pipeline/check/JSChecks.groovy delete mode 100644 src/net/wooga/jenkins/pipeline/check/JavaChecks.groovy delete mode 100644 src/net/wooga/jenkins/pipeline/check/WDKChecks.groovy delete mode 100644 src/net/wooga/jenkins/pipeline/check/steps/GradleSteps.groovy create mode 100644 src/net/wooga/jenkins/pipeline/config/Config.groovy delete mode 100644 src/net/wooga/jenkins/pipeline/config/UnityVersionPlatform.groovy rename test/groovy/{net/wooga/jenkins/pipeline/config => scripts}/JSConfigSpec.groovy (77%) rename test/groovy/{net/wooga/jenkins/pipeline/config => scripts}/JavaConfigSpec.groovy (78%) rename test/groovy/{net/wooga/jenkins/pipeline/config => scripts}/WDKConfigSpec.groovy (65%) create mode 100644 test/groovy/tools/sandbox/GroovyClassLoaderWhitelist.groovy create mode 100644 vars/checkCreator.groovy create mode 100644 vars/configs.groovy create mode 100644 vars/javaCheckTemplate.groovy create mode 100644 vars/jsCheckTemplate.groovy create mode 100644 vars/parallelize.groovy create mode 100644 vars/staticAnalysis.groovy create mode 100644 vars/wdkCheckTemplate.groovy diff --git a/build.gradle b/build.gradle index da64e76c..3f42b04b 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,7 @@ dependencies { } testImplementation "org.jenkins-ci.main:jenkins-test-harness:2.71" testImplementation 'com.github.ben-manes.caffeine:caffeine:2.9.2' + testImplementation 'org.powermock:powermock-classloading-xstream:2.0.9' } diff --git a/src/net/wooga/jenkins/pipeline/BuildVersion.groovy b/src/net/wooga/jenkins/pipeline/BuildVersion.groovy index deea9014..97f99b52 100644 --- a/src/net/wooga/jenkins/pipeline/BuildVersion.groovy +++ b/src/net/wooga/jenkins/pipeline/BuildVersion.groovy @@ -41,6 +41,7 @@ class BuildVersion { } final String version + @Deprecated final Boolean optional // net_4_6, net_standard_2_0 (DEFAULT) final String apiCompatibilityLevel @@ -58,7 +59,7 @@ class BuildVersion { } @NonCPS - String toLabel(){ + String toLabel() { def result = version if (optional){ result += " (optional)" diff --git a/src/net/wooga/jenkins/pipeline/PipelineTools.groovy b/src/net/wooga/jenkins/pipeline/PipelineTools.groovy index 3f1828eb..a7ded414 100644 --- a/src/net/wooga/jenkins/pipeline/PipelineTools.groovy +++ b/src/net/wooga/jenkins/pipeline/PipelineTools.groovy @@ -21,7 +21,7 @@ class PipelineTools { def gradle = Gradle.fromJenkins(jenkins, config.gradleArgs) def docker = Docker.fromJenkins(jenkins, config.dockerArgs) def setups = Setups.create(jenkins, gradle) - def checks = Checks.create(jenkins, docker, gradle, config.metadata.buildNumber) + def checks = Checks.create(jenkins, docker, config.metadata.buildNumber) def assemblers = Assemblers.fromJenkins(jenkins, gradle) def publishersFactory = { String releaseType, String releaseScope -> Publishers.fromJenkins(jenkins, gradle, releaseType, releaseScope) diff --git a/src/net/wooga/jenkins/pipeline/check/CheckCreator.groovy b/src/net/wooga/jenkins/pipeline/check/CheckCreator.groovy deleted file mode 100644 index f7836fe8..00000000 --- a/src/net/wooga/jenkins/pipeline/check/CheckCreator.groovy +++ /dev/null @@ -1,61 +0,0 @@ -package net.wooga.jenkins.pipeline.check - -import net.wooga.jenkins.pipeline.check.steps.Step -import net.wooga.jenkins.pipeline.config.Platform -import net.wooga.jenkins.pipeline.config.UnityVersionPlatform - -class CheckCreator { - final Object jenkins - final Enclosures enclosures - - public CheckCreator(Object jenkinsScript, Enclosures enclosures) { - this.jenkins = jenkinsScript - this.enclosures = enclosures - } - - Closure junitCheck(Platform platform, Step testStep, Step analysisStep) { - def mainClosure = createCheck(testStep, analysisStep).pack(platform) - def catchClosure = {throw it} - def finallyClosure = { - jenkins.junit allowEmptyResults: true, testResults: "**/build/test-results/**/*.xml" - } - - def checkStep = platform.runsOnDocker ? - enclosures.withDocker(platform, mainClosure, catchClosure, finallyClosure) : - enclosures.simple(platform, mainClosure, catchClosure, finallyClosure) - return checkStep - } - - Closure csWDKChecks(UnityVersionPlatform versionBuild, Step testStep, Step analysisStep) { - def mainClosure = createCheck(testStep, analysisStep).pack(versionBuild.platform) - def catchClosure = { Throwable e -> - if (versionBuild.optional) { - jenkins.unstable(message: "Unity build for optional version ${versionBuild.version} is found to be unstable\n${e.toString()}") - } else { - throw e - } - } - def finallyClosure = { - jenkins.nunit failIfNoResults: false, testResultsPattern: '**/build/reports/unity/test*/*.xml' - jenkins.archiveArtifacts artifacts: '**/build/logs/**/*.log', allowEmptyArchive: true - jenkins.archiveArtifacts artifacts: '**/build/reports/unity/**/*.xml', allowEmptyArchive: true - } - def checkStep = enclosures.simple(versionBuild.platform, mainClosure, catchClosure, finallyClosure) - return checkStep - } - - protected Step createCheck(Step testStep, Step analysisStep) { - return new Step({ Platform platform -> - jenkins.dir(platform.checkoutDirectory) { - jenkins.dir(platform.checkDirectory) { - testStep(platform) - if (platform.isMain()) { - analysisStep(platform) - } - } - } - }) - } -} - - diff --git a/src/net/wooga/jenkins/pipeline/check/Checks.groovy b/src/net/wooga/jenkins/pipeline/check/Checks.groovy index 6fc87d09..0d155e00 100644 --- a/src/net/wooga/jenkins/pipeline/check/Checks.groovy +++ b/src/net/wooga/jenkins/pipeline/check/Checks.groovy @@ -1,48 +1,45 @@ package net.wooga.jenkins.pipeline.check -import net.wooga.jenkins.pipeline.check.steps.GradleSteps +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.config.Platform import net.wooga.jenkins.pipeline.model.Docker -import net.wooga.jenkins.pipeline.model.Gradle class Checks { + final Object jenkins + final Enclosures enclosures - Docker docker - Gradle gradle - GradleSteps steps - EnclosureCreator enclosureCreator - Enclosures enclosures - CheckCreator checkCreator - - //jenkins CPS-transformations doesn't work inside constructors, so we have to keep these as simple as possible. - //for non-trivial constructors, prefer static factories. - static Checks create(Object jenkinsScript, Docker docker, Gradle gradle, int buildNumber) { + static Checks create(Object jenkinsScript, Docker docker, int buildNumber) { def enclosureCreator = new EnclosureCreator(jenkinsScript, buildNumber) def enclosures = new Enclosures(jenkinsScript, docker, enclosureCreator) - def checkCreator = new CheckCreator(jenkinsScript, enclosures) - def steps = new GradleSteps(jenkinsScript, gradle) - - return new Checks(docker, gradle, steps, enclosureCreator, enclosures, checkCreator) + return new Checks(jenkinsScript, enclosures) } - private Checks(Docker docker, Gradle gradle, GradleSteps steps, EnclosureCreator enclosureCreator, - Enclosures enclosures, CheckCreator checkCreator) { - this.docker = docker - this.gradle = gradle - this.steps = steps - this.enclosureCreator = enclosureCreator + public Checks(Object jenkinsScript, Enclosures enclosures) { + this.jenkins = jenkinsScript this.enclosures = enclosures - this.checkCreator = checkCreator } - JavaChecks forJavaPipelines() { - return new JavaChecks(checkCreator, steps) + Step enclosedSimpleCheck(Step testStep, Step analysisStep, Closure catchClosure, Closure finallyClosure) { + return simpleCheck(testStep, analysisStep).wrappedBy { checkStep, platform -> + def enclosedPackedStep = platform.runsOnDocker ? + enclosures.withDocker(platform, checkStep.pack(platform), catchClosure, finallyClosure) : + enclosures.simple(platform, checkStep.pack(platform), catchClosure, finallyClosure) + enclosedPackedStep() + } } - WDKChecks forWDKPipelines() { - return new WDKChecks(checkCreator, steps) + Step simpleCheck(Step testStep, Step analysisStep) { + return new Step({ Platform platform -> + jenkins.dir(platform.checkDirectory) { + testStep(platform) + if (platform.isMain()) { + analysisStep(platform) + } + } + }) } - JSChecks forJSPipelines() { - return new JSChecks(checkCreator, steps) - } + } + + diff --git a/src/net/wooga/jenkins/pipeline/check/Coveralls.groovy b/src/net/wooga/jenkins/pipeline/check/Coveralls.groovy index 8979f258..8d472394 100644 --- a/src/net/wooga/jenkins/pipeline/check/Coveralls.groovy +++ b/src/net/wooga/jenkins/pipeline/check/Coveralls.groovy @@ -1,7 +1,5 @@ package net.wooga.jenkins.pipeline.check -import net.wooga.jenkins.pipeline.model.Gradle - class Coveralls { final Object jenkins @@ -12,23 +10,6 @@ class Coveralls { this.token = token } - void maybeRun(Gradle gradle, String task) { - if (token) { - jenkins.withEnv(["COVERALLS_REPO_TOKEN=${token}"]) { - gradle.wrapper(task) - jenkins.publishHTML([ - allowMissing: true, - alwaysLinkToLastBuild: true, - keepAll: true, - reportDir: 'build/reports/jacoco/test/html', - reportFiles: 'index.html', - reportName: "Coverage ${it}", - reportTitles: '' - ]) - } - } - } - boolean equals(o) { if (this.is(o)) return true if (getClass() != o.class) return false diff --git a/src/net/wooga/jenkins/pipeline/check/EnclosureCreator.groovy b/src/net/wooga/jenkins/pipeline/check/EnclosureCreator.groovy index b35c958a..2776005b 100644 --- a/src/net/wooga/jenkins/pipeline/check/EnclosureCreator.groovy +++ b/src/net/wooga/jenkins/pipeline/check/EnclosureCreator.groovy @@ -13,7 +13,7 @@ class EnclosureCreator { this.buildNumber = buildNumber } - Closure withNodeAndEnv(Platform platform, PackedStep mainCls, Closure catchCls, PackedStep finallyCls) { + Closure nodeForPlatform(Platform platform, PackedStep mainCls, Closure catchCls, PackedStep finallyCls) { def testEnvironment = platform.testEnvironment + ["TRAVIS_JOB_NUMBER=${buildNumber}.${platform.name.toUpperCase()}"] return { diff --git a/src/net/wooga/jenkins/pipeline/check/Enclosures.groovy b/src/net/wooga/jenkins/pipeline/check/Enclosures.groovy index b9ea5fd7..90627dfd 100644 --- a/src/net/wooga/jenkins/pipeline/check/Enclosures.groovy +++ b/src/net/wooga/jenkins/pipeline/check/Enclosures.groovy @@ -17,17 +17,17 @@ class Enclosures { } def withDocker(Platform platform, PackedStep mainCls, Closure catchCls = {throw it}, PackedStep finallyCls = {}) { - return enclosureCreator.withNodeAndEnv(platform, + return enclosureCreator.nodeForPlatform(platform, withCheckout(platform.checkoutDirectory, { docker.runOnImage(mainCls) }), - catchCls, + withOptional(platform.name, platform.optional, catchCls), withCleanup(platform.clearWs, finallyCls) ) } def simple(Platform platform, PackedStep mainClosure, Closure catchCls = {throw it}, PackedStep finallyCls = {}) { - return enclosureCreator.withNodeAndEnv(platform, + return enclosureCreator.nodeForPlatform(platform, withCheckout(platform.checkoutDirectory, mainClosure), - catchCls, + withOptional(platform.name, platform.optional, catchCls), withCleanup(platform.clearWs, finallyCls) ) } @@ -36,8 +36,8 @@ class Enclosures { return { jenkins.dir(checkoutDir) { jenkins.checkout(jenkins.scm) + step() } - step() } } @@ -49,4 +49,16 @@ class Enclosures { } } } + + + //TODO tests + private Closure withOptional(String name, boolean isOptional, Closure catchCls) { + return { exception -> + if (isOptional) { + jenkins.unstable(message: "Optional run ${name} failed, continuing other runs\n${exception.toString()}") + } else { + catchCls(exception) + } + } + } } diff --git a/src/net/wooga/jenkins/pipeline/check/JSChecks.groovy b/src/net/wooga/jenkins/pipeline/check/JSChecks.groovy deleted file mode 100644 index 7b1e7772..00000000 --- a/src/net/wooga/jenkins/pipeline/check/JSChecks.groovy +++ /dev/null @@ -1,53 +0,0 @@ -package net.wooga.jenkins.pipeline.check - -import net.wooga.jenkins.pipeline.check.steps.GradleSteps -import net.wooga.jenkins.pipeline.check.steps.Step -import net.wooga.jenkins.pipeline.config.CheckArgs -import net.wooga.jenkins.pipeline.config.PipelineConventions -import net.wooga.jenkins.pipeline.config.Platform - -class JSChecks { - - final CheckCreator checkCreator - final GradleSteps steps - - JSChecks(CheckCreator checkCreator, GradleSteps steps) { - this.checkCreator = checkCreator - this.steps = steps - } - - Map gradleCheckWithCoverage(Platform[] platforms, CheckArgs checkArgs, PipelineConventions conventions) { - def baseTestStep = steps.defaultGradleTestStep(conventions.checkTask) - def baseAnalysisStep = steps.staticAnalysis(conventions, checkArgs.metadata, checkArgs.sonarqube, checkArgs.coveralls) - return parallel(platforms, - baseTestStep.wrappedBy(checkArgs.testWrapper), - baseAnalysisStep.wrappedBy(checkArgs.analysisWrapper), conventions) - } - - Closure check(Platform platform, Step testStep, Step analysisStep) { - return checkCreator.junitCheck(platform, testStep, analysisStep) - } - - Map parallel(Platform[] platforms, Closure checkStep, - PipelineConventions conventions = PipelineConventions.standard) { - return parallel(platforms, new Step(checkStep), conventions) - } - - Map parallel(Platform[] platforms, Step checkStep, - PipelineConventions conventions = PipelineConventions.standard) { - return parallel(platforms, checkStep, new Step({}), conventions) - } - - Map parallel(Platform[] platforms, Closure testStep, Closure analysisStep, - PipelineConventions conventions = PipelineConventions.standard) { - parallel(platforms, new Step(testStep), new Step(analysisStep), conventions) - } - - Map parallel(Platform[] platforms, Step testStep, Step analysisStep, - PipelineConventions conventions = PipelineConventions.standard) { - return platforms.collectEntries { platform -> - String parallelStepName = "${conventions.javaParallelPrefix}${platform.name}" - return [(parallelStepName): check(platform, testStep, analysisStep)] - } - } -} diff --git a/src/net/wooga/jenkins/pipeline/check/JavaChecks.groovy b/src/net/wooga/jenkins/pipeline/check/JavaChecks.groovy deleted file mode 100644 index e9b1992f..00000000 --- a/src/net/wooga/jenkins/pipeline/check/JavaChecks.groovy +++ /dev/null @@ -1,52 +0,0 @@ -package net.wooga.jenkins.pipeline.check - -import net.wooga.jenkins.pipeline.check.steps.GradleSteps -import net.wooga.jenkins.pipeline.check.steps.Step -import net.wooga.jenkins.pipeline.config.* - -class JavaChecks { - - final CheckCreator checkCreator - final GradleSteps steps - - JavaChecks(CheckCreator checkCreator, GradleSteps steps) { - this.checkCreator = checkCreator - this.steps = steps - } - - Map parallel(Platform[] platforms, Closure checkStep, - PipelineConventions conventions = PipelineConventions.standard) { - return parallel(platforms, new Step(checkStep), conventions) - } - - Map parallel(Platform[] platforms, Step checkStep, - PipelineConventions conventions = PipelineConventions.standard) { - return parallel(platforms, checkStep, new Step({}), conventions) - } - - Map parallel(Platform[] platforms, Closure testStep, Closure analysisStep, - PipelineConventions conventions = PipelineConventions.standard) { - parallel(platforms, new Step(testStep), new Step(analysisStep), conventions) - } - - Map parallel(Platform[] platforms, Step testStep, Step analysisStep, - PipelineConventions conventions = PipelineConventions.standard) { - return platforms.collectEntries { platform -> - String parallelStepName = "${conventions.javaParallelPrefix}${platform.name}" - return [(parallelStepName): check(platform, testStep, analysisStep)] - } - } - - Closure check(Platform platform, Step testStep, Step analysisStep) { - return checkCreator.junitCheck(platform, testStep, analysisStep) - } - - Map gradleCheckWithCoverage(Platform[] platforms, CheckArgs checkArgs, PipelineConventions conventions) { - def baseTestStep = steps.defaultGradleTestStep(conventions.checkTask) - def baseAnalysisStep = steps.jacocoAnalysis(conventions, checkArgs.metadata, checkArgs.sonarqube, checkArgs.coveralls) - - return parallel(platforms, - baseTestStep.wrappedBy(checkArgs.testWrapper), - baseAnalysisStep.wrappedBy(checkArgs.analysisWrapper), conventions) - } -} diff --git a/src/net/wooga/jenkins/pipeline/check/Sonarqube.groovy b/src/net/wooga/jenkins/pipeline/check/Sonarqube.groovy index cdaf5556..e616fbcf 100644 --- a/src/net/wooga/jenkins/pipeline/check/Sonarqube.groovy +++ b/src/net/wooga/jenkins/pipeline/check/Sonarqube.groovy @@ -1,7 +1,5 @@ package net.wooga.jenkins.pipeline.check -import net.wooga.jenkins.pipeline.model.Gradle - class Sonarqube { final String token @@ -10,14 +8,6 @@ class Sonarqube { this.token = token } - void maybeRun(Gradle gradle, String task, String branchName="") { - if(token != null) { - branchName = branchName == null? "" : branchName - gradle.wrapper(task + " -Dsonar.login=${token}" + - " -Pgithub.branch.name=${branchName.trim()}" as String) - } - } - boolean equals(o) { if (this.is(o)) return true if (getClass() != o.class) return false diff --git a/src/net/wooga/jenkins/pipeline/check/WDKChecks.groovy b/src/net/wooga/jenkins/pipeline/check/WDKChecks.groovy deleted file mode 100644 index d6e110bf..00000000 --- a/src/net/wooga/jenkins/pipeline/check/WDKChecks.groovy +++ /dev/null @@ -1,58 +0,0 @@ -package net.wooga.jenkins.pipeline.check - -import net.wooga.jenkins.pipeline.check.steps.GradleSteps -import net.wooga.jenkins.pipeline.check.steps.Step -import net.wooga.jenkins.pipeline.config.* - - -class WDKChecks { - - final CheckCreator checkCreator - final GradleSteps steps - - WDKChecks(CheckCreator checkCreator, GradleSteps steps) { - this.checkCreator = checkCreator - this.steps = steps - } - - Map wdkCoverage(UnityVersionPlatform[] unityVersions, String releaseType, String releaseScope, - CheckArgs checkArgs, PipelineConventions conventions) { - def baseTestStep = steps.wdkTestStep(releaseType, releaseScope, conventions.wdkSetupStashId, conventions.checkTask) - def baseAnalysisStep = steps.wdkAnalysisStep(conventions, checkArgs.metadata, checkArgs.sonarqube) - - return parallel(unityVersions, - baseTestStep.wrappedBy(checkArgs.testWrapper), - baseAnalysisStep.wrappedBy(checkArgs.analysisWrapper), - conventions) - } - - Closure check(UnityVersionPlatform platform, Step testStep, Step analysisStep) { - return checkCreator.csWDKChecks(platform, testStep, analysisStep) - } - - Map parallel(UnityVersionPlatform[] wdkPlatforms, Closure checkStep, - PipelineConventions conventions = PipelineConventions.standard) { - return parallel(wdkPlatforms, new Step(checkStep), conventions) - } - - Map parallel(UnityVersionPlatform[] wdkPlatforms, Step checkStep, - PipelineConventions conventions = PipelineConventions.standard) { - return wdkPlatforms.collectEntries { wdkPlatform -> - [("${conventions.wdkParallelPrefix}${wdkPlatform.platform.name}".toString()): checkStep.pack(wdkPlatform.platform)] - } - } - - Map parallel(UnityVersionPlatform[] wdkPlatforms, Closure testStep, Closure analysisStep, - PipelineConventions conventions = PipelineConventions.standard) { - return parallel(wdkPlatforms, new Step(testStep), new Step(analysisStep), conventions) - } - - Map parallel(UnityVersionPlatform[] wdkPlatforms, Step testStep, Step analysisStep, - PipelineConventions conventions = PipelineConventions.standard) { - return wdkPlatforms.collectEntries { wdkPlatform -> - def checkStep = checkCreator.csWDKChecks(wdkPlatform, testStep, analysisStep) - return [("${conventions.wdkParallelPrefix}${wdkPlatform.platform.name}".toString()): checkStep] - } - } - -} diff --git a/src/net/wooga/jenkins/pipeline/check/steps/GradleSteps.groovy b/src/net/wooga/jenkins/pipeline/check/steps/GradleSteps.groovy deleted file mode 100644 index 1bede8f7..00000000 --- a/src/net/wooga/jenkins/pipeline/check/steps/GradleSteps.groovy +++ /dev/null @@ -1,66 +0,0 @@ -package net.wooga.jenkins.pipeline.check.steps - -import net.wooga.jenkins.pipeline.config.JenkinsMetadata; -import net.wooga.jenkins.pipeline.check.Coveralls -import net.wooga.jenkins.pipeline.check.Sonarqube -import net.wooga.jenkins.pipeline.config.PipelineConventions -import net.wooga.jenkins.pipeline.config.Platform -import net.wooga.jenkins.pipeline.model.Gradle - -class GradleSteps { - - final Object jenkins - final Gradle gradle - - GradleSteps(Object jenkins, Gradle gradle) { - this.jenkins = jenkins - this.gradle = gradle - } - - Step defaultGradleTestStep(String checkTask) { - return new Step({ Platform _ -> - gradle.wrapper(checkTask) - }) - } - - Step jacocoAnalysis(PipelineConventions conventions, - JenkinsMetadata metadata, - Sonarqube sonarqube, - Coveralls coveralls) { - return new Step({ Platform platform -> - gradle.wrapper(conventions.jacocoTask) - def staticAnalysis = staticAnalysis(conventions, metadata, sonarqube, coveralls) - staticAnalysis.call(platform) - }) - } - - Step staticAnalysis(PipelineConventions conventions, - JenkinsMetadata metadata, - Sonarqube sonarqube, - Coveralls coveralls) { - return new Step({ Platform _ -> - def branchName = metadata.isPR() ? null : metadata.branchName - sonarqube.maybeRun(gradle, conventions.sonarqubeTask, branchName) - coveralls.maybeRun(gradle, conventions.coverallsTask) - }) - } - - Step wdkTestStep(String releaseType, String releaseScope, String setupStashId = "setup_w", - String checkTask) { - return new Step({ Platform platform -> - jenkins.unstash setupStashId - gradle.wrapper("-Prelease.stage=${releaseType.trim()} -Prelease.scope=${releaseScope.trim()} ${checkTask}") - }) - } - - Step wdkAnalysisStep(PipelineConventions conventions, - JenkinsMetadata metadata, - Sonarqube sonarqube) { - return new Step({ Platform platform -> - def branchName = metadata.isPR() ? null : metadata.branchName - sonarqube.maybeRun(gradle, conventions.sonarqubeTask, branchName) - def coberturaAdapter = jenkins.istanbulCoberturaAdapter(conventions.wdkCoberturaFile) - jenkins.publishCoverage adapters: [coberturaAdapter], sourceFileResolver: jenkins.sourceFiles('STORE_LAST_BUILD') - }) - } -} diff --git a/src/net/wooga/jenkins/pipeline/check/steps/Step.groovy b/src/net/wooga/jenkins/pipeline/check/steps/Step.groovy index dd9101bc..1e3815bd 100644 --- a/src/net/wooga/jenkins/pipeline/check/steps/Step.groovy +++ b/src/net/wooga/jenkins/pipeline/check/steps/Step.groovy @@ -5,6 +5,8 @@ import net.wooga.jenkins.pipeline.config.Platform class Step { + final static StepWrapper identityWrapper = { step, plat -> step(plat) } + StepFunction stepFunction Step(Closure closure) { diff --git a/src/net/wooga/jenkins/pipeline/config/BaseConfig.groovy b/src/net/wooga/jenkins/pipeline/config/BaseConfig.groovy index 2210f661..7ce6517d 100644 --- a/src/net/wooga/jenkins/pipeline/config/BaseConfig.groovy +++ b/src/net/wooga/jenkins/pipeline/config/BaseConfig.groovy @@ -1,7 +1,5 @@ package net.wooga.jenkins.pipeline.config -import net.wooga.jenkins.pipeline.PipelineTools - class BaseConfig { final Object jenkins final PipelineConventions conventions @@ -10,7 +8,7 @@ class BaseConfig { final DockerArgs dockerArgs final CheckArgs checkArgs - protected static BaseConfig fromConfigMap(Map configMap, Object jenkinsScript) { + static BaseConfig fromConfigMap(Map configMap, Object jenkinsScript) { def conventions = PipelineConventions.standard.mergeWithConfigMap(configMap) def metadata = JenkinsMetadata.fromScript(jenkinsScript) def gradleArgs = GradleArgs.fromConfigMap(configMap) @@ -20,7 +18,7 @@ class BaseConfig { return new BaseConfig(jenkinsScript, conventions, metadata, gradleArgs, dockerArgs, checkArgs) } - protected BaseConfig(Object jenkins, PipelineConventions conventions, JenkinsMetadata metadata, + BaseConfig(Object jenkins, PipelineConventions conventions, JenkinsMetadata metadata, GradleArgs gradleArgs, DockerArgs dockerArgs, CheckArgs checkArgs) { this.jenkins = jenkins this.conventions = conventions diff --git a/src/net/wooga/jenkins/pipeline/config/CheckArgs.groovy b/src/net/wooga/jenkins/pipeline/config/CheckArgs.groovy index dc9fe545..635e951f 100644 --- a/src/net/wooga/jenkins/pipeline/config/CheckArgs.groovy +++ b/src/net/wooga/jenkins/pipeline/config/CheckArgs.groovy @@ -2,13 +2,15 @@ package net.wooga.jenkins.pipeline.config import net.wooga.jenkins.pipeline.check.Coveralls import net.wooga.jenkins.pipeline.check.Sonarqube +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.check.steps.StepWrapper class CheckArgs { final JenkinsMetadata metadata - final Closure testWrapper - final Closure analysisWrapper + final StepWrapper testWrapper + final StepWrapper analysisWrapper final Sonarqube sonarqube final Coveralls coveralls @@ -16,8 +18,8 @@ class CheckArgs { static CheckArgs fromConfigMap(Object jenkins, JenkinsMetadata metadata, Map configMap) { def sonarqubeToken = configMap.sonarToken as String def coverallsToken = configMap.coverallsToken as String - def testWrapper = (configMap.testWrapper ?:{ testOp, plat -> testOp(plat) }) as Closure - def analysisWrapper = (configMap.analysisWrapper ?: { analysisOp, plat -> analysisOp(plat) }) as Closure + def testWrapper = (configMap.testWrapper ?: Step.identityWrapper) as StepWrapper + def analysisWrapper = (configMap.analysisWrapper ?: Step.identityWrapper) as StepWrapper def sonarqube = new Sonarqube(sonarqubeToken) def coveralls = new Coveralls(jenkins, coverallsToken) @@ -25,7 +27,7 @@ class CheckArgs { return new CheckArgs(metadata, testWrapper, analysisWrapper, sonarqube, coveralls) } - CheckArgs(JenkinsMetadata metadata, Closure testWrapper, Closure analysisWrapper, Sonarqube sonarqube, Coveralls coveralls) { + CheckArgs(JenkinsMetadata metadata, StepWrapper testWrapper, StepWrapper analysisWrapper, Sonarqube sonarqube, Coveralls coveralls) { this.metadata = metadata this.testWrapper = testWrapper this.analysisWrapper = analysisWrapper diff --git a/src/net/wooga/jenkins/pipeline/config/Config.groovy b/src/net/wooga/jenkins/pipeline/config/Config.groovy new file mode 100644 index 00000000..728d7266 --- /dev/null +++ b/src/net/wooga/jenkins/pipeline/config/Config.groovy @@ -0,0 +1,48 @@ +package net.wooga.jenkins.pipeline.config + +import net.wooga.jenkins.pipeline.PipelineTools + +class Config implements PipelineConfig { + + final BaseConfig baseConfig + final Platform[] platforms + + Config(BaseConfig baseConfig, List platforms) { + this.baseConfig = baseConfig + this.platforms = platforms + } + + Platform getMainPlatform() { + return platforms.find {it.main } + } + + @Override + PipelineConventions getConventions() { + return baseConfig.conventions + } + + @Override + CheckArgs getCheckArgs() { + return baseConfig.checkArgs + } + + @Override + GradleArgs getGradleArgs() { + return baseConfig.gradleArgs + } + + @Override + DockerArgs getDockerArgs() { + return baseConfig.dockerArgs + } + + @Override + JenkinsMetadata getMetadata() { + return baseConfig.metadata + } + + @Override + PipelineTools getPipelineTools() { + return PipelineTools.fromConfig(baseConfig.jenkins, this) + } +} diff --git a/src/net/wooga/jenkins/pipeline/config/JSConfig.groovy b/src/net/wooga/jenkins/pipeline/config/JSConfig.groovy index 118f5364..b1b9d3a2 100644 --- a/src/net/wooga/jenkins/pipeline/config/JSConfig.groovy +++ b/src/net/wooga/jenkins/pipeline/config/JSConfig.groovy @@ -1,12 +1,13 @@ package net.wooga.jenkins.pipeline.config -import net.wooga.jenkins.pipeline.PipelineTools - -class JSConfig implements PipelineConfig { - - BaseConfig baseConfig - Platform[] platforms - +/** + * Opinionated configurations are now under vars/configs.groovy. + * * WDKConfig.fromConfigMap is replaced by configs().jsWDK(...) + */ +@Deprecated +class JSConfig extends Config { + + @Deprecated static List collectPlatforms(Map configMap, List platformNames) { def index = 0 return platformNames.collect { String platformName -> @@ -16,6 +17,7 @@ class JSConfig implements PipelineConfig { } } + @Deprecated static JSConfig fromConfigMap(Map configMap, Object jenkinsScript) { configMap.platforms = configMap.platforms ?: ['macos'] def baseConfig = BaseConfig.fromConfigMap(configMap, jenkinsScript) @@ -25,37 +27,6 @@ class JSConfig implements PipelineConfig { } JSConfig(BaseConfig baseConfig, List platforms) { - this.baseConfig = baseConfig - this.platforms = platforms - } - - @Override - PipelineConventions getConventions() { - return baseConfig.conventions - } - - @Override - CheckArgs getCheckArgs() { - return baseConfig.checkArgs - } - - @Override - GradleArgs getGradleArgs() { - return baseConfig.gradleArgs - } - - @Override - DockerArgs getDockerArgs() { - return baseConfig.dockerArgs - } - - @Override - JenkinsMetadata getMetadata() { - return baseConfig.metadata - } - - @Override - PipelineTools getPipelineTools() { - return PipelineTools.fromConfig(baseConfig.jenkins, this) + super(baseConfig, platforms) } } diff --git a/src/net/wooga/jenkins/pipeline/config/JavaConfig.groovy b/src/net/wooga/jenkins/pipeline/config/JavaConfig.groovy index 2a3b7473..2fcc7f40 100644 --- a/src/net/wooga/jenkins/pipeline/config/JavaConfig.groovy +++ b/src/net/wooga/jenkins/pipeline/config/JavaConfig.groovy @@ -1,12 +1,13 @@ package net.wooga.jenkins.pipeline.config -import net.wooga.jenkins.pipeline.PipelineTools - -class JavaConfig implements PipelineConfig { - - final BaseConfig baseConfig - final Platform[] platforms - +/** + * Opinionated configurations are now under vars/configs.groovy. + * WDKConfig.fromConfigMap is replaced by configs().java(...) + */ +@Deprecated +class JavaConfig extends Config { + + @Deprecated static List collectPlatform(Map configMap, List platformNames) { def index = 0 return platformNames.collect { String platformName -> @@ -16,6 +17,7 @@ class JavaConfig implements PipelineConfig { } } + @Deprecated static JavaConfig fromConfigMap(Map config, Object jenkinsScript) { config.platforms = config.platforms ?: ['macos','windows'] def platforms = collectPlatform(config, config.platforms as List) @@ -25,71 +27,6 @@ class JavaConfig implements PipelineConfig { } JavaConfig(BaseConfig baseConfig, List platforms) { - this.baseConfig = baseConfig - this.platforms = platforms - } - - Platform getMainPlatform() { - return platforms.find {it.main } - } - - @Override - PipelineConventions getConventions() { - return baseConfig.conventions - } - - @Override - CheckArgs getCheckArgs() { - return baseConfig.checkArgs - } - - @Override - GradleArgs getGradleArgs() { - return baseConfig.gradleArgs - } - - @Override - DockerArgs getDockerArgs() { - return baseConfig.dockerArgs + super(baseConfig, platforms) } - - @Override - JenkinsMetadata getMetadata() { - return baseConfig.metadata - } - - @Override - PipelineTools getPipelineTools() { - return PipelineTools.fromConfig(baseConfig.jenkins, this) - } - - boolean equals(o) { - if (this.is(o)) return true - if (getClass() != o.class) return false - - JavaConfig that = (JavaConfig) o - - if (checkArgs != that.checkArgs) return false - if (conventions != that.conventions) return false - if (dockerArgs != that.dockerArgs) return false - if (gradleArgs != that.gradleArgs) return false - if (jenkins != that.jenkins) return false - if (metadata != that.metadata) return false - if (!Arrays.equals(platforms, that.platforms)) return false - - return true - } - - int hashCode() { - int result - result = (jenkins != null ? jenkins.hashCode() : 0) - result = 31 * result + (conventions != null ? conventions.hashCode() : 0) - result = 31 * result + (platforms != null ? Arrays.hashCode(platforms) : 0) - result = 31 * result + (metadata != null ? metadata.hashCode() : 0) - result = 31 * result + (gradleArgs != null ? gradleArgs.hashCode() : 0) - result = 31 * result + (dockerArgs != null ? dockerArgs.hashCode() : 0) - result = 31 * result + (checkArgs != null ? checkArgs.hashCode() : 0) - return result - } - } diff --git a/src/net/wooga/jenkins/pipeline/config/Platform.groovy b/src/net/wooga/jenkins/pipeline/config/Platform.groovy index 25afdac2..af2bc656 100644 --- a/src/net/wooga/jenkins/pipeline/config/Platform.groovy +++ b/src/net/wooga/jenkins/pipeline/config/Platform.groovy @@ -14,12 +14,12 @@ class Platform { final boolean runsOnDocker final boolean main final boolean clearWs - + final boolean optional static Platform forJava(String platformName, Map config, boolean isMain) { return new Platform( - (config.checkoutDir?: ".") as String, - (config.checkDir?: ".") as String, + (config.checkoutDir ?: ".") as String, + (config.checkDir ?: ".") as String, platformName, platformName, platformName == "linux", @@ -27,36 +27,26 @@ class Platform { mapOrCollection(platformName, config.testEnvironment), mapOrCollection(platformName, config.testLabels), isMain, - (config.clearWs?: false) as boolean + (config.clearWs ?: false) as boolean, + false ) } static Platform forJS(String platformName, Map config, boolean isMain) { - return new Platform( - (config.checkoutDir?: ".") as String, - (config.checkDir?: ".") as String, - platformName, - platformName, - platformName == "linux", - (config.labels ?: '') as String, - mapOrCollection(platformName, config.testEnvironment), - mapOrCollection(platformName, config.testLabels), - isMain, - (config.clearWs?: false) as boolean - ) + return forJava(platformName, config, isMain) } static Platform forWDK(BuildVersion buildVersion, String buildOS, Map config, boolean isMain) { def unityEnv = ["UNITY_LOG_CATEGORY=check-${buildVersion.version}"] - if(buildVersion.hasVersion()) { + if (buildVersion.hasVersion()) { unityEnv.add("UVM_UNITY_VERSION=${buildVersion.version}") } - if (buildVersion.apiCompatibilityLevel != null){ + if (buildVersion.apiCompatibilityLevel != null) { unityEnv.add("UNITY_API_COMPATIBILITY_LEVEL=${buildVersion.apiCompatibilityLevel}") } return new Platform( - (config.checkoutDir?: buildVersion.toDirectoryName()) as String, - (config.checkDir?: ".") as String, + (config.checkoutDir ?: buildVersion.toDirectoryName()) as String, + (config.checkDir ?: ".") as String, buildVersion.version, buildOS, false, @@ -64,12 +54,32 @@ class Platform { mapOrCollection(buildVersion.version, config.testEnvironment) + unityEnv, mapOrCollection(buildVersion.version, config.testLabels), isMain, - (config.clearWs?: false) as boolean + (config.clearWs ?: false) as boolean, + buildVersion.optional ) } + protected static Collection mapOrCollection(String mapKey, Object obj) { + if (obj == null) { + return [] + } + if (obj instanceof Map) { + def value = obj[mapKey] + if (value instanceof String || value instanceof GString) { + return [value?.toString()] ?: [] + } else { + return obj[mapKey] as Collection ?: [] + } + } + if (obj instanceof Collection) { + return obj as Collection + } + throw new IllegalArgumentException("${obj} should be a Collection or a Map of [key:collection] or [key:string]") + } + Platform(String checkoutDirectory, String checkDirectory, String name, String os, boolean runsOnDocker, - String labels, Collection testEnvironment, Collection testLabels, boolean main, boolean clearWs) { + String labels, Collection testEnvironment, Collection testLabels, + boolean main, boolean clearWs, boolean optional) { this.checkoutDirectory = checkoutDirectory this.checkDirectory = checkDirectory this.name = name @@ -80,6 +90,7 @@ class Platform { this.runsOnDocker = runsOnDocker this.main = main this.clearWs = clearWs + this.optional = optional } String generateTestLabelsString() { @@ -87,10 +98,10 @@ class Platform { if (runsOnDocker) { generatedLabels.add("docker") } - def configLabelsStr = testLabels?: labels + def configLabelsStr = testLabels ?: labels def generatedLabelsStr = generatedLabels.join(" && ") - return configLabelsStr != null && !configLabelsStr.empty? + return configLabelsStr != null && !configLabelsStr.empty ? "${configLabelsStr} && ${generatedLabelsStr}".toString() : generatedLabelsStr } @@ -134,22 +145,4 @@ class Platform { result = 31 * result + (main ? 1 : 0) return result } - - protected static Collection mapOrCollection(String mapKey, Object obj) { - if(obj == null) { - return [] - } - if(obj instanceof Map) { - def value = obj[mapKey] - if(value instanceof String || value instanceof GString) { - return [value?.toString()]?: [] - } else { - return obj[mapKey] as Collection ?: [] - } - } - if(obj instanceof Collection) { - return obj as Collection - } - throw new IllegalArgumentException("${obj} should be a Collection or a Map of [key:collection] or [key:string]") - } } diff --git a/src/net/wooga/jenkins/pipeline/config/UnityVersionPlatform.groovy b/src/net/wooga/jenkins/pipeline/config/UnityVersionPlatform.groovy deleted file mode 100644 index e9c083bc..00000000 --- a/src/net/wooga/jenkins/pipeline/config/UnityVersionPlatform.groovy +++ /dev/null @@ -1,49 +0,0 @@ -package net.wooga.jenkins.pipeline.config - -import net.wooga.jenkins.pipeline.BuildVersion - -class UnityVersionPlatform { - final Platform platform - final BuildVersion buildVersion - - UnityVersionPlatform(Platform platform, BuildVersion buildVersion) { - this.platform = platform - this.buildVersion = buildVersion - } - - String getVersion() { - return buildVersion.version - } - - String getStepDescription() { - return "Unity-${buildVersion.toLabel()}" - } - - boolean getOptional() { - return buildVersion.getOptional() - } - - @Override - String toString() { - return buildVersion.version - } - - boolean equals(o) { - if (this.is(o)) return true - if (getClass() != o.class) return false - - UnityVersionPlatform that = (UnityVersionPlatform) o - - if (buildVersion != that.buildVersion) return false - if (platform != that.platform) return false - - return true - } - - int hashCode() { - int result - result = (platform != null ? platform.hashCode() : 0) - result = 31 * result + (buildVersion != null ? buildVersion.hashCode() : 0) - return result - } -} diff --git a/src/net/wooga/jenkins/pipeline/config/WDKConfig.groovy b/src/net/wooga/jenkins/pipeline/config/WDKConfig.groovy index 4fe7c601..14638e92 100644 --- a/src/net/wooga/jenkins/pipeline/config/WDKConfig.groovy +++ b/src/net/wooga/jenkins/pipeline/config/WDKConfig.groovy @@ -3,67 +3,44 @@ package net.wooga.jenkins.pipeline.config import net.wooga.jenkins.pipeline.BuildVersion import net.wooga.jenkins.pipeline.PipelineTools -class WDKConfig implements PipelineConfig { +/** + * Opinionated configurations are now under vars/configs.groovy. + * WDKConfig.fromConfigMap is replaced by configs().unityWDK(...) + */ +@Deprecated +class WDKConfig extends Config { - final UnityVersionPlatform[] unityVersions - final BaseConfig baseConfig final String buildLabel - static List collectUnityVersions(List unityVerObjs, String buildLabel, Map configMap) { + static List collectWDKPlatforms(List unityVerObjs, String buildLabel, Map configMap) { def index = 0 return unityVerObjs.collect { Object unityVersionObj -> def buildVersion = BuildVersion.parse(unityVersionObj) def platform = Platform.forWDK(buildVersion, buildLabel, configMap, index == 0) index++ - return new UnityVersionPlatform(platform, buildVersion) + return platform } } static WDKConfig fromConfigMap(String buildLabel, Map configMap, Object jenkinsScript) { configMap.unityVersions = configMap.unityVersions ?: [] - def unityVersions = collectUnityVersions(configMap.unityVersions as List, buildLabel, configMap) - if (unityVersions.isEmpty()) throw new IllegalArgumentException("Please provide at least one unity version.") + def platforms = collectWDKPlatforms(configMap.unityVersions as List, buildLabel, configMap) + if (platforms.isEmpty()) throw new IllegalArgumentException("Please provide at least one unity version.") def baseConfig = BaseConfig.fromConfigMap(configMap, jenkinsScript) - return new WDKConfig(unityVersions, baseConfig, buildLabel) + return new WDKConfig(platforms, baseConfig, buildLabel) } - WDKConfig(List unityVersions, BaseConfig baseConfig, String buildLabel) { - this.unityVersions = unityVersions - this.baseConfig = baseConfig + WDKConfig(List platforms, BaseConfig baseConfig, String buildLabel) { + super(baseConfig, platforms) this.buildLabel = buildLabel } - @Override - PipelineConventions getConventions() { - return baseConfig.conventions - } - - @Override - CheckArgs getCheckArgs() { - return baseConfig.checkArgs - } - - @Override - GradleArgs getGradleArgs() { - return baseConfig.gradleArgs - } - @Override DockerArgs getDockerArgs() { return null } - - @Override - JenkinsMetadata getMetadata() { - return baseConfig.metadata - } - - @Override - PipelineTools getPipelineTools() { - return PipelineTools.fromConfig(baseConfig.jenkins, this) - } } diff --git a/src/net/wooga/jenkins/pipeline/publish/Publishers.groovy b/src/net/wooga/jenkins/pipeline/publish/Publishers.groovy index 6bdb5703..1fb2dd10 100644 --- a/src/net/wooga/jenkins/pipeline/publish/Publishers.groovy +++ b/src/net/wooga/jenkins/pipeline/publish/Publishers.groovy @@ -104,5 +104,4 @@ class Publishers { gradle.wrapper("${releaseType} -Prelease.stage=${releaseType} -Prelease.scope=${releaseScope} -x check") } } - } diff --git a/test/groovy/net/wooga/jenkins/pipeline/config/PlatformSpec.groovy b/test/groovy/net/wooga/jenkins/pipeline/config/PlatformSpec.groovy index 1ac86856..468ea070 100644 --- a/test/groovy/net/wooga/jenkins/pipeline/config/PlatformSpec.groovy +++ b/test/groovy/net/wooga/jenkins/pipeline/config/PlatformSpec.groovy @@ -26,22 +26,22 @@ class PlatformSpec extends Specification { where: config | isMain | platName | expected - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | "name" | new Platform(".", ".", "name", "name", false, "", [], [], true, false) - [checkDir: "dir"] | false | "name" | new Platform(".", "dir", "name", "name", false, "", [], [], false, false) - [checkoutDir: "dir"] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, false) - [checkoutDir: "dir", clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true) - [clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true) - [testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], [], false, false) - [testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | true | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], ["l", "l2"], true, false) - [labels: "label", testLabels: ["t", "t2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false) - [labels: "label", testLabels: [name: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false) - [labels: "label", testLabels: [notname: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false) - [labels: "label", testEnvironment: [name: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false) - [labels: "label", testEnvironment: [notname: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false) - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", [], [], false, false) - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "linux" | new Platform(".", ".", "linux", "linux", true, "", [], [], false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | "name" | new Platform(".", ".", "name", "name", false, "", [], [], true, false, false) + [checkDir: "dir"] | false | "name" | new Platform(".", "dir", "name", "name", false, "", [], [], false, false, false) + [checkoutDir: "dir"] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, false, false) + [checkoutDir: "dir", clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true, false) + [clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true, false) + [testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], [], false, false, false) + [testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | true | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], ["l", "l2"], true, false, false) + [labels: "label", testLabels: ["t", "t2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false, false) + [labels: "label", testLabels: [name: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false, false) + [labels: "label", testLabels: [notname: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false, false) + [labels: "label", testEnvironment: [name: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false, false) + [labels: "label", testEnvironment: [notname: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", [], [], false, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "linux" | new Platform(".", ".", "linux", "linux", true, "", [], [], false, false, false) } @@ -70,25 +70,27 @@ class PlatformSpec extends Specification { platform.main == expected.main where: - config | isMain | buildVersion | expected - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", [], [], true, false) - [checkDir: "dir"] | false | buildVersion("v") | new Platform("v", "dir", "v", "macos", false, "", [], [], false, false) - [checkoutDir: "dir"] | false | buildVersion("v") | new Platform("dir", ".", "v", "macos", false, "", [], [], false, false) - [checkoutDir: "dir", clearWs: true] | false | buildVersion("v") | new Platform("dir", ".", "v", "macos", false, "", [], [], false, true) - [clearWs: true] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", [], [], false, true) - [testEnvironment: ["t=a", "t2=b"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", ["t=a", "t2=b"], [], false, false) - [testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | true | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", ["t=a", "t2=b"], ["l", "l2"], true, false) - [labels: "label", testLabels: ["t", "t2"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], ["t", "t2"], false, false) - [labels: "label", testLabels: [v: ["t", "t2"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], ["t", "t2"], false, false) - [labels: "label", testLabels: [v: "tag"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], ["tag"], false, false) - [labels: "label", testLabels: [notv: ["t", "t2"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], [], false, false) - [labels: "label", testEnvironment: [v: ["t=a", "t2=b"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", ["t=a", "t2=b"], [], false, false) - [labels: "label", testEnvironment: [notv: ["t=a", "t2=b"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], [], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", ["t=a", "t2=b"], [], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | buildVersion("v", "lv") | new Platform("v_lv", ".", "v", "macos", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false) - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", [], [], false, false) - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | buildVersion("v", "lv") | new Platform("v_lv", ".", "v", "macos", false, "", [], [], false, false) + config | isMain | buildVersion | expected + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", [], [], true, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | buildVersion("v", true) | new Platform("v", ".", "v", "macos", false, "", [], [], true, false, true) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | buildVersion("v", false) | new Platform("v", ".", "v", "macos", false, "", [], [], true, false, false) + [checkDir: "dir"] | false | buildVersion("v") | new Platform("v", "dir", "v", "macos", false, "", [], [], false, false, false) + [checkoutDir: "dir"] | false | buildVersion("v") | new Platform("dir", ".", "v", "macos", false, "", [], [], false, false, false) + [checkoutDir: "dir", clearWs: true] | false | buildVersion("v") | new Platform("dir", ".", "v", "macos", false, "", [], [], false, true, false) + [clearWs: true] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", [], [], false, true, false) + [testEnvironment: ["t=a", "t2=b"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", ["t=a", "t2=b"], [], false, false, false) + [testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | true | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", ["t=a", "t2=b"], ["l", "l2"], true, false, false) + [labels: "label", testLabels: ["t", "t2"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], ["t", "t2"], false, false, false) + [labels: "label", testLabels: [v: ["t", "t2"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], ["t", "t2"], false, false, false) + [labels: "label", testLabels: [v: "tag"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], ["tag"], false, false, false) + [labels: "label", testLabels: [notv: ["t", "t2"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], [], false, false, false) + [labels: "label", testEnvironment: [v: ["t=a", "t2=b"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", ["t=a", "t2=b"], [], false, false, false) + [labels: "label", testEnvironment: [notv: ["t=a", "t2=b"]]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", [], [], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", ["t=a", "t2=b"], [], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | buildVersion("v", false, "lv") | new Platform("v_lv", ".", "v", "macos", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | buildVersion("v") | new Platform("v", ".", "v", "macos", false, "", [], [], false, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | buildVersion("v", false, "lv") | new Platform("v_lv", ".", "v", "macos", false, "", [], [], false, false, false) } @Unroll("creates platform named #platName from js config map #config") @@ -111,28 +113,28 @@ class PlatformSpec extends Specification { where: config | isMain | platName | expected - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | "name" | new Platform(".", ".", "name", "name", false, "", [], [], true, false) - [checkDir: "dir"] | false | "name" | new Platform(".", "dir", "name", "name", false, "", [], [], false, false) - [checkoutDir: "dir"] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, false) - [checkoutDir: "dir", clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true) - [clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true) - [testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], [], false, false) - [testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | true | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], ["l", "l2"], true, false) - [labels: "label", testLabels: ["t", "t2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false) - [labels: "label", testLabels: [name: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false) - [labels: "label", testLabels: [notname: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false) - [labels: "label", testEnvironment: [name: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false) - [labels: "label", testEnvironment: [notname: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false) - [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false) - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", [], [], false, false) - [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "linux" | new Platform(".", ".", "linux", "linux", true, "", [], [], false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: null] | true | "name" | new Platform(".", ".", "name", "name", false, "", [], [], true, false, false) + [checkDir: "dir"] | false | "name" | new Platform(".", "dir", "name", "name", false, "", [], [], false, false, false) + [checkoutDir: "dir"] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, false, false) + [checkoutDir: "dir", clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true, false) + [clearWs: true] | false | "name" | new Platform("dir", ".", "name", "name", false, "", [], [], false, true, false) + [testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], [], false, false, false) + [testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | true | "name" | new Platform(".", ".", "name", "name", false, "", ["t=a", "t2=b"], ["l", "l2"], true, false, false) + [labels: "label", testLabels: ["t", "t2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false, false) + [labels: "label", testLabels: [name: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], ["t", "t2"], false, false, false) + [labels: "label", testLabels: [notname: ["t", "t2"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false, false) + [labels: "label", testEnvironment: [name: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false, false) + [labels: "label", testEnvironment: [notname: ["t=a", "t2=b"]]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", [], [], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], [], false, false, false) + [labels: "label", testEnvironment: ["t=a", "t2=b"], testLabels: ["l", "l2"]] | false | "name" | new Platform(".", ".", "name", "name", false, "label", ["t=a", "t2=b"], ["l", "l2"], false, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "name" | new Platform(".", ".", "name", "name", false, "", [], [], false, false, false) + [labels: null, testEnvironment: null, testLabels: null, dockerArgs: [not: "nul"]] | false | "linux" | new Platform(".", ".", "linux", "linux", true, "", [], [], false, false, false) } @Unroll def "generates test label string"() { given: "a valid platform" - def platform = new Platform(".", ".", "platname", os, false, labels, [], testLabels, false, false) + def platform = new Platform(".", ".", "platname", os, false, labels, [], testLabels, false, false, false) when: "generating test label string" def labelsStr = platform.generateTestLabelsString() then: @@ -167,7 +169,7 @@ class PlatformSpec extends Specification { } - def buildVersion(String version, String apiCompatibilityLevel = null) { + def buildVersion(String version, boolean optional = false, String apiCompatibilityLevel = null) { return new BuildVersion(version, false, apiCompatibilityLevel) } } diff --git a/test/groovy/scripts/BuildGradlePluginSpec.groovy b/test/groovy/scripts/BuildGradlePluginSpec.groovy index f8c72108..7af8334e 100644 --- a/test/groovy/scripts/BuildGradlePluginSpec.groovy +++ b/test/groovy/scripts/BuildGradlePluginSpec.groovy @@ -48,7 +48,7 @@ class BuildGradlePluginSpec extends DeclarativeJenkinsSpec { inSandbox { buildGradlePlugin() } then: "runs gradle with parameters" - def gradleCall = getShGradleCalls().first() + def gradleCall = (getShGradleCalls().find() ?: "") as String skipsRelease || (gradleCall != null) skipsRelease ^ gradleCall.contains(releaseType) skipsRelease ^ gradleCall.contains("-Pgradle.publish.key=key") diff --git a/test/groovy/scripts/BuildJavaLibraryOSSRHSpec.groovy b/test/groovy/scripts/BuildJavaLibraryOSSRHSpec.groovy index bea9e96e..f507ffee 100644 --- a/test/groovy/scripts/BuildJavaLibraryOSSRHSpec.groovy +++ b/test/groovy/scripts/BuildJavaLibraryOSSRHSpec.groovy @@ -52,7 +52,7 @@ class BuildJavaLibraryOSSRHSpec extends DeclarativeJenkinsSpec { inSandbox { buildJavaLibrary() } then: "runs gradle with parameters" - def gradleCall = getShGradleCalls().first() + def gradleCall = (getShGradleCalls().find() ?: "") as String skipsRelease || (gradleCall != null) skipsRelease ^ gradleCall.contains(releaseType) skipsRelease ^ gradleCall.contains("-Prelease.stage=${releaseType}") diff --git a/test/groovy/scripts/BuildJavaLibrarySpec.groovy b/test/groovy/scripts/BuildJavaLibrarySpec.groovy index e68d20c3..483a5d3d 100644 --- a/test/groovy/scripts/BuildJavaLibrarySpec.groovy +++ b/test/groovy/scripts/BuildJavaLibrarySpec.groovy @@ -49,8 +49,8 @@ class BuildJavaLibrarySpec extends DeclarativeJenkinsSpec { inSandbox { buildJavaLibrary() } then: "runs gradle with parameters" - def gradleCall = getShGradleCalls().first() - skipsRelease || (gradleCall != null) + def gradleCall = (getShGradleCalls().find() ?: "") as String + skipsRelease || (gradleCall != "") skipsRelease ^ gradleCall.contains(releaseType) skipsRelease ^ gradleCall.contains("-Pbintray.user=user") skipsRelease ^ gradleCall.contains("-Pbintray.key=key") diff --git a/test/groovy/scripts/BuildWDKJSSpec.groovy b/test/groovy/scripts/BuildWDKJSSpec.groovy index 51424732..c0c6a107 100644 --- a/test/groovy/scripts/BuildWDKJSSpec.groovy +++ b/test/groovy/scripts/BuildWDKJSSpec.groovy @@ -142,10 +142,10 @@ class BuildWDKJSSpec extends DeclarativeJenkinsSpec { given: "loaded check in a running jenkins build" def buildWDKJS = loadSandboxedScript(SCRIPT_PATH) and: "configuration object with any platforms" - def configMap = [platforms: ["linux"], - sonarToken: "token", coverallsToken: "token", - checkTask: convCheck, sonarqubeTask: convSonarqubeTask, - jacocoTask: convJacocoTask, javaParallelPrefix: convJavaParallelPrefix, + def configMap = [platforms : ["linux"], + sonarToken : "token", coverallsToken: "token", + checkTask : convCheck, sonarqubeTask: convSonarqubeTask, + jacocoTask : convJacocoTask, javaParallelPrefix: convJavaParallelPrefix, coverallsTask: convCoverallsTask] when: "running check" @@ -180,9 +180,9 @@ class BuildWDKJSSpec extends DeclarativeJenkinsSpec { and: "configuration object with any platforms and desired wrappers" def configMap = [ - platforms: ["linux", "windows"], - sonarToken: "token", coverallsToken: "token", - testWrapper: { testOp, platform -> + platforms : ["linux", "windows"], + sonarToken : "token", coverallsToken: "token", + testWrapper : { testOp, platform -> testCount.incrementAndGet() testOp(platform) }, @@ -244,15 +244,17 @@ class BuildWDKJSSpec extends DeclarativeJenkinsSpec { def buildWDKJS = loadSandboxedScript(SCRIPT_PATH) and: "configuration object with any platforms and wrappers for test result capture" def stepsDirs = [] - def configMap = [platforms: ["linux"], checkDir: checkDir, - testWrapper: { testOp, platform -> - stepsDirs.add(this.currentDir) - testOp(platform) - }, - analysisWrapper: { analysisOp, platform -> - stepsDirs.add(this.currentDir) - analysisOp(platform) - }] + def configMap = [ + platforms : ["linux"], + checkDir : checkDir, checkoutDir: checkoutDir, + testWrapper : { testOp, platform -> + stepsDirs.add(this.currentDir) + testOp(platform) + }, + analysisWrapper: { analysisOp, platform -> + stepsDirs.add(this.currentDir) + analysisOp(platform) + }] when: "running check" inSandbox { @@ -263,10 +265,16 @@ class BuildWDKJSSpec extends DeclarativeJenkinsSpec { then: "steps ran on given directory" //checks steps + 1 analysis step stepsDirs.size() == configMap.platforms.size() + 1 - stepsDirs.every {it == checkDir} + stepsDirs.every { it == expectedDir } where: - checkDir << [".", "dir", "dir/subdir"] + checkDir | checkoutDir | expectedDir + "" | null | "./." + "." | null | "./." + "." | "checkoutdir" | "checkoutdir/." + "dir" | null | "./dir" + "dir/subdir" | null | "./dir/subdir" + "dir/subdir" | "checkout" | "checkout/dir/subdir" } @Unroll("#description all check workspaces when clearWs is #clearWs") @@ -281,15 +289,15 @@ class BuildWDKJSSpec extends DeclarativeJenkinsSpec { } then: "all platforms workspaces are clean" - calls["cleanWs"].length == (clearWs? platforms.size() : 0) + calls["cleanWs"].length == (clearWs ? platforms.size() : 0) where: - platforms | clearWs - ["linux"] | true - ["linux"] | false + platforms | clearWs + ["linux"] | true + ["linux"] | false ["linux", "windows"] | true ["linux", "windows"] | false - description = clearWs? "clears" : "doesn't clear" + description = clearWs ? "clears" : "doesn't clear" } // jenkins.usernamePassword(credentialsId: npmCredsSecret, // usernameVariable:"NODE_RELEASE_NPM_USER", @@ -316,7 +324,7 @@ class BuildWDKJSSpec extends DeclarativeJenkinsSpec { skipsRelease ^ gradleCall.contains("-Prelease.scope=${releaseScope}") skipsRelease ^ gradleCall.contains("-x check") and: "sets credentials on environment" - def env = usedEnvironments.last() + def env = usedEnvironments.last() skipsRelease ^ env["NODE_RELEASE_NPM_USER"] == "npmusr" skipsRelease ^ env["NODE_RELEASE_NPM_PASS"] == "npmpwd" diff --git a/test/groovy/net/wooga/jenkins/pipeline/config/JSConfigSpec.groovy b/test/groovy/scripts/JSConfigSpec.groovy similarity index 77% rename from test/groovy/net/wooga/jenkins/pipeline/config/JSConfigSpec.groovy rename to test/groovy/scripts/JSConfigSpec.groovy index f7973d6e..9535a3f2 100644 --- a/test/groovy/net/wooga/jenkins/pipeline/config/JSConfigSpec.groovy +++ b/test/groovy/scripts/JSConfigSpec.groovy @@ -1,10 +1,18 @@ -package net.wooga.jenkins.pipeline.config +package scripts +import net.wooga.jenkins.pipeline.config.BaseConfig +import net.wooga.jenkins.pipeline.config.CheckArgs +import net.wooga.jenkins.pipeline.config.Config +import net.wooga.jenkins.pipeline.config.DockerArgs +import net.wooga.jenkins.pipeline.config.GradleArgs +import net.wooga.jenkins.pipeline.config.JenkinsMetadata +import net.wooga.jenkins.pipeline.config.PipelineConventions +import net.wooga.jenkins.pipeline.config.Platform import spock.lang.Shared -import spock.lang.Specification import spock.lang.Unroll +import tools.DeclarativeJenkinsSpec -class JSConfigSpec extends Specification { +class JSConfigSpec extends DeclarativeJenkinsSpec { @Shared def jenkinsScript = [BUILD_NUMBER: 1, BRANCH_NAME: "branch"] @@ -13,8 +21,11 @@ class JSConfigSpec extends Specification { def "creates valid config object from config map"() { given: "a configuration map" def configMap = [platforms: platforms, dockerArgs: dockerArgs, coverallsToken: cvallsToken] + extraFields + and: "loaded configs script" + def configs = loadSandboxedScript("vars/configs.groovy") + when: "generating config object from map" - def config = JSConfig.fromConfigMap(configMap, jenkinsScript) + def config = inSandboxClonedReturn { configs().jsWDK(configMap, jenkinsScript) } as Config then: "generated config object is valid and matches map values" config.metadata == expected.metadata config.platforms == expected.platforms @@ -33,7 +44,7 @@ class JSConfigSpec extends Specification { ["plat"] | null | [logLevel: "info", stackTrace: true, refreshDependencies: true] | null | ["labels": "label"] | configWith(["plat"], [:], [logLevel: "info", stackTrace: true, refreshDependencies: true], ["labels": "label"], null) } - JavaConfig configWith(List platforms, Map dockerArgs = [:], Map gradleArgs = [:], Map extraFields = [:], String coverallsToken = null) { + Config configWith(List platforms, Map dockerArgs = [:], Map gradleArgs = [:], Map extraFields = [:], String coverallsToken = null) { def cfgMap = [platforms: platforms, dockerArgs: dockerArgs, coverallsToken: coverallsToken] + extraFields def metadata = JenkinsMetadata.fromScript(jenkinsScript) def baseConfig = new BaseConfig(jenkinsScript, @@ -45,6 +56,6 @@ class JSConfigSpec extends Specification { def platformObjs = platforms.withIndex().collect { String platName, int index -> Platform.forJava(platName, cfgMap, index == 0) } - return new JavaConfig(baseConfig, platformObjs) + return new Config(baseConfig, platformObjs) } } diff --git a/test/groovy/scripts/JavaCheckSpec.groovy b/test/groovy/scripts/JavaCheckSpec.groovy index 010c22a2..0e05a548 100644 --- a/test/groovy/scripts/JavaCheckSpec.groovy +++ b/test/groovy/scripts/JavaCheckSpec.groovy @@ -236,11 +236,11 @@ class JavaCheckSpec extends DeclarativeJenkinsSpec { given: "loaded check in a running jenkins build" def check = loadSandboxedScript(TEST_SCRIPT_PATH) and: "configuration object with any platforms" - def configMap = [platforms: ["linux"], - sonarToken: "token", coverallsToken: "token", - checkTask: convCheck, sonarqubeTask: convSonarqubeTask, - jacocoTask: convJacocoTask, javaParallelPrefix: convJavaParallelPrefix, - coverallsTask: convCoverallsTask] + def configMap = [platforms : ["linux"], + sonarToken : "token", coverallsToken: "token", + checkTask : convCheck, sonarqubeTask: convSonarqubeTask, + jacocoTask : convJacocoTask, javaParallelPrefix: convJavaParallelPrefix, + coverallsTask: convCoverallsTask] when: "running check" Map checkSteps = inSandbox { @@ -285,16 +285,16 @@ class JavaCheckSpec extends DeclarativeJenkinsSpec { and: "configuration object with any platforms and desired wrappers" def configMap = [ - platforms: ["linux", "windows"], - sonarToken: "token", coverallsToken: "token", - testWrapper: { testOp, platform -> - testCount.incrementAndGet() - testOp(platform) - }, - analysisWrapper: { analysisOp, platform -> - analysisCount.incrementAndGet() - analysisOp(platform) - } + platforms : ["linux", "windows"], + sonarToken : "token", coverallsToken: "token", + testWrapper : { testOp, platform -> + testCount.incrementAndGet() + testOp(platform) + }, + analysisWrapper: { analysisOp, platform -> + analysisCount.incrementAndGet() + analysisOp(platform) + } ] when: "running check" @@ -346,21 +346,24 @@ class JavaCheckSpec extends DeclarativeJenkinsSpec { checkoutDir << [".", "dir", "dir/subdir"] } - @Unroll("runs test and analysis step on #checkDir") + @Unroll("runs test and analysis step on #checkDir inside #checkoutDir") def "runs test and analysis step on given checkDir"() { given: "loaded check in a running jenkins build" def check = loadSandboxedScript(TEST_SCRIPT_PATH) and: "configuration object with any platforms and wrappers for test result capture" def stepsDirs = [] - def configMap = [platforms: ["linux"], checkDir: checkDir, - testWrapper: { testOp, platform -> - stepsDirs.add(this.currentDir) - testOp(platform) + def configMap = [ + platforms : ["linux"], + checkDir : checkDir, + checkoutDir : checkoutDir, + testWrapper : { testOp, platform -> + stepsDirs.add(this.currentDir) + testOp(platform) }, - analysisWrapper: { analysisOp, platform -> - stepsDirs.add(this.currentDir) - analysisOp(platform) - }] + analysisWrapper: { analysisOp, platform -> + stepsDirs.add(this.currentDir) + analysisOp(platform) + }] when: "running check" inSandbox { @@ -371,10 +374,18 @@ class JavaCheckSpec extends DeclarativeJenkinsSpec { then: "steps ran on given directory" //checks steps + 1 analysis step stepsDirs.size() == configMap.platforms.size() + 1 - stepsDirs.every {it == checkDir} + stepsDirs.every { + it == expectedDir + } where: - checkDir << [".", "dir", "dir/subdir"] + checkDir | checkoutDir | expectedDir + "" | null | "./." + "." | null | "./." + "." | "checkoutdir" | "checkoutdir/." + "dir" | null | "./dir" + "dir/subdir" | null | "./dir/subdir" + "dir/subdir" | "checkout" | "checkout/dir/subdir" } @Unroll("#description all check workspaces when clearWs is #clearWs") @@ -389,15 +400,15 @@ class JavaCheckSpec extends DeclarativeJenkinsSpec { } then: "all platforms workspaces are clean" - calls["cleanWs"].length == (clearWs? platforms.size() : 0) + calls["cleanWs"].length == (clearWs ? platforms.size() : 0) where: - platforms | clearWs - ["linux"] | true - ["linux"] | false + platforms | clearWs + ["linux"] | true + ["linux"] | false ["linux", "windows"] | true ["linux", "windows"] | false - description = clearWs? "clears" : "doesn't clear" + description = clearWs ? "clears" : "doesn't clear" } static def createTmpFile(String dir = ".", String file) { diff --git a/test/groovy/net/wooga/jenkins/pipeline/config/JavaConfigSpec.groovy b/test/groovy/scripts/JavaConfigSpec.groovy similarity index 78% rename from test/groovy/net/wooga/jenkins/pipeline/config/JavaConfigSpec.groovy rename to test/groovy/scripts/JavaConfigSpec.groovy index ef0e8443..53fae0b0 100644 --- a/test/groovy/net/wooga/jenkins/pipeline/config/JavaConfigSpec.groovy +++ b/test/groovy/scripts/JavaConfigSpec.groovy @@ -1,10 +1,18 @@ -package net.wooga.jenkins.pipeline.config +package scripts +import net.wooga.jenkins.pipeline.config.BaseConfig +import net.wooga.jenkins.pipeline.config.CheckArgs +import net.wooga.jenkins.pipeline.config.Config +import net.wooga.jenkins.pipeline.config.DockerArgs +import net.wooga.jenkins.pipeline.config.GradleArgs +import net.wooga.jenkins.pipeline.config.JenkinsMetadata +import net.wooga.jenkins.pipeline.config.PipelineConventions +import net.wooga.jenkins.pipeline.config.Platform import spock.lang.Shared -import spock.lang.Specification import spock.lang.Unroll +import tools.DeclarativeJenkinsSpec -class JavaConfigSpec extends Specification { +class JavaConfigSpec extends DeclarativeJenkinsSpec { @Shared def jenkinsScript = [BUILD_NUMBER: 1, BRANCH_NAME: "branch"] @@ -13,8 +21,10 @@ class JavaConfigSpec extends Specification { def "creates valid config object from config map"() { given: "a configuration map" def configMap = [platforms: platforms, dockerArgs: dockerArgs, coverallsToken: cvallsToken] + extraFields + and: "loaded configs script" + def configs = loadSandboxedScript("vars/configs.groovy") when: "generating config object from map" - def config = JavaConfig.fromConfigMap(configMap, jenkinsScript) + def config = inSandboxClonedReturn { configs().java(configMap, jenkinsScript) } as Config then: "generated config object is valid and matches map values" config.metadata == expected.metadata config.platforms == expected.platforms @@ -34,7 +44,7 @@ class JavaConfigSpec extends Specification { ["plat"] | null | [logLevel: "info", stackTrace: true, refreshDependencies: true] | null | ["labels": "label"] | configWith(["plat"], [:], [logLevel: "info", stackTrace: true, refreshDependencies: true], ["labels": "label"], null) } - JavaConfig configWith(List platforms, Map dockerArgs = [:], Map gradleArgs = [:], Map extraFields = [:], String coverallsToken = null) { + Config configWith(List platforms, Map dockerArgs = [:], Map gradleArgs = [:], Map extraFields = [:], String coverallsToken = null) { def cfgMap = [platforms: platforms, dockerArgs: dockerArgs, coverallsToken: coverallsToken] + extraFields def metadata = JenkinsMetadata.fromScript(jenkinsScript) def baseConfig = new BaseConfig(jenkinsScript, @@ -46,6 +56,6 @@ class JavaConfigSpec extends Specification { def platformObjs = platforms.withIndex().collect { String platName, int index -> Platform.forJava(platName, cfgMap, index == 0) } - return new JavaConfig(baseConfig, platformObjs) + return new Config(baseConfig, platformObjs) } } diff --git a/test/groovy/scripts/WDKCheckSpec.groovy b/test/groovy/scripts/WDKCheckSpec.groovy index f12504e2..7d4cb7ba 100644 --- a/test/groovy/scripts/WDKCheckSpec.groovy +++ b/test/groovy/scripts/WDKCheckSpec.groovy @@ -246,7 +246,7 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { and: "configuration object with given platforms" def configMap = [unityVersions: [version]] and: "some failing script step" - helper.registerAllowedMethod("dir", [String, Closure]) { throw new Exception() } + helper.registerAllowedMethod("dir", [String, Closure]) { throw new Exception("this shouldn't break") } when: "running check" inSandbox { @@ -258,7 +258,7 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { noExceptionThrown() calls.has["unstable"] { MethodCall it -> String message = it.args[0]["message"] - message.startsWith("Unity build for optional version ${version.version} is found to be unstable") + return message.length() > 0 } where: version << [[version: "2019", optional: true]] @@ -338,7 +338,7 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { given: "loaded check in a running jenkins build" def check = loadSandboxedScript(TEST_SCRIPT_PATH) and: "configuration object with given platforms" - def configMap = [unityVersions: ["any"], + def configMap = [unityVersions : ["any"], checkTask : convCheck, sonarqubeTask : convSonarqube, wdkCoberturaFile : convWDKCoberturaFile, @@ -382,15 +382,15 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { def testCount = new AtomicInteger(0) def analysisCount = new AtomicInteger(0) and: "configuration object with given platforms with wrapper code" - def configMap = [unityVersions: ["any", "other"], - testWrapper: { testOp, unityPlatform -> - testCount.incrementAndGet() - testOp(unityPlatform) - }, - analysisWrapper: { analysisOp, unityPlatform -> - analysisCount.incrementAndGet() - analysisOp(unityPlatform) - }] + def configMap = [unityVersions : ["any", "other"], + testWrapper : { testOp, unityPlatform -> + testCount.incrementAndGet() + testOp(unityPlatform) + }, + analysisWrapper: { analysisOp, unityPlatform -> + analysisCount.incrementAndGet() + analysisOp(unityPlatform) + }] and: "stashed setup data" jenkinsStash[PipelineConventions.standard.wdkSetupStashId] = [:] @@ -434,21 +434,23 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { checkoutDir << [".", "dir", "dir/subdir"] } - @Unroll("runs test and analysis step on #checkDir") + @Unroll("runs test and analysis step on #checkoutDir/#checkDir") def "runs test and analysis step on given checkDir"() { given: "loaded check in a running jenkins build" def check = loadSandboxedScript(TEST_SCRIPT_PATH) and: "configuration object with any platforms and wrappers for test assertion" def stepsDirs = [] - def configMap = [unityVersions: ["2019"], checkDir: checkDir, - testWrapper: { testOp, platform -> - stepsDirs.add(this.currentDir) - testOp(platform) - }, - analysisWrapper: { analysisOp, platform -> - stepsDirs.add(this.currentDir) - analysisOp(platform) - }] + def configMap = [ + unityVersions : [platform], + checkDir : checkDir, checkoutDir: checkoutDir, + testWrapper : { testOp, platform -> + stepsDirs.add(this.currentDir) + testOp(platform) + }, + analysisWrapper: { analysisOp, platform -> + stepsDirs.add(this.currentDir) + analysisOp(platform) + }] and: "stashed setup" jenkinsStash["setup_w"] = [:] @@ -462,10 +464,18 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { then: "steps ran on given directory" //checks steps + 1 analysis step stepsDirs.size() == configMap.unityVersions.size() + 1 - stepsDirs.every { it == checkDir } + stepsDirs.every { + it == expectedDir + } where: - checkDir << [".", "dir", "dir/subdir"] + platform | checkDir | checkoutDir | expectedDir + "2019" | "" | null | "2019/." + "2019" | "." | null | "2019/." + "2020" | "." | "checkoutdir" | "checkoutdir/." + "2015" | "dir" | null | "2015/dir" + "name" | "dir/subdir" | null | "name/dir/subdir" + "1234" | "dir/subdir" | "checkout" | "checkout/dir/subdir" } @Unroll("#description all check workspaces when clearWs is #clearWs") @@ -488,14 +498,14 @@ class WDKCheckSpec extends DeclarativeJenkinsSpec { } } then: "all platforms workspaces are clean" - calls["cleanWs"].length == (clearWs? versions.size() : 0) + calls["cleanWs"].length == (clearWs ? versions.size() : 0) where: - versions | clearWs - ["2019"] | true - ["2019"] | false + versions | clearWs + ["2019"] | true + ["2019"] | false ["2019", "2022"] | true ["2019", "2022"] | false - description = clearWs? "clears" : "doesn't clear" + description = clearWs ? "clears" : "doesn't clear" } } diff --git a/test/groovy/net/wooga/jenkins/pipeline/config/WDKConfigSpec.groovy b/test/groovy/scripts/WDKConfigSpec.groovy similarity index 65% rename from test/groovy/net/wooga/jenkins/pipeline/config/WDKConfigSpec.groovy rename to test/groovy/scripts/WDKConfigSpec.groovy index 7e05a590..7d2e67ec 100644 --- a/test/groovy/net/wooga/jenkins/pipeline/config/WDKConfigSpec.groovy +++ b/test/groovy/scripts/WDKConfigSpec.groovy @@ -1,28 +1,37 @@ -package net.wooga.jenkins.pipeline.config +package scripts import net.wooga.jenkins.pipeline.BuildVersion +import net.wooga.jenkins.pipeline.config.BaseConfig +import net.wooga.jenkins.pipeline.config.CheckArgs +import net.wooga.jenkins.pipeline.config.DockerArgs +import net.wooga.jenkins.pipeline.config.GradleArgs +import net.wooga.jenkins.pipeline.config.Config +import net.wooga.jenkins.pipeline.config.JenkinsMetadata +import net.wooga.jenkins.pipeline.config.PipelineConventions +import net.wooga.jenkins.pipeline.config.Platform import spock.lang.Shared -import spock.lang.Specification import spock.lang.Unroll +import tools.DeclarativeJenkinsSpec import tools.FakeJenkinsObject -class WDKConfigSpec extends Specification { +class WDKConfigSpec extends DeclarativeJenkinsSpec { @Shared def jenkinsScript = new FakeJenkinsObject([BUILD_NUMBER: 1, BRANCH_NAME: "branch"]) - @Unroll("creates valid WDKConfig object from #configMap") - def "creates valid WDKConfig object from config map"() { + @Unroll("creates valid WDK Config object from #configMap") + def "creates valid WDK Config object from config map"() { given: "a configuration map" and: "a jenkins build label" + and: "loaded configs script" + def configs = loadSandboxedScript("vars/configs.groovy") when: - def wdkConf = WDKConfig.fromConfigMap(label, configMap, jenkinsScript) + def wdkConf = inSandboxClonedReturn { configs().unityWDK(label, configMap, jenkinsScript)} as Config then: wdkConf.pipelineTools != null wdkConf.checkArgs == expected.checkArgs - wdkConf.unityVersions == expected.unityVersions - wdkConf.buildLabel == expected.buildLabel + wdkConf.platforms == expected.platforms wdkConf.gradleArgs == expected.gradleArgs wdkConf.metadata == expected.metadata @@ -38,12 +47,14 @@ class WDKConfigSpec extends Specification { } @Unroll - def "fails to create valid WDKConfig object if config map has null or empty unityVersions list"() { + def "fails to create valid WDK Config object if config map has null or empty unityVersions list"() { given: "a null or empty configuration map" + and: "loaded configs script" + def configs = loadSandboxedScript("vars/configs.groovy") when: - WDKConfig.fromConfigMap("any", [unityVersions: unityVersions], new FakeJenkinsObject([:])) + inSandbox { configs().unityWDK("any", [unityVersions: unityVersions], new FakeJenkinsObject([:])) } then: - def e = thrown(IllegalArgumentException) + def e = thrown(Exception) e.message == "Please provide at least one unity version." where: @@ -52,22 +63,21 @@ class WDKConfigSpec extends Specification { def configFor(List plats, String label, String sonarToken, boolean refreshDependencies, boolean showStackTrace, String logLevel) { def metadata = JenkinsMetadata.fromScript(jenkinsScript) - def unityVersions = platsFor(plats, label) + def platforms = platsFor(plats, label) def baseConfig = new BaseConfig(jenkinsScript, PipelineConventions.standard.mergeWithConfigMap([:]), metadata, GradleArgs.fromConfigMap([refreshDependencies: refreshDependencies, showStackTrace: showStackTrace, logLevel: logLevel]), DockerArgs.fromConfigMap([:]), CheckArgs.fromConfigMap(jenkinsScript, metadata, [sonarToken: sonarToken])) - return new WDKConfig(unityVersions, baseConfig, label) + return new Config(baseConfig, platforms) } def platsFor(List unityVersionObj, String buildLabel) { return unityVersionObj.withIndex().collect { Object it, int index -> def buildVersion = BuildVersion.parse(it) - def platform = Platform.forWDK(buildVersion, buildLabel, [:], index == 0) - return new UnityVersionPlatform(platform, buildVersion) + Platform.forWDK(buildVersion, buildLabel, [:], index == 0) } } } diff --git a/test/groovy/tools/DeclarativeJenkinsSpec.groovy b/test/groovy/tools/DeclarativeJenkinsSpec.groovy index aafd41b0..dfa98e8b 100644 --- a/test/groovy/tools/DeclarativeJenkinsSpec.groovy +++ b/test/groovy/tools/DeclarativeJenkinsSpec.groovy @@ -9,6 +9,7 @@ import com.lesfurets.jenkins.unit.declarative.WhenDeclaration import org.apache.commons.lang3.ClassUtils import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.GenericWhitelist import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist +import org.powermock.classloading.DeepCloner import spock.lang.Shared import spock.lang.Specification import tools.sandbox.PackageWhitelist @@ -62,6 +63,7 @@ abstract class DeclarativeJenkinsSpec extends Specification { helper?.callStack?.clear() environment.wipe() credentials.wipe() + currentDir = null } def getUsedEnvironments() { @@ -124,9 +126,12 @@ abstract class DeclarativeJenkinsSpec extends Specification { } registerAllowedMethod("dir", [String, Closure]) { String targetDir, cls -> def previousDir = this.currentDir - this.currentDir = targetDir - cls() - this.currentDir = previousDir + try { + this.currentDir = [previousDir, targetDir].findAll {it != null }.join("/") + cls() + } finally { + this.currentDir = previousDir + } } } } @@ -142,16 +147,26 @@ abstract class DeclarativeJenkinsSpec extends Specification { /** * Loads a script and the javaLibCheck and publish side scripts inside the sandbox. * @param path - path to the script to be loaded. + * @param path - path to the script to be loaded. * @param varBindingOps - convenience closure to execute operations over the binding * object that will be passed to scripts - * @param reloadSideScripts - if the side scripts should be loaded, defaults to true. + * @param loadSideScripts - if the side scripts should be loaded, defaults to true. * @return Script object representing the loaded script */ - Script loadSandboxedScript(String path, Closure varBindingOps={}, boolean reloadSideScripts = true) { + Script loadSandboxedScript(String path, Closure varBindingOps={}, boolean loadSideScripts = true) { varBindingOps.setDelegate(binding.variables) varBindingOps(binding.variables) - if(reloadSideScripts) { - registerSideScript("vars/javaLibs.groovy", binding) + if(loadSideScripts) { + inSandbox { + registerSideScript("vars/configs.groovy", binding) + registerSideScript("vars/gradleWrapper.groovy", binding) + registerSideScript("vars/parallelize.groovy", binding) + registerSideScript("vars/staticAnalysis.groovy", binding) + registerSideScript("vars/javaCheckTemplate.groovy", binding) + registerSideScript("vars/wdkCheckTemplate.groovy", binding) + registerSideScript("vars/jsCheckTemplate.groovy", binding) + registerSideScript("vars/javaLibs.groovy", binding) + } } return helper.loadSandboxedScript(path, binding) } @@ -201,25 +216,40 @@ abstract class DeclarativeJenkinsSpec extends Specification { /** * Runs a closure in sandbox environment. - * - * IMPORTANT: - * Avoid object exchange from in to outside the sandbox environment (ie. parameters pass or returns). + *

+ * IMPORTANT:
+ * Object exchange from in to outside the sandbox environment (ie. parameters pass or returns), is non-trivial. * As the sandbox environment has its own ClassLoader, trying to use any 'non-basic' * (ie. not loaded by the bootstrap ClassLoader) JVM object will fail. * If you are having trouble with inane ClassNotFoundException(s), this is probably the case. - * + *

* Example of safe classes are Map, String, Object, and primitives, but there are many others besides these. - * - * If you absolutely have to pass a custom object, you can try serializing the it, passing the bytes, - * and then deserialize it on the other side, for instance, using ObjectOutputStream/ObjectInputStream. - * + *

+ * If you have to pass in a custom object, `helper.cloneToSandbox` will generate a clone of that object in the sandbox classLoader, + * which then can be used inside the sandbox. + * For returns, you can use inSandboxClonedReturn or `helper.cloneTo`, to generate a clone of a sandboxed object in a non-sandbox environment. + *
* @param cls function to run into the sandbox - * @return the return of the cls closure + * @return the direct return of the cls closure */ protected T inSandbox(Closure cls) { return helper.inSandbox(cls) } + /** + * Runs a closure in sandbox environment. + * Limitations from inSandbox(Closure) still applies, except for the return object, + * which is transfered to this class classLoader. + * + * @param cls function to run into the sandbox + * @return cloned return of the cls closure, transplanted to this class' class loader. + */ + protected T inSandboxClonedReturn(Closure cls) { + def sandboxedReturn = inSandbox { cls() } + return helper.cloneTo(sandboxedReturn, this.class.classLoader) + } + + String[] getShGradleCalls() { return calls["sh"].collect { it.args[0]["script"].toString() }.findAll { it.contains("gradlew") diff --git a/test/groovy/tools/sandbox/GroovyClassLoaderWhitelist.groovy b/test/groovy/tools/sandbox/GroovyClassLoaderWhitelist.groovy new file mode 100644 index 00000000..8e738980 --- /dev/null +++ b/test/groovy/tools/sandbox/GroovyClassLoaderWhitelist.groovy @@ -0,0 +1,59 @@ +package tools.sandbox + +import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist + +import java.lang.reflect.Constructor +import java.lang.reflect.Field +import java.lang.reflect.Method + +//Based on ClassLoaderWhitelist from jenkins' security plugin +class GroovyClassLoaderWhitelist extends Whitelist { + + private final ClassLoader scriptLoader; + + public GroovyClassLoaderWhitelist(ClassLoader scriptLoader) { + this.scriptLoader = scriptLoader; + } + + private boolean permitClassLoader(ClassLoader classLoader) { + //Groovy uses these inner loaders to load scripts tru GSE. + // This isn't a problem in jenkins itself for some reason, but it is in our tests, + // so we have to find the nearest non-innerloader parent. + if(classLoader!= null && classLoader instanceof GroovyClassLoader.InnerLoader) { + return permitClassLoader(classLoader.parent) + } + return classLoader == scriptLoader + } + + private boolean permit(Class declaringClass) { + return permitClassLoader(declaringClass.classLoader) + } + + @Override boolean permitsMethod(Method method, Object receiver, Object[] args) { + return permit(method.getDeclaringClass()); + } + + @Override boolean permitsConstructor(Constructor constructor, Object[] args) { + return permit(constructor.getDeclaringClass()); + } + + @Override boolean permitsStaticMethod(Method method, Object[] args) { + return permit(method.getDeclaringClass()); + } + + @Override boolean permitsFieldGet(Field field, Object receiver) { + return permit(field.getDeclaringClass()); + } + + @Override boolean permitsFieldSet(Field field, Object receiver, Object value) { + return permit(field.getDeclaringClass()); + } + + @Override boolean permitsStaticFieldGet(Field field) { + return permit(field.getDeclaringClass()); + } + + @Override boolean permitsStaticFieldSet(Field field, Object value) { + return permit(field.getDeclaringClass()); + } +} diff --git a/test/groovy/tools/sandbox/SandboxPipelineTestHelper.groovy b/test/groovy/tools/sandbox/SandboxPipelineTestHelper.groovy index c1fc0c56..224beeb2 100644 --- a/test/groovy/tools/sandbox/SandboxPipelineTestHelper.groovy +++ b/test/groovy/tools/sandbox/SandboxPipelineTestHelper.groovy @@ -3,9 +3,9 @@ package tools.sandbox import com.lesfurets.jenkins.unit.PipelineTestHelper import org.codehaus.groovy.control.CompilerConfiguration import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist -import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.ClassLoaderWhitelist import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist +import org.powermock.classloading.DeepCloner /** * Pipeline version test that integrates its own Groovy compilations shenanigans with the groovy sandbox ones. @@ -30,7 +30,7 @@ class SandboxPipelineTestHelper extends PipelineTestHelper { private Whitelist createWhitelist() { return new ProxyWhitelist(whitelist, - new ClassLoaderWhitelist(gse.groovyClassLoader), + new GroovyClassLoaderWhitelist(gse.groovyClassLoader), new MethodSignatureWhitelist(allowedMethodCallbacks.keySet())) } @@ -69,6 +69,30 @@ class SandboxPipelineTestHelper extends PipelineTestHelper { scope.close() } } + /** + * Uses powermock's org.powermock.classloading.DeepCloner to deep clone a object to the target classloader. + * Assumes that a identical class is loaded in the target classloader. + * + * @param object - Object to be cloned + * @param cl - Target classloader. Defaults to the classloader used to load this class. + * @return cloned object in the target classloader. + */ + public T cloneTo(T object, ClassLoader cl = this.class.classLoader) { + def deepCloner = new DeepCloner(cl) //clones given object in classLoader + return deepCloner.clone(object) + } + + /** + * Deep clones a object to the sandbox classloader. + * Assumes that a identical class is loaded in the sandbox classloader. + * + * @param object - Object to be cloned + * @param cl - Target classloader. Defaults to the classloader used to load this class. + * @return cloned object in the target classloader. + */ + public T cloneToSandbox(T object) { + return cloneTo(object, gse.groovyClassLoader) + } } \ No newline at end of file diff --git a/test/resources/scripts/checkTest.groovy b/test/resources/scripts/checkTest.groovy index 89664de3..0842cf45 100644 --- a/test/resources/scripts/checkTest.groovy +++ b/test/resources/scripts/checkTest.groovy @@ -1,29 +1,36 @@ package scripts -import net.wooga.jenkins.pipeline.config.JavaConfig -import net.wooga.jenkins.pipeline.config.WDKConfig +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.config.Config def javaCoverage(Map configMap) { - def config = JavaConfig.fromConfigMap(configMap, this) - def checks = config.pipelineTools.checks.forJavaPipelines() - return checks.gradleCheckWithCoverage(config.platforms, config.checkArgs, config.conventions) + def config = configs().java(configMap, this) as Config + Step checkTemplate = javaCheckTemplate(config.pipelineTools.checks, config.checkArgs, config.conventions) + return parallelize(checkTemplate, config.platforms, config.conventions.javaParallelPrefix) } def parallel(Map configMap, Closure checkCls, Closure analysisCls) { - def config = JavaConfig.fromConfigMap(configMap, this) - def checks = config.pipelineTools.checks.forJavaPipelines() - return checks.parallel(config.platforms, checkCls, analysisCls, config.conventions) + def config = configs().java(configMap, this) as Config + def checkStep = config.pipelineTools.checks.enclosedSimpleCheck( + new Step(checkCls).wrappedBy(config.checkArgs.testWrapper), + new Step(analysisCls).wrappedBy(config.checkArgs.analysisWrapper), + { ex -> throw ex },{ }) + return parallelize(checkStep, config.platforms, config.conventions.javaParallelPrefix) } - def wdkCoverage(String buildLabel, Map configMap, String releaseType, String releaseScope) { - def config = WDKConfig.fromConfigMap(buildLabel, configMap, this) - def checks = config.pipelineTools.checks.forWDKPipelines() - return checks.wdkCoverage(config.unityVersions, releaseType, releaseScope, config.checkArgs, config.conventions) + def config = configs().unityWDK(buildLabel, configMap, this) as Config + Step checkTemplate = wdkCheckTemplate(config.pipelineTools.checks, config.checkArgs, + releaseType, releaseScope, config.conventions) + return parallelize(checkTemplate, config.platforms, config.conventions.wdkParallelPrefix) } def simpleWDK(String buildLabel, Map configMap, Closure checkCls, Closure analysisCls) { - def config = WDKConfig.fromConfigMap(buildLabel, configMap, this) - def checks = config.pipelineTools.checks.forWDKPipelines() - return checks.parallel(config.unityVersions, checkCls, analysisCls) + def config = configs().unityWDK(buildLabel, configMap, this) as Config + def checkStep = config.pipelineTools.checks.enclosedSimpleCheck( + new Step(checkCls).wrappedBy(config.checkArgs.testWrapper), + new Step(analysisCls).wrappedBy(config.checkArgs.analysisWrapper), + { ex -> throw ex }, + { }) + return parallelize(checkStep, config.platforms, config.conventions.wdkParallelPrefix) } diff --git a/vars/buildGradlePlugin.groovy b/vars/buildGradlePlugin.groovy index 9461b6ae..a22ef006 100644 --- a/vars/buildGradlePlugin.groovy +++ b/vars/buildGradlePlugin.groovy @@ -1,6 +1,6 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.config.JavaConfig +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -11,7 +11,7 @@ import net.wooga.jenkins.pipeline.config.JavaConfig def call(Map configMap = [:]) { javaLibs(configMap) { stages -> - stages.publish = { stage, params, JavaConfig config -> + stages.publish = { stage, params, Config config -> stage.action = { def publisher = config.pipelineTools.createPublishers(params.RELEASE_TYPE, params.RELEASE_SCOPE) publisher.gradlePlugin('gradle.publish.key', 'gradle.publish.secret') diff --git a/vars/buildJavaLibrary.groovy b/vars/buildJavaLibrary.groovy index b7d1c7b8..ab723a32 100644 --- a/vars/buildJavaLibrary.groovy +++ b/vars/buildJavaLibrary.groovy @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.config.JavaConfig +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -10,7 +10,7 @@ import net.wooga.jenkins.pipeline.config.JavaConfig def call(Map configMap = [:]) { javaLibs(configMap) { stages -> - stages.publish = { stage, params, JavaConfig config -> + stages.publish = { stage, params, Config config -> stage.action = { def publisher = config.pipelineTools.createPublishers(params.RELEASE_TYPE, params.RELEASE_SCOPE) publisher.bintray('bintray.publish') diff --git a/vars/buildJavaLibraryOSSRH.groovy b/vars/buildJavaLibraryOSSRH.groovy index a8f5977b..8174d11f 100644 --- a/vars/buildJavaLibraryOSSRH.groovy +++ b/vars/buildJavaLibraryOSSRH.groovy @@ -1,6 +1,6 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.config.JavaConfig +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -11,7 +11,7 @@ import net.wooga.jenkins.pipeline.config.JavaConfig def call(Map configMap = [:]) { javaLibs(configMap) { stages -> - stages.publish = { stage, params, JavaConfig config -> + stages.publish = { stage, params, Config config -> stage.action = { def publisher = config.pipelineTools.createPublishers(params.RELEASE_TYPE, params.RELEASE_SCOPE) publisher.ossrh('ossrh.publish', 'ossrh.signing.key', diff --git a/vars/buildPrivateGradlePlugin.groovy b/vars/buildPrivateGradlePlugin.groovy index 5d8974ef..0eae15ed 100644 --- a/vars/buildPrivateGradlePlugin.groovy +++ b/vars/buildPrivateGradlePlugin.groovy @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.config.JavaConfig +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -10,7 +10,7 @@ import net.wooga.jenkins.pipeline.config.JavaConfig def call(Map configMap = [:]) { javaLibs(configMap) { stages -> - stages.publish = { stage, params, JavaConfig config -> + stages.publish = { stage, params, Config config -> stage.when = { true } //always stage.action = { def publisher = config.pipelineTools.createPublishers(params.RELEASE_TYPE, params.RELEASE_SCOPE) diff --git a/vars/buildPrivateJavaLibrary.groovy b/vars/buildPrivateJavaLibrary.groovy index 5d8974ef..0eae15ed 100644 --- a/vars/buildPrivateJavaLibrary.groovy +++ b/vars/buildPrivateJavaLibrary.groovy @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.config.JavaConfig +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -10,7 +10,7 @@ import net.wooga.jenkins.pipeline.config.JavaConfig def call(Map configMap = [:]) { javaLibs(configMap) { stages -> - stages.publish = { stage, params, JavaConfig config -> + stages.publish = { stage, params, Config config -> stage.when = { true } //always stage.action = { def publisher = config.pipelineTools.createPublishers(params.RELEASE_TYPE, params.RELEASE_SCOPE) diff --git a/vars/buildWDKAutoSwitch.groovy b/vars/buildWDKAutoSwitch.groovy index 327148c9..8066cee1 100644 --- a/vars/buildWDKAutoSwitch.groovy +++ b/vars/buildWDKAutoSwitch.groovy @@ -1,9 +1,7 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.assemble.Assemblers -import net.wooga.jenkins.pipeline.check.Checks -import net.wooga.jenkins.pipeline.config.WDKConfig -import net.wooga.jenkins.pipeline.model.Gradle -import net.wooga.jenkins.pipeline.setup.Setups +import net.wooga.jenkins.pipeline.BuildVersion +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -13,12 +11,13 @@ import net.wooga.jenkins.pipeline.setup.Setups //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// def call(Map configMap = [ unityVersions:[] ]) { + def buildLabel = "macos" configMap.logLevel = configMap.get("logLevel", params.LOG_LEVEL?: env.LOG_LEVEL as String) configMap.showStackTrace = configMap.get("showStackTrace", params.STACK_TRACE as Boolean) configMap.refreshDependencies = configMap.get("refreshDependencies", params.REFRESH_DEPENDENCIES as Boolean) configMap.clearWs = configMap.get("clearWs", params.CLEAR_WS as boolean) - def config = WDKConfig.fromConfigMap("macos", configMap, this) - def mainPlatform = config.unityVersions[0].platform + def config = configs().unityWDK(buildLabel, configMap, this) as Config + def mainPlatform = config.platforms[0] // We can only configure static pipelines atm. // To test multiple unity versions we use a script block with a parallel stages inside. @@ -51,7 +50,7 @@ def call(Map configMap = [ unityVersions:[] ]) { stage('setup') { agent { - label "atlas && $config.buildLabel" + label "atlas && $buildLabel" } steps { @@ -86,7 +85,7 @@ def call(Map configMap = [ unityVersions:[] ]) { parallel { stage('assemble package') { agent { - label "atlas && $config.buildLabel" + label "atlas && $buildLabel" } steps { @@ -124,11 +123,10 @@ def call(Map configMap = [ unityVersions:[] ]) { steps { script { - def checks = config.pipelineTools.checks.forWDKPipelines() - def stepsForParallel = checks.wdkCoverage(config.unityVersions, - params.RELEASE_TYPE as String, params.RELEASE_SCOPE as String, - config.checkArgs, config.conventions) - parallel stepsForParallel + Step checkTemplate = wdkCheckTemplate(config.pipelineTools.checks, config.checkArgs, + params.RELEASE_TYPE as String, params.RELEASE_SCOPE as String, config.conventions) + def checksForParallel = parallelize(checkTemplate, config.platforms, config.conventions.wdkParallelPrefix) + parallel checksForParallel } } } @@ -137,7 +135,7 @@ def call(Map configMap = [ unityVersions:[] ]) { stage('publish') { agent { - label "atlas && $config.buildLabel" + label "atlas && $buildLabel" } environment { @@ -154,7 +152,9 @@ def call(Map configMap = [ unityVersions:[] ]) { script { def applicationsHome = env.APPLICATIONS_HOME?: "" def unityExecPackagePath = env.UNITY_EXEC_PACKAGE_PATH?: "" - def unityPath = "${applicationsHome}/${config.unityVersions[0].stepDescription}/${unityExecPackagePath}" + def mainBuildVersion = BuildVersion.parse(configMap.unityVersions[0]).toLabel() + def unityDir = "Unity-${mainBuildVersion}" + def unityPath = "${applicationsHome}/${unityDir}/${unityExecPackagePath}".toString() def publisher = config.pipelineTools.createPublishers(params.RELEASE_TYPE, params.RELEASE_SCOPE) publisher.unityArtifactoryPaket(unityPath, 'artifactory_publish') diff --git a/vars/buildWDKJS.groovy b/vars/buildWDKJS.groovy index d48b0131..0238384c 100644 --- a/vars/buildWDKJS.groovy +++ b/vars/buildWDKJS.groovy @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -import net.wooga.jenkins.pipeline.config.JSConfig +import net.wooga.jenkins.pipeline.check.steps.Step //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -14,7 +14,7 @@ def call(Map configMap = [:]) { configMap.showStackTrace = configMap.get("showStackTrace", params.STACK_TRACE as Boolean) configMap.refreshDependencies = configMap.get("refreshDependencies", params.REFRESH_DEPENDENCIES as Boolean) configMap.clearWs = configMap.get("clearWs", params.CLEAR_WS as boolean) - def config = JSConfig.fromConfigMap(configMap, this) + def config = configs().jsWDK(configMap, this) def platforms = config.platforms def mainPlatform = platforms[0] @@ -65,11 +65,9 @@ def call(Map configMap = [:]) { steps { script { - withEnv(["COVERALLS_PARALLEL=true"]) { - def jsChecks = config.pipelineTools.checks.forJSPipelines() - def checksForParallel = jsChecks.gradleCheckWithCoverage(config.platforms, config.checkArgs, config.conventions) - parallel checksForParallel - } + Step checkTemplate = jsCheckTemplate(config.pipelineTools.checks, config.checkArgs, config.conventions) + def checksForParallel = parallelize(checkTemplate, config.platforms, config.conventions.javaParallelPrefix) + parallel checksForParallel } } post { diff --git a/vars/checkCreator.groovy b/vars/checkCreator.groovy new file mode 100644 index 00000000..e776e0cc --- /dev/null +++ b/vars/checkCreator.groovy @@ -0,0 +1,13 @@ +import net.wooga.jenkins.pipeline.check.Checks +import net.wooga.jenkins.pipeline.check.EnclosureCreator +import net.wooga.jenkins.pipeline.check.Enclosures +import net.wooga.jenkins.pipeline.config.DockerArgs +import net.wooga.jenkins.pipeline.model.Docker + + +def call(Map dockerArgs = [:]) { + def docker = Docker.fromJenkins(this, DockerArgs.fromConfigMap(dockerArgs)) + def enclosureCreator = new EnclosureCreator(this, BUILD_NUMBER) //from jenkins env + def enclosures = new Enclosures(this, docker, enclosureCreator) + return new Checks(this, enclosures) +} diff --git a/vars/configs.groovy b/vars/configs.groovy new file mode 100644 index 00000000..67b9e1cf --- /dev/null +++ b/vars/configs.groovy @@ -0,0 +1,70 @@ +import net.wooga.jenkins.pipeline.BuildVersion +import net.wooga.jenkins.pipeline.config.BaseConfig +import net.wooga.jenkins.pipeline.config.Config +import net.wooga.jenkins.pipeline.config.Platform + + + +def call(String type="") { + def configs = [ + java: this.&forJava, + unityWDK: this.&forUnityWDKs, + jsWDK: this.&forJSWDKs + ] + return configs[type]?: configs +} + +static List collectPlatform(Map configMap, List platformNames) { + def index = 0 + return platformNames.collect { String platformName -> + def platform = Platform.forJava(platformName, configMap, index == 0) + index++ + return platform + } +} + +Config forJava(Map config, Object jenkinsScript) { + config.platforms = config.platforms ?: ['macos','windows'] + def platforms = collectPlatform(config, config.platforms as List) + def baseConfig = BaseConfig.fromConfigMap(config, jenkinsScript) + + return new Config(baseConfig, platforms) +} + +List collectJSWDKPlatforms(Map configMap, List platformNames) { + def index = 0 + return platformNames.collect { String platformName -> + def platform = Platform.forJS(platformName, configMap, index == 0) + index++ + return platform + } +} + +Config forJSWDKs(Map configMap, Object jenkinsScript) { + configMap.platforms = configMap.platforms ?: ['macos'] + def baseConfig = BaseConfig.fromConfigMap(configMap, jenkinsScript) + def platforms = collectJSWDKPlatforms(configMap, configMap.platforms as List) + + return new Config(baseConfig, platforms) +} + +List collectWDKPlatforms(List unityVerObjs, String buildLabel, Map configMap) { + def index = 0 + return unityVerObjs.collect { Object unityVersionObj -> + def buildVersion = BuildVersion.parse(unityVersionObj) + def platform = Platform.forWDK(buildVersion, buildLabel, configMap, index == 0) + index++ + return platform + } +} + +Config forUnityWDKs(String buildLabel, Map configMap, Object jenkinsScript) { + configMap.unityVersions = configMap.unityVersions ?: [] + def platforms = collectWDKPlatforms(configMap.unityVersions as List, buildLabel, configMap) + if (platforms.isEmpty()) { + error("Please provide at least one unity version.") + } + + def baseConfig = BaseConfig.fromConfigMap(configMap, jenkinsScript) + return new Config(baseConfig, platforms) +} \ No newline at end of file diff --git a/vars/gradleWrapper.groovy b/vars/gradleWrapper.groovy index 88a9dfca..0c7c53d8 100644 --- a/vars/gradleWrapper.groovy +++ b/vars/gradleWrapper.groovy @@ -1,9 +1,12 @@ #!/usr/bin/env groovy +import net.wooga.jenkins.pipeline.config.GradleArgs import net.wooga.jenkins.pipeline.model.Gradle /** * execute gradlew or gradlew.bat based on current os */ + + def call(String command, Boolean returnStatus = false, Boolean returnStdout = false) { def gradle = Gradle.fromJenkins(this, params.LOG_LEVEL?: env.LOG_LEVEL as String, diff --git a/vars/javaCheckTemplate.groovy b/vars/javaCheckTemplate.groovy new file mode 100644 index 00000000..6af6c23f --- /dev/null +++ b/vars/javaCheckTemplate.groovy @@ -0,0 +1,70 @@ +import net.wooga.jenkins.pipeline.check.Checks +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.check.steps.StepWrapper +import net.wooga.jenkins.pipeline.config.CheckArgs +import net.wooga.jenkins.pipeline.config.PipelineConfig +import net.wooga.jenkins.pipeline.config.PipelineConventions +import net.wooga.jenkins.pipeline.config.Platform + + +//TODO: reduce. exposed. surface. Maybe leave just configuration/vars files as public API? +// maybe leave only (config) and (map) as supported api, and hide the rest behind a closure or something, +// it would still be accessible, but not encouraged. +// maybe just fuck the map api? All of its parameters can be changed thru the config object anyway. +// centering everything around the config object is very convenient but is very framework-y. +// The best is to have the config object as an option to sort parameters, but avoid bringing it deep into the app. +// Config is not deep in, but its children are, stuff like PipelineConventions and CheckArgs. Not as bad, but not ideal. +// on other hand, being able to use stuff outside the Config environment will be very useful for 3rd parties (ie games) +// they can implement the PipelineConfig interface as well, but yeah. + +Step call(PipelineConfig config) { + call(config.pipelineTools.checks, config.checkArgs, config.conventions) +} + +Step call(Checks checks, CheckArgs checkArgs, PipelineConventions conventions) { + createCheckTemplate(checks, conventions.checkTask, checkArgs.testWrapper, + conventions.jacocoTask, checkArgs.analysisWrapper, + conventions.sonarqubeTask, checkArgs.sonarqube.token, checkArgs.metadata.branchName, + conventions.coverallsTask, checkArgs.coveralls.token) +} + +//def call(CheckCreator checkCreator, Map args = [ +// checkTask : PipelineConventions.standard.checkTask, +// checkWrapper : Step.identityWrapper, +// jacocoTask : PipelineConventions.standard.jacocoTask, +// analysisWrapper: Step.identityWrapper, +// sonarqubeTask : PipelineConventions.standard.sonarqubeTask, +// branchName : env?.BRANCH_NAME, //from jenkins environment, null if not present +// coverallsTask : PipelineConventions.standard.coverallsTask]) { +// createCheckTemplate(checkCreator, args.checkTask?.toString(), args.checkWrapper as StepWrapper, +// args.jacocoTask?.toString(), args.analysisWrapper as StepWrapper, +// args.sonarqubeTask?.toString(), args.sonarqubeToken?.toString(), args.branchName?.toString(), +// args.coverallsTask?.toString(), args.coverallsToken?.toString()) +//} + +private Step createCheckTemplate(Checks checkCreator, String checkTask, StepWrapper checkWrapper, + String jacocoTask, StepWrapper analysisWrapper, + String sonarqubeTask, String sonarqubeToken, String branchName, + String coverallsTask, String coverallsToken) { + def testStep = { Platform platform -> + gradleWrapper checkTask + } + def analysisStep = { Platform platform -> + gradleWrapper jacocoTask + staticAnalysis().composite sonarqubeTask: sonarqubeTask, sonarqubeToken: sonarqubeToken, + branchName: branchName, coverallsTask: coverallsTask, coverallsToken: coverallsToken + } + def finallyAction = { + junit allowEmptyResults: true, testResults: "**/build/test-results/**/*.xml" + } + + def checkStep = checkCreator.enclosedSimpleCheck( + new Step(testStep).wrappedBy(checkWrapper as StepWrapper), + new Step(analysisStep).wrappedBy(analysisWrapper as StepWrapper), + { ex -> throw ex }, finallyAction) + return checkStep.wrappedBy { check, platform -> + withEnv(["COVERALLS_PARALLEL=true"]) { + check(platform) + } + } +} diff --git a/vars/javaLibs.groovy b/vars/javaLibs.groovy index 2f201b8d..30cfd940 100644 --- a/vars/javaLibs.groovy +++ b/vars/javaLibs.groovy @@ -1,6 +1,7 @@ #!/usr/bin/env groovy +import net.wooga.jenkins.pipeline.check.steps.Step import net.wooga.jenkins.pipeline.stages.Stages -import net.wooga.jenkins.pipeline.config.JavaConfig +import net.wooga.jenkins.pipeline.config.Config //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // @@ -15,7 +16,7 @@ def call(Map configMap = [:], Closure stepsConfigCls) { configMap.showStackTrace = configMap.get("showStackTrace", params.STACK_TRACE as Boolean) configMap.refreshDependencies = configMap.get("refreshDependencies", params.REFRESH_DEPENDENCIES as Boolean) configMap.clearWs = configMap.get("clearWs", params.CLEAR_WS as boolean) - def config = JavaConfig.fromConfigMap(configMap, this) + def config = configs().java(configMap, this) as Config def actions = Stages.fromClosure(params as Map, config, stepsConfigCls) def mainPlatform = config.mainPlatform.name @@ -63,11 +64,9 @@ def call(Map configMap = [:], Closure stepsConfigCls) { steps { script { actions.check.runActionOrElse { - withEnv(["COVERALLS_PARALLEL=true"]) { - def javaChecks = config.pipelineTools.checks.forJavaPipelines() - def checksForParallel = javaChecks.gradleCheckWithCoverage(config.platforms, config.checkArgs, config.conventions) - parallel checksForParallel - } + Step checkTemplate = javaCheckTemplate(config.pipelineTools.checks, config.checkArgs, config.conventions) + def checksForParallel = parallelize(checkTemplate, config.platforms, config.conventions.javaParallelPrefix) + parallel checksForParallel } } } diff --git a/vars/jsCheckTemplate.groovy b/vars/jsCheckTemplate.groovy new file mode 100644 index 00000000..b42a4fc8 --- /dev/null +++ b/vars/jsCheckTemplate.groovy @@ -0,0 +1,14 @@ +import net.wooga.jenkins.pipeline.check.Checks +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.config.CheckArgs +import net.wooga.jenkins.pipeline.config.PipelineConfig +import net.wooga.jenkins.pipeline.config.PipelineConventions + + +Step call(PipelineConfig config) { + javaCheckTemplate(config) +} + +Step call(Checks checks, CheckArgs checkArgs, PipelineConventions conventions) { + javaCheckTemplate(checks, checkArgs, conventions) +} diff --git a/vars/parallelize.groovy b/vars/parallelize.groovy new file mode 100644 index 00000000..c6bb1383 --- /dev/null +++ b/vars/parallelize.groovy @@ -0,0 +1,14 @@ +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.config.Platform + +Map call(Step checkTemplate, Platform[] platforms, String parallelPrefix) { + return call(checkTemplate.stepFunction.&call, platforms, parallelPrefix) +} + +Map call(Closure checkTemplate, Platform[] platforms, String parallelPrefix) { + return platforms.collectEntries { platform -> + String parallelStepName = "${parallelPrefix}${platform.name}" + def check = checkTemplate.clone() + return [(parallelStepName): { check(platform) }] + } +} diff --git a/vars/staticAnalysis.groovy b/vars/staticAnalysis.groovy new file mode 100644 index 00000000..fa7c8fe6 --- /dev/null +++ b/vars/staticAnalysis.groovy @@ -0,0 +1,58 @@ +#!/usr/bin/env groovy +import net.wooga.jenkins.pipeline.check.Coveralls +import net.wooga.jenkins.pipeline.check.Sonarqube +import net.wooga.jenkins.pipeline.config.PipelineConventions + +def call() { + return [ //look mom I can do JS + composite: this.&composite, + sonarqube: this.&sonarqube, + coveralls: this.&coveralls + ] +} + + +def composite(Map args = [ + sonarqubeTask: PipelineConventions.standard.sonarqubeTask, + branchName : BRANCH_NAME, //from jenkins environment + coverallsTask: PipelineConventions.standard.coverallsTask +]) { + compositeStaticAnalysis(args.sonarqubeTask?.toString(), + args.sonarqubeToken?.toString(), + args.branchName?.toString(), + args.coverallsTask?.toString(), + args.coverallsToken?.toString() + ) +} + +def composite(Sonarqube sonarqube, Coveralls coveralls, String branchName, PipelineConventions conventions) { + compositeStaticAnalysis(conventions.sonarqubeTask, sonarqube.token, branchName, conventions.coverallsTask, coveralls.token) +} + +private def compositeStaticAnalysis(String sonarqubeTask, String sonarqubeToken, String branchName, String coverallsTask, String coverallsToken) { + if (sonarqubeToken) { + sonarqube(sonarqubeTask, sonarqubeToken, branchName.trim()) + } + if (coverallsToken) { + coveralls(coverallsTask, coverallsToken) + } +} + +def sonarqube(String task, String token, String branchName) { + gradleWrapper "${task} -Dsonar.login=${token} -Pgithub.branch.name=${branchName}" +} + +def coveralls(String task, String token) { + withEnv(["COVERALLS_REPO_TOKEN=${token}"]) { + gradleWrapper task + publishHTML([ + allowMissing : true, + alwaysLinkToLastBuild: true, + keepAll : true, + reportDir : 'build/reports/jacoco/test/html', + reportFiles : 'index.html', + reportName : "Coverage ${it}", + reportTitles : '' + ]) + } +} diff --git a/vars/wdkCheckTemplate.groovy b/vars/wdkCheckTemplate.groovy new file mode 100644 index 00000000..83adec91 --- /dev/null +++ b/vars/wdkCheckTemplate.groovy @@ -0,0 +1,34 @@ +import net.wooga.jenkins.pipeline.check.Checks +import net.wooga.jenkins.pipeline.check.steps.Step +import net.wooga.jenkins.pipeline.check.steps.StepWrapper +import net.wooga.jenkins.pipeline.config.CheckArgs +import net.wooga.jenkins.pipeline.config.PipelineConfig +import net.wooga.jenkins.pipeline.config.PipelineConventions +import net.wooga.jenkins.pipeline.config.Platform + + +Step call(PipelineConfig config, String releaseType, String releaseScope) { + call(config.pipelineTools.checks, config.checkArgs, releaseType, releaseScope, config.conventions) +} + +Step call(Checks checkCreator, CheckArgs checkArgs, String releaseType, String releaseScope, PipelineConventions conventions) { + def testStep = { Platform platform -> + unstash conventions.wdkSetupStashId + gradleWrapper "-Prelease.stage=${releaseType.trim()} -Prelease.scope=${releaseScope.trim()} ${conventions.checkTask}" + } + def analysisStep = { Platform platform -> + def branchName = checkArgs.metadata.isPR() ? null : checkArgs.metadata.branchName + staticAnalysis().sonarqube conventions.sonarqubeTask, checkArgs.sonarqube.token, branchName + publishCoverage adapters: [istanbulCoberturaAdapter(conventions.wdkCoberturaFile)], + sourceFileResolver: sourceFiles('STORE_LAST_BUILD') + } + def finallyAction = { + nunit failIfNoResults: false, testResultsPattern: '**/build/reports/unity/test*/*.xml' + archiveArtifacts artifacts: '**/build/logs/**/*.log', allowEmptyArchive: true + archiveArtifacts artifacts: '**/build/reports/unity/**/*.xml', allowEmptyArchive: true + } + return checkCreator.enclosedSimpleCheck( + new Step(testStep).wrappedBy(checkArgs.testWrapper as StepWrapper), + new Step(analysisStep).wrappedBy(checkArgs.analysisWrapper as StepWrapper), + { Throwable e -> throw e }, finallyAction) +}