Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-60115

NullPointerException in Declarative Pipeline after upgrade from 1.3.9 to 1.4.0

    XMLWordPrintable

Details

    Description

      After the upgrade to 1.4.0, my builds started to fail with a NullPointerException when parsing the model. Here's the full stack trace:

       

      java.lang.NullPointerExceptionava.lang.NullPointerException at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStep.withOrWithoutParens(ModelASTStep.java:111) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStep.toGroovy(ModelASTStep.java:100) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTElement.toGroovy(ModelASTElement.java:142) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTBranch.toGroovy(ModelASTBranch.java:41) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStage.toGroovy(ModelASTStage.java:115) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTElement.toGroovy(ModelASTElement.java:142) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTElement.toGroovyBlock(ModelASTElement.java:213) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTStages.toGroovy(ModelASTStages.java:44) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTElement.toGroovy(ModelASTElement.java:122) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTPipelineDef.toGroovy(ModelASTPipelineDef.java:58) at org.jenkinsci.plugins.pipeline.modeldefinition.ast.ModelASTMarkerInterface$toGroovy.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.RuntimeASTTransformer$Wrapper.<init>(RuntimeASTTransformer.groovy:1077) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83) at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:255) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.RuntimeASTTransformer.transform(RuntimeASTTransformer.groovy:90) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.RuntimeASTTransformer$transform.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:141) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.ModelParser.parsePipelineStep(ModelParser.groovy:269) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:384) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.ModelParser$_parse_closure5.doCall(ModelParser.groovy:168) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325) at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022) at groovy.lang.Closure.call(Closure.java:414) at groovy.lang.Closure.call(Closure.java:430) at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3202) at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3172) at org.codehaus.groovy.runtime.dgm$67.invoke(Unknown Source) at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274) at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.ModelParser.parse(ModelParser.groovy:167) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.ModelParser$parse.callCurrent(Unknown Source) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.ModelParser.parse(ModelParser.groovy:124) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.ModelParser.parse(ModelParser.groovy) at org.jenkinsci.plugins.pipeline.modeldefinition.parser.GroovyShellDecoratorImpl$1.call(GroovyShellDecoratorImpl.java:78) at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1065)Caused: BUG! exception in phase 'semantic analysis' in source unit '/var/jenkins_home/jobs/BroadleafCommerce/jobs/CartOperationServices/branches/PR-134/builds/6/libs/broadleaf-pipeline-library/vars/mavenBuild.groovy' unexpected NullpointerException at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1070) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:603) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:254) at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:761) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:718) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787) at java.lang.ClassLoader.loadClass(ClassLoader.java:411) at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$TimingLoader.loadClass(CpsGroovyShell.java:170) at java.lang.ClassLoader.loadClass(ClassLoader.java:411) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:775) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at org.jboss.marshalling.AbstractClassResolver.loadClass(AbstractClassResolver.java:123) at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:104) at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:1022) at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1355) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:220) at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1853) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1767) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1715) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1715) at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1395) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:220) at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1853) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1767) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1715) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1715) at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1395) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:220) at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1853) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1767) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1715) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1715) at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1395) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) at org.jboss.marshalling.river.BlockUnmarshaller.readObject(BlockUnmarshaller.java:149) at org.jboss.marshalling.river.BlockUnmarshaller.readObject(BlockUnmarshaller.java:135) at org.jboss.marshalling.MarshallerObjectInputStream.readObjectOverride(MarshallerObjectInputStream.java:53) at org.jboss.marshalling.river.RiverObjectInputStream.readObjectOverride(RiverObjectInputStream.java:307) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:425) at java.util.HashMap.readObject(HashMap.java:1412) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.marshalling.reflect.JDKSpecific$SerMethods.callReadObject(JDKSpecific.java:179) at org.jboss.marshalling.reflect.SerializableClass.callReadObject(SerializableClass.java:212) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1746) at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1395) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:220) at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1853) at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1767) at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1395) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272) at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:205) at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41) at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverReader$SandboxedUnmarshaller.lambda$readObject$0(RiverReader.java:250) at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:237) at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverReader$SandboxedUnmarshaller.sandbox(RiverReader.java:237) at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverReader$SandboxedUnmarshaller.readObject(RiverReader.java:250) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution$2.onSuccess(CpsFlowExecution.java:783) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution$2.onSuccess(CpsFlowExecution.java:776) at org.jenkinsci.plugins.workflow.support.concurrent.Futures$1.run(Futures.java:150) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:134) at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:170) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture.access$000(ChainingListenableFuture.java:33) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture$1.run(ChainingListenableFuture.java:196) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.add(ExecutionList.java:105) at com.google.common.util.concurrent.AbstractFuture.addListener(AbstractFuture.java:155) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture.run(ChainingListenableFuture.java:189) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:134) at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:170) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture.access$000(ChainingListenableFuture.java:33) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture$1.run(ChainingListenableFuture.java:196) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.add(ExecutionList.java:105) at com.google.common.util.concurrent.AbstractFuture.addListener(AbstractFuture.java:155) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture.run(ChainingListenableFuture.java:189) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:134) at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:170) at org.jenkinsci.plugins.workflow.support.concurrent.ListFuture.setOneValue(ListFuture.java:158) at org.jenkinsci.plugins.workflow.support.concurrent.ListFuture.access$000(ListFuture.java:40) at org.jenkinsci.plugins.workflow.support.concurrent.ListFuture$2.run(ListFuture.java:107) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:134) at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:170) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture.access$000(ChainingListenableFuture.java:33) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture$1.run(ChainingListenableFuture.java:196) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.add(ExecutionList.java:105) at com.google.common.util.concurrent.AbstractFuture.addListener(AbstractFuture.java:155) at org.jenkinsci.plugins.workflow.support.concurrent.ChainingListenableFuture.run(ChainingListenableFuture.java:189) at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:253) at com.google.common.util.concurrent.ExecutionList$RunnableExecutorPair.execute(ExecutionList.java:149) at com.google.common.util.concurrent.ExecutionList.execute(ExecutionList.java:134) at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:170) at org.jenkinsci.plugins.workflow.support.pickles.TryRepeatedly.access$500(TryRepeatedly.java:48) at org.jenkinsci.plugins.workflow.support.pickles.TryRepeatedly$1.run(TryRepeatedly.java:112) at jenkins.security.ImpersonatingScheduledExecutorService$1.run(ImpersonatingScheduledExecutorService.java:58) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)Caused: java.io.IOException: Failed to load build state at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution$3.onSuccess(CpsFlowExecution.java:855) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution$3.onSuccess(CpsFlowExecution.java:853) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution$4$1.run(CpsFlowExecution.java:907) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$1.run(CpsVmExecutorService.java:38) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 

       

      I suppose I could post my entire shared library pipeline, but I need to strip some things out of it. I would rather self-diagnose but I do not know how. Is there any other logging or anything I could turn on that would tell me which class in my library is the problematic one?

      Attachments

        Issue Links

          Activity

            bitwiseman Liam Newman added a comment -

            Thanks! Yes, I would appreciate a look at your pipeline.  It shouldn't be all the code in your shared library, just the whatever is in in your pipline directive.
             
            I see where the error is being thrown, but it doesn't help me understand the underlying cause.
             

            bitwiseman Liam Newman added a comment - Thanks! Yes, I would appreciate a look at your pipeline.  It shouldn't be all the code in your shared library, just the whatever is in in your pipline directive.   I see where the error is being thrown, but it doesn't help me understand the underlying cause.  

            Thanks for the response, sorry for the cloak and dagger.

            My pipeline script is a bit unique in that this is what my Jenkinsfile looks like in all my projects:

            mavenBuild{ } 

            And then I have a shared library that has a `vars/mavenBuild.groovy` that has the declarative pipeline in it. Pasted below.

            import com.broadleafcommerce.jenkins.DependentProject
            import com.broadleafcommerce.jenkins.DependentProjectDiscoverer
            import com.broadleafcommerce.jenkins.ReleaseUtils
            import com.broadleafcommerce.jenkins.SonarUtils
            import com.broadleafcommerce.jenkins.Utils
            
            def call(body) {
              // evaluate the body block, and collect configuration into the object
              def pipelineParams = [:]
              body.resolveStrategy = Closure.DELEGATE_FIRST
              body.delegate = pipelineParams
              body()
            
              println "Building with Jenkinsfile settings: $pipelineParams"
              Utils.abortPreviousUpstreamBuilds(currentBuild)
            
              def extraBuildProfiles = pipelineParams.extraBuildProfiles ?: ''
              def extraDeployProfiles = pipelineParams.extraDeployProfiles ?: ''
              def sonarAnalysis = pipelineParams.sonarAnalysis ?: ''
              def javadocsDirectories = pipelineParams.javadocsDirectories ?: []
              def referenceDocsDirectories = pipelineParams.referenceDocsDirectories ?: []
              def agentLabel = pipelineParams.agentLabel ?: 'maven-jdk8'
              def requiresNpmrc = pipelineParams.requiresNpmrc != null ? pipelineParams.requiresNpmrc : false
              def forceDeploy = pipelineParams.forceDeploy != null ? pipelineParams.forceDeploy : false
            
              def mainBranch = Utils.isMainBranch(this)
              def shouldDeploy = mainBranch || forceDeploy || params.FORCE_DEPLOY || params.IS_RELEASE_BUILD
              def mavenVersion = '3.6'
            
              pipeline {
            
                parameters {
                  string(
                    // Disabling the classpathURLCheck is for a bug in OpenJDK that prevents Surefire from running properly
                    // see https://stackoverflow.com/questions/53010200/maven-surefire-could-not-find-forkedbooter-class/53016532
            
                    defaultValue: '-Xmx2048m -Djdk.net.URLClassPath.disableClassPathURLCheck=true',
                    name: 'MAVEN_OPTS',
                    description: 'JVM parameters passed to Maven as MAVEN_OPTS'
                  )
                  string(
                    // Disabling the classpathURLCheck is for a bug in OpenJDK that prevents Surefire from running properly
                    // see https://stackoverflow.com/questions/53010200/maven-surefire-could-not-find-forkedbooter-class/53016532
            
                    defaultValue: '',
                    name: 'MAVEN_BUILD_ARGS',
                    description: 'Arguments passed directly to the Maven process (like -X, -e, any extra -D arguments etc). Only applies to the build phase on CI builds, applies to _both_ release:prepare and release:perform on release builds'
                  )
                  booleanParam(
                    defaultValue: false,
                    name: 'IS_RELEASE_BUILD',
                    description: 'Indicate whether or not this build should be treated as a release'
                      +' (GA, milestone, etc) If you would like to validate the versions that are autogenerated,'
                      +' use VALIDATE_RELEASE_VERSION_DEFAULTS. Otherwise, current release version (in conjunction'
                      +' with the RELEASE_BUILD_QUALIFIER) and next SNAPSHOT version will be autodetected.'
                  )
                  string(
                    defaultValue: 'GA',
                    name: 'RELEASE_BUILD_QUALIFIER',
                    description: 'Only used in release builds for next and current version calculations'
                  )
                  booleanParam(
                    defaultValue: false,
                    name: 'FORCE_DEPLOY',
                    description: 'By default, non-release builds only auto-deploy to Nexus from branches named develop-x.y.'
                      +' This executes a deploy regardles of what the branch is with whatever version is currently in the pom.'
                  )
                  booleanParam(
                    defaultValue: false,
                    name: 'VALIDATE_RELEASE_VERSION_DEFAULTS',
                    description: 'Only used when IS_RELEASE_BUILD is true. Pauses the job and waits for the user to confirm whether or not the autodiscovered version numbers are correct for the release.'
                  )
                }
            
                agent {
                  label agentLabel
                }
            
                options {
                  buildDiscarder(logRotator(artifactDaysToKeepStr: '1', artifactNumToKeepStr: '', daysToKeepStr: '', numToKeepStr: '15'))
                }
            
                stages {
            
                  /**
                   * Common to all build types
                   */
                  stage('Project Validation') {
                    steps {
                      script {
                        def lastCommit = sh returnStdout: true, script: 'git log -1 --pretty=%B'
                        if (lastCommit.contains("[maven-release-plugin] prepare release")) {
                            println 'Maven Release build detected, aborting build'
                            currentBuild.result = 'ABORTED'
                            return
                        }
            
                        // <scm> must match this repository
                        def pom = readMavenPom()
                        def scm = pom.scm
                        if (!scm) {
                          error("An <scm> section is required in your pom.xml")
                        }
                        if (!scm.connection.startsWith('scm:git:')) {
                          error("Only git repositories are supported. Ensure that the <scm> section in your pom.xml starts with scm:git:<url>")
                        }
                        if (!scm.connection.equalsIgnoreCase("scm:git:${env.GIT_URL}")) {
                          error("The <scm> section in pom.xml must match the repository being cloned. Expected: scm:git:${env.GIT_URL} but found ${scm.connection}")
                        }
            
                        // mvnw must exist and be executable
                        def mvnwUnixExists = fileExists 'mvnw'
                        def mvnwWindowsExists = fileExists 'mvnw.cmd'
                        if (!mvnwUnixExists || !mvnwWindowsExists) {
                          error("There must be both mvnw and mvnw.cmd executables at the root of the repository. This can be initialized by executing 'mvn -N io.takari:maven:wrapper'")
                        }
                        def mvnwUnixFile = sh returnStdout: true, script: 'ls -l mvnw'.trim()
                        def mvnwWindowsFile = sh returnStdout: true, script: 'ls -l mvnw.cmd'.trim()
                        if (!mvnwUnixFile.contains('x') || !mvnwWindowsFile.contains('x')) {
                          error("The mvnw or mvnw.cmd file is not executable. Run 'chmod +x mvnw mvnw.cmd' in the root of the repository and push the changes to resolve this")
                        }
            
                        if (Utils.isMainBranch(this) && forceDeploy) {
                          error("The currently executing branch is already a main branch and will be deployed. Remove the forceDeploy parameter from the Jenkinsfile")
                        }
                      }
                    }
                  }
            
                  /**
                   *
                   *  RELEASE STAGES
                   *
                   */
                  stage('Prepare release version') {
                    when { expression { return params.IS_RELEASE_BUILD } }
                    steps {
                      milestone null
                      withMaven(maven: "$mavenVersion", mavenSettingsConfig: 'mvn-settings.xml', mavenOpts: params.MAVEN_OPTS) {
                        script {
                          def requestedQualifier = params.RELEASE_BUILD_QUALIFIER
                          def pom = readMavenPom()
            
                          // Set as environment variables to propagate to next stages
                          env.release = ReleaseUtils.nextReleaseVersion(pom.version, requestedQualifier)
                          env.nextSnapshot = ReleaseUtils.incrementVersion(pom.version, requestedQualifier)
                          env.nextRelease = ReleaseUtils.nextReleaseVersion(release, requestedQualifier)
                          env.tag = pom.artifactId + '-' + release
            
                          if (params.VALIDATE_RELEASE_VERSION_DEFAULTS) {
                              def userInput
                              timeout(time: 90, unit: 'SECONDS') {
                                userInput = input(
                                  id: 'userInput', message: 'Release Properties', parameters: [
                                  [$class: 'TextParameterDefinition', defaultValue: release, description: 'The version you are about to release', name: 'release'],
                                  [$class: 'TextParameterDefinition', defaultValue: nextSnapshot, description: 'The next development version that the pom will be changed to after completing the release', name: 'nextSnapshot'],
                                  [$class: 'TextParameterDefinition', defaultValue: tag, description: 'The tag that will show up in the repository for the release', name: 'tag'],
                                  [$class: 'TextParameterDefinition', defaultValue: nextRelease, description: 'What the next release wil be after this one. Used to update milestones and labels automatically on GitHub', name: 'nextRelease']
                                ])
                              }
            
                              env.release = userInput['release']
                              env.nextSnapshot = userInput['nextSnapshot']
                              env.nextRelease = userInput['nextRelease']
                              env.tag = userInput['tag']
                          }
            
                          // this makes commits, need to configure Git
                          sh 'git config --replace-all user.email email@domain.com'
                          sh 'git config --replace-all user.name Git User'
            
                          try {
                            sh "mvn release:prepare ${params.MAVEN_BUILD_ARGS} -DpushChanges=false -Dresume=false -Dtag=$env.tag -DreleaseVersion=$env.release -DdevelopmentVersion=$env.nextSnapshot -DpreparationGoals='clean initialize spotless:apply verify' -DcompletionGoals='spotless:apply' -Darguments='-Ddockerfile.tag=$env.release'"
                          } catch(Exception e) {
                            // only rollback if we have .releaseBackup files
                            def backupFiles = findFiles glob: '*.releaseBackup'
                            if (backupFiles.length > 0) {
                              sh "mvn -DpushChanges=false release:rollback -Dtag=$env.tag -DreleaseVersion=$env.release -DdevelopmentVersion=$env.nextSnapshot"
                              error("The release has failed but it is possible that the repository has already been tagged. The pom has been reverted back but you must manually verify the tag is removed from the repository before retrying to release")
                            }
                            throw e
                          }
                        }
                      }
                    }
                  }
            
                  stage("Perform and deploy the release") {
                    when { expression { return params.IS_RELEASE_BUILD } }
                    steps {
                      milestone null
                      withMaven(maven: "$mavenVersion", mavenSettingsConfig: 'mvn-settings.xml', mavenOpts: params.MAVEN_OPTS) {
                        // GPG signing obtained originally from https://wiki.eclipse.org/EE4J_Build#Example_pipeline_build_job_.28for_GPG_signing.29
                        withCredentials([file(credentialsId: 'gpg', variable: 'KEYRING')]) {
                          sh 'gpg --batch --import "${KEYRING}"'
                          sh 'for fpr in $(gpg --list-keys --with-colons  | awk -F: \'/fpr:/ {print $10}\' | sort -u); do echo -e "5\ny\n" |  gpg --batch --command-fd 0 --expert --edit-key ${fpr} trust; done'
            
                          // Perform the Maven deploy
                          sshagent(['github-ssh']) {
                            // using -DlocalCheckout makes it so we can prevent a push until the very very end
                            sh "mvn release:perform ${params.MAVEN_BUILD_ARGS} -Dresume=false -DlocalCheckout=true -Dtag=$env.tag -DreleaseVersion=$env.release -DdevelopmentVersion=$env.nextSnapshot"
                          }
                        }
                      }
            
                      // now that the build is on the Nexus, push the changes to the Git repo
                      sshagent(['github-ssh']) {
                        sh "git push origin $env.BRANCH_NAME"
                        sh 'git push origin --tags'
                      }
                    }
                  }
            
                  /**
                   *
                   *  CI STAGES
                   *
                   */
                  stage('Build') {
                    when { expression { return !params.IS_RELEASE_BUILD } }
                    steps {
                      script {
                        milestone null
            
                        withMaven(maven: "$mavenVersion", mavenSettingsConfig: 'mvn-settings.xml', mavenOpts: params.MAVEN_OPTS) {
                          withCredentials([string(credentialsId: 'GITHUB_AUTH_TOKEN', variable: 'TOKEN')]) {
                            def mavenExec = { Map args ->
                              sh "mvn -U clean verify $args.buildArgs -Pcoverage -Pjavadocs $args.additionalProfiles"
                            }
                            def build = requiresNpmrc ? { buildArgs -> withNPM(npmrcConfig: 'npmrc') { mavenExec(buildArgs) }} : mavenExec
            
                            def pom = readMavenPom()
                            DependentProject[] dependentProjects = new DependentProjectDiscoverer().getDependentProjects(pom, TOKEN, this)
                            if (dependentProjects) {
                              String modifiedArtifactRoot = mavenDependentBuild(dependentProjects, pom.artifactId, build, [buildArgs: params.MAVEN_BUILD_ARGS, additionalProfiles: extraBuildProfiles])
                              env.CURRENT_ARTIFACT_ROOT = modifiedArtifactRoot
                              env.DEPENDENT_CHECKOUT = true
                            } else {
                              build([buildArgs: params.MAVEN_BUILD_ARGS, additionalProfiles: extraBuildProfiles])
                              env.CURRENT_ARTIFACT_ROOT = '.'
                            }
                          }
                        }
                      }
                    }
                  }
            
                  stage('Sonar Analysis') {
                    when { expression { return sonarAnalysis != 'skip' && !params.IS_RELEASE_BUILD } }
                    steps {
                      milestone null
                      withMaven(maven: "$mavenVersion", mavenSettingsConfig: 'mvn-settings.xml', mavenOpts: params.MAVEN_OPTS) {
                        withSonarQubeEnv('Sonar') {
                          sh "mvn -f $env.CURRENT_ARTIFACT_ROOT sonar:sonar ${SonarUtils.getAnalysisParameters(this).join(' ')}"
                        }
                      }
                      // It's possible that the analysis succeeds _very_ quickly before it even gets to the next phase
                      // Need to sleep in-between https://community.sonarsource.com/t/need-a-sleep-between-withsonarqubeenv-and-waitforqualitygate-or-it-spins-in-in-progress/2265/8
                      echo 'Sleeping for 5 seconds so Sonar can complete the background task'
                      sleep(5)
                    }
                  }
            
                  stage('Sonar Quality Gate') {
                    when { expression { return sonarAnalysis != 'skip' && !params.IS_RELEASE_BUILD } }
                    steps {
                      milestone null
                      timeout(time: 2, unit: 'MINUTES') {
                        waitForQualityGate abortPipeline: false
                      }
                    }
                  }
            
                  stage('Deploy artifact, sources, javadocs to Nexus') {
                    when { expression { return !params.IS_RELEASE_BUILD } }
                    steps {
                      script {
                        milestone null
                        // GPG signing obtained originally from https://wiki.eclipse.org/EE4J_Build#Example_pipeline_build_job_.28for_GPG_signing.29
                        withCredentials([file(credentialsId: 'gpg', variable: 'KEYRING')]) {
                          sh 'gpg --batch --import "${KEYRING}"'
                          sh 'for fpr in $(gpg --list-keys --with-colons  | awk -F: \'/fpr:/ {print $10}\' | sort -u); do echo -e "5\ny\n" |  gpg --batch --command-fd 0 --expert --edit-key ${fpr} trust; done'
            
                          withMaven(maven: "$mavenVersion", mavenSettingsConfig: 'mvn-settings.xml', mavenOpts: params.MAVEN_OPTS) {
            
                            def dockerTag = Utils.getDistTag(this, params.IS_RELEASE_BUILD)
            
                            // not a normal main branch, need to do some transformation
                            if (!Utils.isMainBranch(this)) {
                              def pom = readMavenPom()
                              def branchSpecificVersion = Utils.getBranchSpecificVersion(this, pom.version)
            
                              println "Transforming version from $pom.version to a branch-specific version $branchSpecificVersion"
                              sh "mvn -f $env.CURRENT_ARTIFACT_ROOT versions:set -DnewVersion=${branchSpecificVersion} -DgenerateBackupPoms"
                              dockerTag = "branch-${Utils.getSanitizedBranchName(this)}-latest-snapshot"
                            }
            
                            sh "mvn -f $env.CURRENT_ARTIFACT_ROOT -Danimal.sniffer.skip=true -DskipTests -DdeployAtEnd=true -Psources -Pjavadocs -Pdocs -Psign-artifacts -Ddockerfile.tag=${dockerTag} $extraDeployProfiles deploy"
                          }
                        }
                      }
                    }
                  }
            
                  /**
                   *
                   * Common final stages
                   *
                   */
                  stage('Upload Javadocs site') {
                    when { expression { return javadocsDirectories && shouldDeploy } }
                    steps {
                      milestone null
                      script {
                        def prefix = params.IS_RELEASE_BUILD ? 'target/checkout/' : ''
                        javadocsDirectories.each {
                          uploadDocsFile("${prefix}${it}/*-javadoc.jar", 'javadocs')
                        }
                      }
                    }
                  }
            
                  stage('Upload Reference docs site') {
                    when { expression { return referenceDocsDirectories && shouldDeploy } }
                    steps {
                      milestone null
                      script {
                        def prefix = params.IS_RELEASE_BUILD ? 'target/checkout/' : ''
                        referenceDocsDirectories.each {
                          uploadDocsFile("${prefix}${it}/*-reference.zip", 'docs')
                        }
                      }
                    }
                  }
                }
            
                post {
                  failure {
                    slackFailureNotification()
                  }
                  success {
                    slackSuccessNotification()
                    supersedeBranchCheck()
                  }
                }
              }
            }
            
            def uploadDocsFile(def file, def host) {
              withCredentials([
                sshUserPrivateKey(credentialsId: "docs-upload-ssh", keyFileVariable: 'keyfile')
              ]) {
                // ignore host checking
                sh "scp -i ${keyfile} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${file} jenkins@${host}:"
                sh "ssh -i ${keyfile} -t -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null jenkins@${host} './extractDocs.sh'"
              }
            }
             
            phillipuniverse Phillip Verheyden added a comment - Thanks for the response, sorry for the cloak and dagger. My pipeline script is a bit unique in that this is what my Jenkinsfile looks like in all my projects: mavenBuild{ } And then I have a shared library that has a `vars/mavenBuild.groovy` that has the declarative pipeline in it. Pasted below. import com.broadleafcommerce.jenkins.DependentProject import com.broadleafcommerce.jenkins.DependentProjectDiscoverer import com.broadleafcommerce.jenkins.ReleaseUtils import com.broadleafcommerce.jenkins.SonarUtils import com.broadleafcommerce.jenkins.Utils def call(body) { // evaluate the body block, and collect configuration into the object def pipelineParams = [:] body.resolveStrategy = Closure.DELEGATE_FIRST body.delegate = pipelineParams body() println "Building with Jenkinsfile settings: $pipelineParams" Utils.abortPreviousUpstreamBuilds(currentBuild) def extraBuildProfiles = pipelineParams.extraBuildProfiles ?: '' def extraDeployProfiles = pipelineParams.extraDeployProfiles ?: '' def sonarAnalysis = pipelineParams.sonarAnalysis ?: '' def javadocsDirectories = pipelineParams.javadocsDirectories ?: [] def referenceDocsDirectories = pipelineParams.referenceDocsDirectories ?: [] def agentLabel = pipelineParams.agentLabel ?: 'maven-jdk8' def requiresNpmrc = pipelineParams.requiresNpmrc != null ? pipelineParams.requiresNpmrc : false def forceDeploy = pipelineParams.forceDeploy != null ? pipelineParams.forceDeploy : false def mainBranch = Utils.isMainBranch( this ) def shouldDeploy = mainBranch || forceDeploy || params.FORCE_DEPLOY || params.IS_RELEASE_BUILD def mavenVersion = '3.6' pipeline { parameters { string( // Disabling the classpathURLCheck is for a bug in OpenJDK that prevents Surefire from running properly // see https://stackoverflow.com/questions/53010200/maven-surefire-could-not-find-forkedbooter- class/ 53016532 defaultValue: '-Xmx2048m -Djdk.net.URLClassPath.disableClassPathURLCheck= true ' , name: 'MAVEN_OPTS' , description: 'JVM parameters passed to Maven as MAVEN_OPTS' ) string( // Disabling the classpathURLCheck is for a bug in OpenJDK that prevents Surefire from running properly // see https://stackoverflow.com/questions/53010200/maven-surefire-could-not-find-forkedbooter- class/ 53016532 defaultValue: '', name: 'MAVEN_BUILD_ARGS' , description: 'Arguments passed directly to the Maven process (like -X, -e, any extra -D arguments etc). Only applies to the build phase on CI builds, applies to _both_ release:prepare and release:perform on release builds' ) booleanParam( defaultValue: false , name: 'IS_RELEASE_BUILD' , description: 'Indicate whether or not this build should be treated as a release' + ' (GA, milestone, etc) If you would like to validate the versions that are autogenerated,' + ' use VALIDATE_RELEASE_VERSION_DEFAULTS. Otherwise, current release version (in conjunction' + ' with the RELEASE_BUILD_QUALIFIER) and next SNAPSHOT version will be autodetected.' ) string( defaultValue: 'GA' , name: 'RELEASE_BUILD_QUALIFIER' , description: 'Only used in release builds for next and current version calculations' ) booleanParam( defaultValue: false , name: 'FORCE_DEPLOY' , description: 'By default , non-release builds only auto-deploy to Nexus from branches named develop-x.y.' + ' This executes a deploy regardles of what the branch is with whatever version is currently in the pom.' ) booleanParam( defaultValue: false , name: 'VALIDATE_RELEASE_VERSION_DEFAULTS' , description: 'Only used when IS_RELEASE_BUILD is true . Pauses the job and waits for the user to confirm whether or not the autodiscovered version numbers are correct for the release.' ) } agent { label agentLabel } options { buildDiscarder(logRotator(artifactDaysToKeepStr: '1' , artifactNumToKeepStr: '', daysToKeepStr: ' ', numToKeepStr: ' 15')) } stages { /** * Common to all build types */ stage( 'Project Validation' ) { steps { script { def lastCommit = sh returnStdout: true , script: 'git log -1 --pretty=%B' if (lastCommit.contains( "[maven-release-plugin] prepare release" )) { println 'Maven Release build detected, aborting build' currentBuild.result = 'ABORTED' return } // <scm> must match this repository def pom = readMavenPom() def scm = pom.scm if (!scm) { error( "An <scm> section is required in your pom.xml" ) } if (!scm.connection.startsWith( 'scm:git:' )) { error( "Only git repositories are supported. Ensure that the <scm> section in your pom.xml starts with scm:git:<url>" ) } if (!scm.connection.equalsIgnoreCase( "scm:git:${env.GIT_URL}" )) { error( "The <scm> section in pom.xml must match the repository being cloned. Expected: scm:git:${env.GIT_URL} but found ${scm.connection}" ) } // mvnw must exist and be executable def mvnwUnixExists = fileExists 'mvnw' def mvnwWindowsExists = fileExists 'mvnw.cmd' if (!mvnwUnixExists || !mvnwWindowsExists) { error( "There must be both mvnw and mvnw.cmd executables at the root of the repository. This can be initialized by executing 'mvn -N io.takari:maven:wrapper' " ) } def mvnwUnixFile = sh returnStdout: true , script: 'ls -l mvnw' .trim() def mvnwWindowsFile = sh returnStdout: true , script: 'ls -l mvnw.cmd' .trim() if (!mvnwUnixFile.contains( 'x' ) || !mvnwWindowsFile.contains( 'x' )) { error( "The mvnw or mvnw.cmd file is not executable. Run 'chmod +x mvnw mvnw.cmd' in the root of the repository and push the changes to resolve this " ) } if (Utils.isMainBranch( this ) && forceDeploy) { error( "The currently executing branch is already a main branch and will be deployed. Remove the forceDeploy parameter from the Jenkinsfile" ) } } } } /** * * RELEASE STAGES * */ stage( 'Prepare release version' ) { when { expression { return params.IS_RELEASE_BUILD } } steps { milestone null withMaven(maven: "$mavenVersion" , mavenSettingsConfig: 'mvn-settings.xml' , mavenOpts: params.MAVEN_OPTS) { script { def requestedQualifier = params.RELEASE_BUILD_QUALIFIER def pom = readMavenPom() // Set as environment variables to propagate to next stages env.release = ReleaseUtils.nextReleaseVersion(pom.version, requestedQualifier) env.nextSnapshot = ReleaseUtils.incrementVersion(pom.version, requestedQualifier) env.nextRelease = ReleaseUtils.nextReleaseVersion(release, requestedQualifier) env.tag = pom.artifactId + '-' + release if (params.VALIDATE_RELEASE_VERSION_DEFAULTS) { def userInput timeout(time: 90, unit: 'SECONDS' ) { userInput = input( id: 'userInput' , message: 'Release Properties' , parameters: [ [$class: 'TextParameterDefinition' , defaultValue: release, description: 'The version you are about to release' , name: 'release' ], [$class: 'TextParameterDefinition' , defaultValue: nextSnapshot, description: 'The next development version that the pom will be changed to after completing the release' , name: 'nextSnapshot' ], [$class: 'TextParameterDefinition' , defaultValue: tag, description: 'The tag that will show up in the repository for the release' , name: 'tag' ], [$class: 'TextParameterDefinition' , defaultValue: nextRelease, description: 'What the next release wil be after this one. Used to update milestones and labels automatically on GitHub' , name: 'nextRelease' ] ]) } env.release = userInput[ 'release' ] env.nextSnapshot = userInput[ 'nextSnapshot' ] env.nextRelease = userInput[ 'nextRelease' ] env.tag = userInput[ 'tag' ] } // this makes commits, need to configure Git sh 'git config --replace-all user.email email@domain.com' sh 'git config --replace-all user.name Git User' try { sh "mvn release:prepare ${params.MAVEN_BUILD_ARGS} -DpushChanges= false -Dresume= false -Dtag=$env.tag -DreleaseVersion=$env.release -DdevelopmentVersion=$env.nextSnapshot -DpreparationGoals= 'clean initialize spotless:apply verify' -DcompletionGoals= 'spotless:apply' -Darguments= '-Ddockerfile.tag=$env.release' " } catch (Exception e) { // only rollback if we have .releaseBackup files def backupFiles = findFiles glob: '*.releaseBackup' if (backupFiles.length > 0) { sh "mvn -DpushChanges= false release:rollback -Dtag=$env.tag -DreleaseVersion=$env.release -DdevelopmentVersion=$env.nextSnapshot" error( "The release has failed but it is possible that the repository has already been tagged. The pom has been reverted back but you must manually verify the tag is removed from the repository before retrying to release" ) } throw e } } } } } stage( "Perform and deploy the release" ) { when { expression { return params.IS_RELEASE_BUILD } } steps { milestone null withMaven(maven: "$mavenVersion" , mavenSettingsConfig: 'mvn-settings.xml' , mavenOpts: params.MAVEN_OPTS) { // GPG signing obtained originally from https://wiki.eclipse.org/EE4J_Build#Example_pipeline_build_job_.28for_GPG_signing.29 withCredentials([file(credentialsId: 'gpg' , variable: 'KEYRING' )]) { sh 'gpg --batch -- import "${KEYRING}" ' sh ' for fpr in $(gpg --list-keys --with-colons | awk -F: \' /fpr:/ {print $10}\ ' | sort -u); do echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key ${fpr} trust; done' // Perform the Maven deploy sshagent([ 'github-ssh' ]) { // using -DlocalCheckout makes it so we can prevent a push until the very very end sh "mvn release:perform ${params.MAVEN_BUILD_ARGS} -Dresume= false -DlocalCheckout= true -Dtag=$env.tag -DreleaseVersion=$env.release -DdevelopmentVersion=$env.nextSnapshot" } } } // now that the build is on the Nexus, push the changes to the Git repo sshagent([ 'github-ssh' ]) { sh "git push origin $env.BRANCH_NAME" sh 'git push origin --tags' } } } /** * * CI STAGES * */ stage( 'Build' ) { when { expression { return !params.IS_RELEASE_BUILD } } steps { script { milestone null withMaven(maven: "$mavenVersion" , mavenSettingsConfig: 'mvn-settings.xml' , mavenOpts: params.MAVEN_OPTS) { withCredentials([string(credentialsId: 'GITHUB_AUTH_TOKEN' , variable: 'TOKEN' )]) { def mavenExec = { Map args -> sh "mvn -U clean verify $args.buildArgs -Pcoverage -Pjavadocs $args.additionalProfiles" } def build = requiresNpmrc ? { buildArgs -> withNPM(npmrcConfig: 'npmrc' ) { mavenExec(buildArgs) }} : mavenExec def pom = readMavenPom() DependentProject[] dependentProjects = new DependentProjectDiscoverer().getDependentProjects(pom, TOKEN, this ) if (dependentProjects) { String modifiedArtifactRoot = mavenDependentBuild(dependentProjects, pom.artifactId, build, [buildArgs: params.MAVEN_BUILD_ARGS, additionalProfiles: extraBuildProfiles]) env.CURRENT_ARTIFACT_ROOT = modifiedArtifactRoot env.DEPENDENT_CHECKOUT = true } else { build([buildArgs: params.MAVEN_BUILD_ARGS, additionalProfiles: extraBuildProfiles]) env.CURRENT_ARTIFACT_ROOT = '.' } } } } } } stage( 'Sonar Analysis' ) { when { expression { return sonarAnalysis != 'skip' && !params.IS_RELEASE_BUILD } } steps { milestone null withMaven(maven: "$mavenVersion" , mavenSettingsConfig: 'mvn-settings.xml' , mavenOpts: params.MAVEN_OPTS) { withSonarQubeEnv( 'Sonar' ) { sh "mvn -f $env.CURRENT_ARTIFACT_ROOT sonar:sonar ${SonarUtils.getAnalysisParameters( this ).join( ' ' )}" } } // It's possible that the analysis succeeds _very_ quickly before it even gets to the next phase // Need to sleep in-between https://community.sonarsource.com/t/need-a-sleep-between-withsonarqubeenv-and-waitforqualitygate-or-it-spins-in-in-progress/2265/8 echo 'Sleeping for 5 seconds so Sonar can complete the background task' sleep(5) } } stage( 'Sonar Quality Gate' ) { when { expression { return sonarAnalysis != 'skip' && !params.IS_RELEASE_BUILD } } steps { milestone null timeout(time: 2, unit: 'MINUTES' ) { waitForQualityGate abortPipeline: false } } } stage( 'Deploy artifact, sources, javadocs to Nexus' ) { when { expression { return !params.IS_RELEASE_BUILD } } steps { script { milestone null // GPG signing obtained originally from https://wiki.eclipse.org/EE4J_Build#Example_pipeline_build_job_.28for_GPG_signing.29 withCredentials([file(credentialsId: 'gpg' , variable: 'KEYRING' )]) { sh 'gpg --batch -- import "${KEYRING}" ' sh ' for fpr in $(gpg --list-keys --with-colons | awk -F: \' /fpr:/ {print $10}\ ' | sort -u); do echo -e "5\ny\n" | gpg --batch --command-fd 0 --expert --edit-key ${fpr} trust; done' withMaven(maven: "$mavenVersion" , mavenSettingsConfig: 'mvn-settings.xml' , mavenOpts: params.MAVEN_OPTS) { def dockerTag = Utils.getDistTag( this , params.IS_RELEASE_BUILD) // not a normal main branch, need to do some transformation if (!Utils.isMainBranch( this )) { def pom = readMavenPom() def branchSpecificVersion = Utils.getBranchSpecificVersion( this , pom.version) println "Transforming version from $pom.version to a branch-specific version $branchSpecificVersion" sh "mvn -f $env.CURRENT_ARTIFACT_ROOT versions:set -DnewVersion=${branchSpecificVersion} -DgenerateBackupPoms" dockerTag = "branch-${Utils.getSanitizedBranchName( this )}-latest-snapshot" } sh "mvn -f $env.CURRENT_ARTIFACT_ROOT -Danimal.sniffer.skip= true -DskipTests -DdeployAtEnd= true -Psources -Pjavadocs -Pdocs -Psign-artifacts -Ddockerfile.tag=${dockerTag} $extraDeployProfiles deploy" } } } } } /** * * Common final stages * */ stage( 'Upload Javadocs site' ) { when { expression { return javadocsDirectories && shouldDeploy } } steps { milestone null script { def prefix = params.IS_RELEASE_BUILD ? 'target/checkout/' : '' javadocsDirectories.each { uploadDocsFile( "${prefix}${it}/*-javadoc.jar" , 'javadocs' ) } } } } stage( 'Upload Reference docs site' ) { when { expression { return referenceDocsDirectories && shouldDeploy } } steps { milestone null script { def prefix = params.IS_RELEASE_BUILD ? 'target/checkout/' : '' referenceDocsDirectories.each { uploadDocsFile( "${prefix}${it}/*-reference.zip" , 'docs' ) } } } } } post { failure { slackFailureNotification() } success { slackSuccessNotification() supersedeBranchCheck() } } } } def uploadDocsFile(def file, def host) { withCredentials([ sshUserPrivateKey(credentialsId: "docs-upload-ssh" , keyFileVariable: 'keyfile' ) ]) { // ignore host checking sh "scp -i ${keyfile} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/ null ${file} jenkins@${host}:" sh "ssh -i ${keyfile} -t -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/ null jenkins@${host} './extractDocs.sh' " } }
            bitwiseman Liam Newman added a comment -

            The issue is cause by literal "null" values in your pipeline text, so it probably due to the milestone null calls.

            Could you try this version of the plugin? https://repo.jenkins-ci.org/incrementals/org/jenkinsci/plugins/pipeline-model-api/1.5.0-beta2-rc1705.52ffd0571b96/
            It should stop the crash.

            I still need to see if I can create a test the reproduces the issue.

            bitwiseman Liam Newman added a comment - The issue is cause by literal " null " values in your pipeline text, so it probably due to the milestone null calls. Could you try this version of the plugin? https://repo.jenkins-ci.org/incrementals/org/jenkinsci/plugins/pipeline-model-api/1.5.0-beta2-rc1705.52ffd0571b96/ It should stop the crash. I still need to see if I can create a test the reproduces the issue.

            Yup the issue was the milestone null for sure. Threw in the version of the plugin you linked at that fixed it! Thanks!

            By the way, the reason I even did that in the first place was because of JENKINS-47729 because I didn't want to add an ordinal or name to my milestones.

            phillipuniverse Phillip Verheyden added a comment - Yup the issue was the  milestone null for sure. Threw in the version of the plugin you linked at that fixed it! Thanks! By the way, the reason I even did that in the first place was because of JENKINS-47729 because I didn't want to add an ordinal or name to my milestones.
            bitwiseman Liam Newman added a comment - Fixed by https://github.com/jenkinsci/pipeline-model-definition-plugin/pull/363

            People

              bitwiseman Liam Newman
              phillipuniverse Phillip Verheyden
              Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: