I use a shared lib method in the background, that handles a global environment variable with a JSON map as data. This way, it's persistent over Jenkins controller restarts and it can store all kinds of objects:
pipelineStore.groovy
def getAll() {
return jsonUtils.fromJson(env.PIPELINE_STORE)
}
def put(key, value) {
def tmpMap = jsonUtils.fromJson(env.PIPELINE_STORE)
if (!tmpMap) {
tmpMap = [:]
}
def result = tmpMap.put(key, value)
env.PIPELINE_STORE = jsonUtils.toJson(tmpMap)
return result
}
def get(key) {
return jsonUtils.fromJson(env.PIPELINE_STORE)[key]
}
def remove(key) {
tmpMap = jsonUtils.fromJson(env.PIPELINE_STORE)
def result = tmpMap.remove(key)
env.PIPELINE_STORE = jsonUtils.toJson(tmpMap)
return result
}
jsonUtils.groovy
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
import groovy.json.JsonSlurperClassic
def toJson(object) {
return new JsonBuilder(object).toPrettyString()
}
def fromJson(text) {
if (!text) {
return ''
}
try {
return new JsonSlurper().parseText(text)
} catch (Exception e) {
return new JsonSlurperClassic().parseText(text)
}
}
And in my pipelines I can use it across stages like
stages {
stage ('1') {
steps {
script {
pipelineStore.put("key_1", [name: "value_1", version: 23])
}
}
}
stage ('2') {
steps {
script {
def value = pipelineStore.get("key_1")
}
}
}
}
post {
unsuccessful {
node ('master') {
script {
pipelineStore.getAll().each { key, value ->
// e.g. cleanup operations
}
}
}
}
}
for more information on shared libraries on Jenkins see https://www.jenkins.io/doc/book/pipeline/shared-libraries/