Jenkins File Environment variables - shell

I have the below Jenkins pipeline for my project where I am setting a variable COLLECTOR_TOKEN which will be set via shell script.
I want to handle a negative scenario where suppose if the shell script fails I send and exit code 1, which in return fails the entire pipeline (this is what we are expecting) but the issue is in the logs we cant see the proper error message, so it will hard to debug.
pipeline {
agent { label 'maven' }
options { timeout(time: 300, unit: 'MINUTES') }
environment {
def COLLECTOR_TOKEN = sh(script: "chmod -R 777 *; hello.sh moshin", returnStdout: true).trim()
}
}
Exception : We can just see the below exception.
I want to handle the below exception and throw proper message. how can we achieve it?
Error when executing always post condition:
org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Required context class hudson.FilePath is missing
Perhaps you forgot to surround the code with a step that provides this, such as: node
at org.jenkinsci.plugins.workflow.steps.StepDescriptor.checkContextAvailability(StepDescriptor.java:266)
at org.jenkinsci.plugins.workflow.cps.DSL.invokeStep(DSL.java:263)
at org.jenkinsci.plugins.workflow.cps.DSL.invokeMethod(DSL.java:179)
at org.jenkinsci.plugins.workflow.cps.CpsScript.invokeMethod(CpsScript.java:122)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:48)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at com.cloudbees.groovy.cps.sandbox.DefaultInvoker.methodCall(DefaultInvoker.java:20)
at stepFinalise.call(stepFinalise.groovy:3)
at WorkflowScript.run(WorkflowScript:56)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.delegateAndExecute(ModelInterpreter.groovy:137)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.runPostConditions(ModelInterpreter.groovy:756)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:395)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.catchRequiredContextForNode(ModelInterpreter.groovy:393)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.runPostConditions(ModelInterpreter.groovy:755)
at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods:2030)
at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods:2015)
at com.cloudbees.groovy.cps.CpsDefaultGroovyMethods.each(CpsDefaultGroovyMethods:2056)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.runPostConditions(ModelInterpreter.groovy:745)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.runPostConditions(ModelInterpreter.groovy)
at org.jenkinsci.plugins.pipeline.modeldefinition.ModelInterpreter.executePostBuild(ModelInterpreter.groovy:723)
at ___cps.transform___(Native Method)
at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:86)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83)
at jdk.internal.reflect.GeneratedMethodAccessor516.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:107)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83)
at jdk.internal.reflect.GeneratedMethodAccessor516.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:89)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83)
at jdk.internal.reflect.GeneratedMethodAccessor516.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:83)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:185)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:400)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:96)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:312)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:276)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
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.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)

I got the solution :
As I was using returnStdout with shell script and the result for that shell script was not always the correct output sometime I use to get some exception which was not getting handled in the Jenkins files. So I had to handle the exception of the shell script by sending a error message instead of exit 1. And then in pipeline stage step we had to validate whether we got the token or we got exception (based on the message we sent from shell script).
If exception then stop the build.
Below code is just for your reference.
moshin.sh file:
#!/bin/bash
if [[ $1 == "moshin" ]]; then
echo "moshin"
else
echo "not_moshin"
fi
Jenkins Pipeline:
pipeline {
agent { label 'maven' }
environment {
COLLECTOR_TOKEN = sh(script: "chmod -R 777 *; moshin.sh moshin" , returnStdout: true).trim()
COLLECTOR_TOKEN_1 = sh(script: "chmod -R 777 *; moshin.sh not_moshin" , returnStdout: true).trim()
}
stages {
stage('PASS') {
steps {
script {
if (env.COLLECTOR_TOKEN == "moshin") {
println "hello moshin"
} else {
println "Unable to fetch COLLECTOR_TOKEN"
currentBuild.result = 'FAILED'
sh "exit 1"
}
}
}
}
stage('FAIL') {
steps {
script {
if (env.COLLECTOR_TOKEN_1 == "moshin") {
println "hello moshin"
} else {
println "Unable to fetch COLLECTOR_TOKEN"
currentBuild.result = 'FAILED'
sh "exit 1"
}
}
}
}
}
}
Build output:
[Pipeline] }
[Pipeline] // stage
[Pipeline] withEnv
[Pipeline] {
[Pipeline] sh
+ chmod -R 777 Jenkinsfile moshin.sh
+ moshin.sh not_moshin
[Pipeline] sh
+ chmod -R 777 Jenkinsfile moshin.sh
+ moshin.sh moshin
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (PASS)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
hello moshin
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (FAIL)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Unable to fetch COLLECTOR_TOKEN
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: FAILURE

Related

Nullpointer exception after running kubectl and helm command in Jenkinsfile

I am trying to run kubernetes and helm command in the deploy step of the Jenkinsfile but I am facing Nullpointer exception. Below is my code:
stage ('Create and Deploy to k8s Dev Environment') {
//agent {label 'docker-maven-slave'}
options {
skipDefaultCheckout()
}
steps {
withCredentials([string(credentialsId: K8S_DEV_SECRET_ID)]) {
command """
kubectl apply --server=https://10.0.0.0:443 --insecure-skip-tls-verify=false --namespace: "dev-ns" -f -
helm template -f "portal-chart/deploy/values-dev.yaml" portal-chart
"""
}
}
Below are the logs:
[Pipeline] End of Pipeline
hudson.remoting.ProxyException: java.lang.NullPointerException
Caused: hudson.remoting.ProxyException: com.xxx.jenkins.pipeline.library.utils.dispatch.ShellCommandException: Exception calling shell command, 'kubectl apply ... ': null
at command.call(command.groovy:51)
I was able to resolve this. Below is the code:
stage ('Create and Deploy to k8s Dev Environment') {
//agent {label 'docker-maven-slave'}
options {
skipDefaultCheckout()
}
steps {
command """
kubectl apply --server=https://10.0.0.0:443 --insecure-skip-tls-verify=false --namespace: "dev-ns" -f -
helm template -f "portal-chart/deploy/values-dev.yaml" portal-chart
"""
}

Bad substitution when passing parameter to shell script in Jenkins

I'm attempting to pass value of a variable by setting the stdOut of a shell script.
However in The console of Jenkins displays of followings:
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Feature Segunda)
[Pipeline] echo
${params.Segunda}
[Pipeline] sh
/var/jenkins_home/workspace/pruebaParametrizada#tmp/durable-71aead85/script.sh: 1: /var/jenkins_home/workspace/pruebaParametrizada#tmp/durable-71aead85/script.sh: Bad substitution
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] echo
Building finished successfully
I use to escape the quotes, nothing works. I get a bad substitution error. I've also tried without double quotes.
If I hardcode in the shell script arguments, it runs fine.
pipeline {
agent any
parameters {
string(defaultValue: "", description: '', name: 'One')
string(defaultValue: "", description: '', name: 'Two')
}
stages {
stage('Git Checkout') {
steps {
git credentialsId: 'personal-github', url: 'https:xxx'
}
}
stage('Maven Compile') {
steps {
sh 'mvn clean compile'
}
}
stage('Test One') {
steps {
//ERROR
sh 'mvn test -Dcucumber.options="-t #${params.One}"'
//This Works
//sh 'mvn test -Dcucumber.options="-t #One"'
}
}
}
post {
always {
echo 'Building finished successfully'
cucumber failedFeaturesNumber: -1,
failedScenariosNumber: -1,
failedStepsNumber: -1,
fileIncludePattern: '**/*.json',
jsonReportDirectory: 'target/cucumber/',
pendingStepsNumber: -1,
reportTitle: 'test features',
skippedStepsNumber: -1,
sortingMethod: 'ALPHABETICAL',
undefinedStepsNumber: -1
}
}
}
I found the way to pass parameters as follows`
sh """mvn test -Dcucumber.options='-t #${params.One}'"""
Thanks to all, for responses.

Jenkins Shared Libraries: is it possible to pass arguments to shell scripts imported as 'libraryResource'?

I have the following setup:
(Stripped out) Jenkinsfile:
#Library('my-custom-library') _
pipeline {
agent any
stages {
stage('Example') {
steps {
printHello name: 'Jenkins'
}
}
}
}
my-custom-library/resources/com/org/scripts/print-hello.sh:
#!/bin/bash
echo "Hello, $1"
my-custom-library/vars/printHello.groovy:
def call(Map parameters = [:]) {
def printHelloScript = libraryResource 'com/org/scripts/print-hello.sh'
def name = parameters.name
//the following line gives me headaches
sh(printHelloScript(name))
}
I expect Hello, Jenkins, but it throws the following exception:
groovy.lang.MissingMethodException: No signature of method:
java.lang.String.call() is applicable for argument types:
(java.lang.String) values: [Jenkins]
Possible solutions: wait(), any(), wait(long),
split(java.lang.String), take(int), each(groovy.lang.Closure)
So, is it possible to do something like described above, without mixing Groovy and Bash code?
Yes, check out withEnv
The example they give looks like;
node {
withEnv(['MYTOOL_HOME=/usr/local/mytool']) {
sh '$MYTOOL_HOME/bin/start'
}
}
More applicable to you:
// resources/test.sh
echo "HI here we are - $PUPPY_DOH --"
// vars/test.groovy
def call() {
withEnv(['PUPPY_DOH=bobby']) {
sh(libraryResource('test.sh'))
}
}
Prints:
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] libraryResource
[Pipeline] sh
+ echo HI here we are - bobby --
HI here we are - bobby --
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
Using that, you can pass it in using a scoped named variable, something like
def call(Map parameters = [:]) {
def printHelloScript = libraryResource 'com/org/scripts/print-hello.sh'
def name = parameters.name
withEnv(['NAME=' + name]) { // This may not be 100% syntax here ;)
sh(printHelloScript)
}
// print-hello.sh
echo "Hello, $name"

Jenkins pipeline "java.io.NotSerializableException: hudson.model.User" when execute shell

Here is my pipeline code. Notice the function promoteBuild() is a fake one, it needs to execute shell blocks. Here I just let it echo a constant string.
pipeline {
agent none
stages {
stage("PromoteBuild") {
agent {
label "test_agent"
}
steps {
script {
mopName = "mop name"
try {
// Timeout in case to avoid running this forever
timeout(time: 30, unit: 'SECONDS') {
promoteMap = input id: 'promote', message: 'Choose bundled buildNumbers', ok: 'Promote?',
parameters: [
string(
defaultValue: mopName,
description: '',
name: 'MopName'),
],
submitter: "xxxx", submitterParameter: 'approver'
}
promoteBuild()
} catch (err) {
def user = err.getCauses()[0].getUser()
if ('SYSTEM' == user.toString()) { // SYSTEM means timeout.
//No response means the build is launched by timer, promote the first bundled-number
echo "Promote only. No following deployment"
promoteBuild()
currentBuild.result = 'SUCCESS'
} else {
//if user aborted this operation, do nothing and mark the build as aborted
currentBuild.result = 'ABORTED'
echo "This build was aborted by [${user}]"
}
}
}
}
}
}
def promoteBuild() {
sh """
echo "hello"
"""
}
The function promoteBuild works successfully in try block (when I respond to the input request) but fails in catch block (when it is timeout).
Below is the console output:
Input requested
Cancelling nested steps due to timeout
[Pipeline] }
[Pipeline] // timeout
[Pipeline] echo
Promote only. No following deployment
[Pipeline] sh
[testTmp] Running shell script
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] End of Pipeline
***java.io.NotSerializableException: hudson.model.User***
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
at java.util.HashMap.internalWriteEntries(HashMap.java:1777)
at java.util.HashMap.writeObject(HashMap.java:1354)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
at java.util.TreeMap.writeObject(TreeMap.java:2434)
at sun.reflect.GeneratedMethodAccessor421.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
I'm pretty sure it is not related with "User" because the build succeeded if I remove the shell invoking. Any hint?
See https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#user-content-serializing-local-variables
As such: any variable values used in your program should be numbers, strings, or other serializable types
Your problem is at this line:
def user = err.getCauses()[0].getUser()
The object returned is of type hudson.model.User, which is not serializable i.e. doesn't implement Serializable interface.
Since you're only interested in the user name anyway, you could instead do this:
def user = err.getCauses()[0].getUser().toString()
if ('SYSTEM' == user) {
This will work because String is serializable.
You might also want to find out the real reason for your Exception occurring in the first place - try logging it inside the catch block.
#Vasan's answer is the right solution. I just want to add why the behavior is different when you don't add the line promoteBuild() or you remove the shell invoke.
As stated in the doc,
Since pipelines must survive Jenkins restarts, the state of the running program is periodically saved to disk so it can be resumed later (saves occur after every step or in the middle of steps such as sh).
you can see that the step with sh invoking will trigger the pipeline state to be saved, and hence the serializing action, which then causes the java.io.NotSerializableException to be thrown.

List in place sorting in Jenkins Pipelines

I am trying to sort a list of objects in Jenkins pipelines. I'm getting different results running code below locally or within Jenkins:
pipeline {
agent any
stages {
stage('default'){
steps {
script {
#NonCPS
def nonCpsTest = {
def list = [
['CreationDate': '200'],
['CreationDate': '300'],
['CreationDate': '100'],
]
def rval = list.sort { it['CreationDate'] }
echo "Rval=$rval"
echo "List=$list"
}
nonCpsTest()
}
}
}
}
}
When I execute this script locally using groovy shell (groovysh) result is
groovy:000> list = [[ 'CreationDate':200 ], [ 'CreationDate':300 ], [ 'CreationDate':100 ]]
===> [[CreationDate:200], [CreationDate:300], [CreationDate:100]]
groovy:000> rval = list.sort { it['CreationDate'] }
===> [[CreationDate:100], [CreationDate:200], [CreationDate:300]]
groovy:000> list
===> [[CreationDate:100], [CreationDate:200], [CreationDate:300]]
groovy:000> list == rval
===> true
While on the Jenkins server I'm getting following
[Pipeline] {
[Pipeline] stage
[Pipeline] { (default)
[Pipeline] script
[Pipeline] {
[Pipeline] echo
Rval=300
[Pipeline] echo
List=[[CreationDate:200], [CreationDate:300], [CreationDate:100]]
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Is Jenkins workflow making list immutable in anyway, or overriding sort method, and if so, how to do in place list sorting within the Jenkins pipeline code?
the problem that you declared nonCpsTest as a variable and it references to closure, so #NonCPS does not work in this case
the following variant works fine:
#NonCPS
def nonCpsTest() {
def list = [
['CreationDate': '200'],
['CreationDate': '300'],
['CreationDate': '100'],
]
def rval = list.sort{ it['CreationDate'] }
echo "Rval=$rval"
echo "List=$list"
}
node{
nonCpsTest()
}

Resources