Is it possible to pass variable from steps to script in jenkinsfile - jenkins

I have one pipeline and I want to pass one Arraylist that I get from a groovy method into the script that is running in Master Jenkins.
stages {
stage('Get Tests Parameter') {
steps {
code = returnList()
script {
properties([
parameters([
[$class : 'CascadeChoiceParameter',
choiceType : 'PT_CHECKBOX',
description : 'Select a choice',
defaultValue : '',
filterLength : 1,
filterable : false,
name : 'Tests',
referencedParameters: 'role',
script : [$class : 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox : true,
script : 'return ["ERROR"]'
],
script : [
classpath: [],
sandbox : false,
script : code
]
]
]
])
])
}
}
}
}
...
def returnList() {
def stringList = []
def fileContent = readFile "/var/jenkins_home/example.txt"
for (line in fileContent.readLines()) {
stringList.add(line.split(",")[0] + ":selected");
}
return stringList
}
That stages are running in a slave, so I couldn't execute that method returnList() inside the script because the script is running in Master. So I'm trying to get returnList ArrayList to a variable and use that variable in the script part.
Is that possible?

If you want to execute a specific step in a specific node then you can specify the agent within the stage block. So what you can do is execute the file reading logic on the master in the initial stage and then use it in consecutive stages. Check the example below.
def code
pipeline {
agent none
stages {
stage('LoadParameters') {
agent { label 'master' }
steps {
scipt {
code = returnList()
}
}
}
stage('Get Tests Parameter') {
steps {
script {
properties([
parameters([
[$class : 'CascadeChoiceParameter',
choiceType : 'PT_CHECKBOX',
description : 'Select a choice',
defaultValue : '',
filterLength : 1,
filterable : false,
name : 'Tests',
referencedParameters: 'role',
script : [$class : 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox : true,
script : 'return ["ERROR"]'
],
script : [
classpath: [],
sandbox : false,
script : code
]
]
]
])
])
}
}
}
}
}
def returnList() {
def stringList = []
def fileContent = readFile "/var/jenkins_home/example.txt"
for (line in fileContent.readLines()) {
stringList.add(line.split(",")[0] + ":selected");
}
return stringList
}

Related

Jenkins File - Execute shell command in active choice script

everyone, I'm using plugin "Active Choices" in my Jenkins, I try to do something condition, and the return based on environment host that will be executed in shell command in my Jenkins file. the command like "echo ${BUILD_ENVIRONMENT}, echo ${BUILD_VERSION}..etc".
Already doing this but the list is still empty. now, what do I have to do to make this work? thank you.
JenkinsFile:
properties([
parameters([
[$class: 'ChoiceParameter',
choiceType: 'PT_SINGLE_SELECT',
name: 'ENVIRONMENT',
description: 'Select Environment',
script: [
$class: 'GroovyScript',
script: [
classpath: [],
sandbox: true,
script: '''
def getEnvVar(String name) {
return sh(script: "echo \${$name}", returnStdout: true).trim()
}
def env = getEnvVar("ENVIRONMENT")
if (envs != "testing") {
return ["stage", "dev", "prod"]
}else{
return ["testing"]
}
''',
],
]
]
])
])
Output:
im fix it with another solution, but maybe isnt the best option.
1st create a method to load the env file (i set the values on it), then define to jenkins global variable.
getEnvHosts = { ->
node {
script {
// Get the environment hosts file
def props = readProperties file: '/var/lib/jenkins/env/dast-service-env'
//define to jenkins global variable
env.BUILD_ENVIRONMENT = props['BUILD_ENVIRONMENT']
}
}
}
and then i call the "BUILD_ENVIRONMENT" with ${env.BUILD_ENVIRONMENT} like this in active choice parameter:
getEnvHosts()
properties([
parameters([
[$class : 'ChoiceParameter',
choiceType : 'PT_SINGLE_SELECT',
name : 'BUILD_ENVIRONMENT',
description: "Select Environment default is ${env.BUILD_ENVIRONMENT}",
script : [
$class: 'GroovyScript',
script: [
classpath: [],
sandbox : true,
script : """
def envs = "${env.BUILD_ENVIRONMENT}"
if (envs == "stage") {
choices = ["stage", "dev", "prod", "testing"]
}else if (envs == "dev") {
choices = ["dev", "prod", "stage", "testing"]
}else if (envs == "prod") {
choices = ["prod", "dev", "stage", "testing"]
}else{
choices = ["testing", "stage", "dev", "prod"]
}
return choices
""",
],
]
],
])
])

Reading .json file from Workspace in Jenkins with Groovy script

I want to read a .json file in the stage Prepare Artifacts, which is there in workspace.
How can I read the workspace file path in the staging groovy and run the code?
The below code I used:
checkout scm: [
$class: 'GitSCM',
branches: [[name: "FETCH_HEAD"]],
extensions: [
[$class: 'RelativeTargetDirectory',
relativeTargetDir: repo2],
[$class: 'WipeWorkspace'],
[$class: 'CloneOption',
depth: 1,
noTags: true,
reference: '',
shallow: true,
honorRefspec: true],
[$class: 'CheckoutOption',
timeout: 30]],
gitTool: 'Default',
submoduleCfg: [],
userRemoteConfigs: [
[credentialsId: 'JENKINS_LOGIN',
]
]
]
def releasePackages = readJSON file: "./BuildAutomation/Jenkins/Pipeline//files/release_package.json"
println releasePackages
}
}
}
stage('Prepare Variable') {
steps {
script{
for(file in releasePackages[buildMod]['India']) {
bat("xcopy ..\\CALReleaseOutput\\${file} ..\\${IndiaReleaseOutputFolder}\\${file} /I /E /Y")
}
for(file in releasePackages[buildMod]['Russia']) {
bat("xcopy ..\\CALReleaseOutput\\${file} ..\\${RussiaReleaseOutputFolder}\\${file} /I /E /Y")
}
zip archive: false, dir: "..\\${b2bReleaseOutputFolder}", glob: '', zipFile: "..\\CALReleaseOutput_${tagFoldername}_B2B.zip"
}
}
}
}
}
}
}
When I run above one, I got error message as below
Console Output
If you are going to use variables between stages you have to define them as Global variables. Hence try defining releasePackages outside the pipeline. Following is an example.
def releasePackages
pipeline {
agent any
stages {
stage('SetVariable') {
steps {
script {
releasePackages = readJSON file: "./BuildAutomation/Jenkins/Pipeline//files/release_package.json"
echo "$releasePackages"
}
}
}
stage('UseVariable') {
steps {
echo "$releasePackages"
}
}
}
}

Jenkins parameters using groovy script

UPDATE
I have a simple pipeline where I want to receive in parameters multiple choices from a file.
In my file I have
#Test1,Accounts
#Test2,Services
#Test3,Accesses
and I want to have all of "#Test1", "#Test2" and "#Test3" in checkboxes as parameters so I would run only the tests selected.
But I'm not understanding what I'm doing wrong.
Pipeline
def code = """tests = getChoices()
return tests
def getChoices() {
def filecontent = readFile "/var/jenkins_home/test.txt"
def stringList = []
for (line in filecontent.readLines()) {stringList.add(line.split(",")[0].toString())}
List modifiedList = stringList.collect{'"' + it + '"'}
return modifiedList
}""".stripIndent()
properties([
parameters([
[$class : 'CascadeChoiceParameter',
choiceType : 'PT_CHECKBOX',
description : 'Select a choice',
filterLength : 1,
filterable : false,
name : 'choice1',
referencedParameters: 'role',
script : [$class : 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox : true,
script : 'return ["ERROR"]'
],
script : [
classpath: [],
sandbox : true,
script : code
]
]
]
])
])
pipeline {
agent {
docker { image 'node:latest' }
}
stages {
stage('Tags') {
steps {
getChoices()
}
}
}
}
def getChoices() {
def filecontent = readFile "/var/jenkins_home/test.txt"
def stringList = []
for (line in filecontent.readLines()) {
stringList.add(line.split(',')[0].toString())
}
List modifiedList = stringList.collect { '"' + it + '"' }
echo "$modifiedList"
return modifiedList
}
With this approach I know I can use multi-select checkboxes because I tried to substitute
def code = """ tests = ["Test1", "Test2", "Test3"]
return tests""".stripIndent()
and I get the output that I wanted.
But when I run my pipeline I get build SUCCESS but always get fallbackScript in my Build parameters checkbox. Can anyone help me out understand what is causing fallbackScript to run always? Thanks :)
If you want to auto-populate build parameters you have to return a list of parameters from your function. When you execute the pipeline the build with parameters will be populated. Note in this was only from the second execution of the pipeline the new parameters will be available. Refer following.
pipeline {
agent any
parameters{
choice(name: 'TESTES', choices: tests() , description: 'example')
}
stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
}
}
def tests() {
return ["Test01", "Test2", "Test4"]
}
If you want to get user input each time you execute a build you should move your choice parameter into a stage. Please refer to the following.
pipeline {
agent any
stages {
stage('Get Parameters') {
steps {
script{
def choice = input message: 'Please select', ok: 'Next',
parameters: [choice(name: 'PRODUCT', choices: tests(), description: 'Please select the test')]
echo '$choice'
}
}
}
}
}
def tests() {
return ["Test01", "Test2", "Test4"]
}
Update 02
Following is how to read from a file and dynamically create the choice list.
pipeline {
agent any
stages {
stage('Get Parameters') {
steps {
script{
sh'''
echo "#Test1,Accounts" >> test.txt
echo "#Test2,Services" >> test.txt
'''
def choice = input message: 'Please select', ok: 'Next',
parameters: [choice(name: 'PRODUCT', choices: getChoices(), description: 'Please select the test')]
}
}
}
}
}
def getChoices() {
def filecontent = readFile "test.txt"
def choices = []
for(line in filecontent.readLines()) {
echo "$line"
choices.add(line.split(',')[0].split('#')[1])
}
return choices
}

Dynamically filling parameters from a file in a Jenkins pipeline

TL;DR:
I would like to use ActiveChoice parameters in a Multibranch Pipeline where choices are defined in a YAML file in the same repository as the pipeline.
Context:
I have config.yaml with the following contents:
CLUSTER:
dev: 'Cluster1'
test: 'Cluster2'
production: 'Cluster3'
And my Jenkinsfile looks like:
pipeline {
agent {
dockerfile {
args '-u root'
}
}
stages {
stage('Parameters') {
steps {
script {
properties([
parameters([
[$class: 'ChoiceParameter',
choiceType: 'PT_SINGLE_SELECT',
description: 'Select the Environemnt from the Dropdown List',
filterLength: 1,
filterable: false,
name: 'Env',
script: [
$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: true,
script:
"return['Could not get The environemnts']"
],
script: [
classpath: [],
sandbox: true,
script:
'''
// Here I would like to read the keys from config.yaml
return list
'''
]
]
]
])
])
}
}
}
stage("Loading pre-defined configs") {
steps{
script{
conf = readYaml file: "config.yaml";
}
}
}
stage("Gather Config Parameter") {
options {
timeout(time: 1, unit: 'HOURS')
}
input {
message "Please submit config parameter"
parameters {
choice(name: 'ENV', choices: ['dev', 'test', 'production'])
}
}
steps{
// Validation of input params goes here
script {
env.CLUSTER = conf.CLUSTER[ENV]
}
}
}
}
}
I added the last 2 stages just to show what I currently have working, but it's a bit ugly as a solution:
The job has to be built without parameters, so I don't have an easy track of the values I used for each job.
I can't just built it with parameters and just leave, I have to wait for the agent to start the job, reach the stage, and then it will finally ask for input.
Choices are hardcoded.
The issue I'm currently facing is that config.yaml doesn't exist in the 'Parameters' stage since (as I understand) the repository hasn't been cloned yet. I also tried using
def yamlFile = readTrusted("config.yaml")
within the groovy code but it didn't work either.
I think one solution could be to try to do a cURL to the file, but I would need Git credentials and I'm not sure that I'm going to have them at that stage.
Do you have any other ideas on how I could handle this situation?

Active choice parameter with declarative Jenkins pipeline

I'm trying to use active choice parameter with declarative Jenkins Pipeline script.
This is my simple script:
environments = 'lab\nstage\npro'
properties([
parameters([
[$class: 'ChoiceParameter',
choiceType: 'PT_SINGLE_SELECT',
description: 'Select a choice',
filterLength: 1,
filterable: true,
name: 'choice1',
randomName: 'choice-parameter-7601235200970',
script: [$class: 'GroovyScript',
fallbackScript: [classpath: [], sandbox: false, script: 'return ["ERROR"]'],
script: [classpath: [], sandbox: false,
script: """
if params.ENVIRONMENT == 'lab'
return['aaa','bbb']
else
return ['ccc', 'ddd']
"""
]]]
])
])
pipeline {
agent any
tools {
maven 'Maven 3.6'
}
options {
disableConcurrentBuilds()
timestamps()
timeout(time: 30, unit: 'MINUTES')
ansiColor('xterm')
}
parameters {
choice(name: 'ENVIRONMENT', choices: "${environments}")
}
stages {
stage("Run Tests") {
steps {
sh "echo SUCCESS on ${params.ENVIRONMENT}"
}
}
}
}
But actually the second parameter is empty
Is it possible to use together scripted active choice parameter and declarative parameter?
UPD
Is there any way to pass list variable into script? For example
List<String> someList = ['ttt', 'yyyy']
...
script: [
classpath: [],
sandbox: true,
script: """
if (ENVIRONMENT == 'lab') {
return someList
}
else {
return['ccc', 'ddd']
}
""".stripIndent()
]
You need to use Active Choices Reactive Parameter which enable current job parameter to reference another job parameter value
environments = 'lab\nstage\npro'
properties([
parameters([
[$class: 'CascadeChoiceParameter',
choiceType: 'PT_SINGLE_SELECT',
description: 'Select a choice',
filterLength: 1,
filterable: true,
name: 'choice1',
referencedParameters: 'ENVIRONMENT',
script: [$class: 'GroovyScript',
fallbackScript: [
classpath: [],
sandbox: true,
script: 'return ["ERROR"]'
],
script: [
classpath: [],
sandbox: true,
script: """
if (ENVIRONMENT == 'lab') {
return['aaa','bbb']
}
else {
return['ccc', 'ddd']
}
""".stripIndent()
]
]
]
])
])
pipeline {
agent any
options {
disableConcurrentBuilds()
timestamps()
timeout(time: 30, unit: 'MINUTES')
ansiColor('xterm')
}
parameters {
choice(name: 'ENVIRONMENT', choices: "${environments}")
}
stages {
stage("Run Tests") {
steps {
sh "echo SUCCESS on ${params.ENVIRONMENT}"
}
}
}
}
As of Jenkins 2.249.2 without any plugin and using a declarative pipeline,
the following pattern prompt the user with a dynamic dropdown menu (for him to choose a branch):
(the surrounding withCredentials bloc is optional, required only if your script and jenkins configuratoin do use credentials)
node {
withCredentials([[$class: 'UsernamePasswordMultiBinding',
credentialsId: 'user-credential-in-gitlab',
usernameVariable: 'GIT_USERNAME',
passwordVariable: 'GITLAB_ACCESS_TOKEN']]) {
BRANCH_NAMES = sh (script: 'git ls-remote -h https://${GIT_USERNAME}:${GITLAB_ACCESS_TOKEN}#dns.name/gitlab/PROJS/PROJ.git | sed \'s/\\(.*\\)\\/\\(.*\\)/\\2/\' ', returnStdout:true).trim()
}
}
pipeline {
agent any
parameters {
choice(
name: 'BranchName',
choices: "${BRANCH_NAMES}",
description: 'to refresh the list, go to configure, disable "this build has parameters", launch build (without parameters)to reload the list and stop it, then launch it again (with parameters)'
)
}
stages {
stage("Run Tests") {
steps {
sh "echo SUCCESS on ${BranchName}"
}
}
}
}
The drawback is that one should refresh the jenkins configration and use a blank run for the list be refreshed using the script ...
Solution (not from me): This limitation can be made less anoying using an aditional parameters used to specifically refresh the values:
parameters {
booleanParam(name: 'REFRESH_BRANCHES', defaultValue: false, description: 'refresh BRANCH_NAMES branch list and launch no step')
}
then wihtin stage:
stage('a stage') {
when {
expression {
return ! params.REFRESH_BRANCHES.toBoolean()
}
}
...
}

Resources