Capturing results of Jenkins input step - jenkins

I am playing around with the Jenkins Pipeline and I have some issues at the time of capturing the results of an input step. When I declare the input step as follows ...
stage('approval'){
steps{
input(id: 'Proceed1', message: 'Was this successful?',
parameters: [[$class: 'BooleanParameterDefinition', defaultValue: true, description: '', name: 'Please confirm you agree with this']])
}
}
... everything seems to be working fine. However, as soon as I try to get the results from the capture (i.e. the answer given to the question), the script does not work. For example, an script like the following:
pipeline {
agent { label 'master' }
stages {
stage('approval'){
steps{
def result=input(id: 'Proceed1', message: 'Was this successful?', parameters: [[$class: 'BooleanParameterDefinition', defaultValue: true, description: '', name: 'Please confirm you agree with this']])
echo 'echo Se ha obtenido aprobacion! (como usar los datos capturados?)'
}
}
}
}
... results in the following error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 6: Expected a step # line 6, column 13.
result=input(id: 'Proceed1', message: 'Was this successful?', parameters: [[$class: 'BooleanParameterDefinition', defaultValue: true, description: '', name: 'Please confirm you agree with this']])
^
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1073)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:591)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
...
at hudson.model.Executor.run(Executor.java:404)
Finished: FAILURE
Something quite interesting is that if I moved the input outside the pipeline{}, it works perfectly fine. I noticed that same behaviour occurs with 'def' statement (I can define and use a variable outside pipeline{} but I cannot define it inside).
I think I must be missing something quite basic here but after few hours trying different configurations, I could not manage to make it work. Is it just that the logic to be used within pipeline{} is limited to very few commands? How people then build complex pipelines?
Any help would be highly appreciated.

The script block allows using the Scripted Pipeline syntax aka almost all Groovy functionality within a Declarative pipeline.
See https://jenkins.io/doc/book/pipeline/syntax/ for syntax comparision and restrictions of the declarative pipeline.
pipeline {
agent any
...
stages {
stage("Stage with input") {
steps {
script {
def result = input(id: 'Proceed1', message: 'Was this successful?', parameters: [[$class: 'BooleanParameterDefinition', defaultValue: true, description: '', name: 'Please confirm you agree with this']])
echo 'result: ' + result
}
}
}
}
}

I finally managed to make it work but I had to completely change the syntax to avoid pipeline, stages & steps tags as used above. Instead, I implemented something like:
#!/usr/bin/env groovy
node('master'){
// --------------------------------------------
// Approval
// -------------------------------------------
stage 'Approval'
def result=input(id: 'Proceed1', message: 'Was this successful?', parameters: [[$class: 'BooleanParameterDefinition', defaultValue: true, description: '', name: 'Please confirm you agree with this']])
echo 'Se ha obtenido aprobacion! '+result
}

Related

How to pass groovy variable to powershell in Jenkins pipeline?

I'm trying to pass groovy variable to powershell script inside of jenkins pipeline, all in the same place but i don't know how. i tried different ways without success.
I require this to obtain the name of the person who approved the step of PIPELINE and pass it to powershell, which connects with SQL SERVER
stage('Step1'){
steps{
script{
def approverDEV
approverDEV = input id: 'test', message: 'Hello', ok: 'Proceed?', parameters: [choice(choices: 'apple\npear\norange', description: 'Select a fruit for this build', name: 'FRUIT'), string(defaultValue: '', description: '', name: 'myparam')], submitter: 'user1,user2,group1', submitterParameter: 'APPROVER'
echo "This build was approved by: ${approverDEV['APPROVER']}"
}
}
}
stage('Step2'){
steps{
script{
powershell ('''
# Example echo "${approverDEV['APPROVER']}"
# BUT THIS DOESN'T WORK :(
''')
}
}
}
I expect the output is the name of the approver stored in the variable GROOVY approverDEV
Dagett is correct, use double-quotes around the powershell script, then the variables will be evaluated:
script{
powershell ("""
# Example echo "${approverDEV['APPROVER']}"
# BUT THIS DOESN'T WORK :(
""")
}
Using triple double quotes in Groovy is called 'multi-line GString'. In a GString, variables will be evaluated before creating the actual String.

String parameter passing in jenkins pipeline

I am developing a pipeline where in when triggered it should display the parameters and below is the code
node {
stage('preparation') {
timeout(time:15, unit:'MINUTES') {
id: 'userInput', message: 'preparation',
parameters: [
[$class: 'TextParameterDefinition', defaultValue: 'cicd', description: 'dev env', name: 'DEV_PROJECT'],
[$class: 'TextParameterDefinition', defaultValue: 'test', description: 'stage env', name: 'STAGE_PROJECT'],
[$class: 'TextParameterDefinition', defaultValue: 'jboss', description: 'Image Name', name: 'IMAGE_NAME'],
] )
input message: "Is the PARAMETERS(can be visible on leftside) are correctly set for deployment?", ok: "Promote" }
echo "${DEV_PROJECT}"
echo "${STAGE_PROJECT}"
echo "${IMAGE_NAME}"
}
When i do echo its not populating the values of user input.
Iam getting below error. My requirement is the user can input the DEV_PROJECT,STAGE_PROJECT and IMAGE_NAME and the values entered by him should be used in the pipeline scripts down the line in build and deploy stages.Iam getting below error
groovy.lang.MissingPropertyException: No such property: DEV_PROJECT for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:242)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:284)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:288)
could anyone let me know how to proceed?
If you have configured your pipeline to accept parameters when it is built — Build with Parameters — they are accessible as Groovy variables inside params.
Example: Using isFoo parameter defined as a boolean parameter (checkbox in the GUI):
node {
sh "isFoo is ${params.isFoo}"
sh 'isFoo is ' + params.isFoo
if (params.isFoo) {
// do something
}
Reference: https://jenkins.io/doc/book/pipeline/getting-started/#global-variable-reference

How to use NodeLabel parameter plugin in declarative pipeline

Im trying to convert my freestyle job to a declarative pipeline job since the pipeline provides more flexibility. I cannot figure out how to use the NodeLabel parameter plugin (https://wiki.jenkins.io/display/JENKINS/NodeLabel+Parameter+Plugin) in a pipeline however.
pipeline {
agent any
parameters {
// Would like something like LabelParameter here
}
stages {
stage('Dummy1') {
steps {
cleanWs()
sh('ls')
sh('pwd')
sh('hostname')
}
}
stage('Dummy2') {
steps {
node("comms-test02") {
sh('ls')
sh('pwd')
sh('hostname')
}
}
}
}
I basically just need a way to start the job using a parameter that specifies where to build the job (using slave label).
Jenkins requires an agent field to be present which i set to 'any'. But it doesnt seem like there is a labelparameter available ?
As an alternative I tried using the 'node' command (https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#-node- allocate node). But that leaves me with two running jobs which, while working, doesnt look that pretty.
Does anyone if the NodeLabel parameter plugin can be used ? or maybe someone has a cleaner approach ?
Edit: Maybe I wasn't clear. I need to be able to run jobs on different nodes. The node to run on should be decided when triggering the job through a parameter. The node label plugin does this perfectly. However, I have not been able to reproduce this behavior in pipeline.
Here's a full example:
pipeline {
parameters {
choice(name: 'node', choices: [nodesByLabel('label')], description: 'The node to run on') //example 1: just listing all the nodes with label
choice(name: 'node2', choices: ['label'] + nodesByLabel('label'), description: 'The node to run on') //example 2: add the label itself as the first choice to make "Any of the nodes" the default choice
}
agent none
stages {
stage('Test') {
agent { label params.node}
stages {
stage('Print environment settings') {
steps {
echo "running on ${env.NODE_NAME}"
sh 'printenv | sort'
}
}
}
}
}
}
Let's say you added the parameter(say named slaveName) using the NodeLabel plugin on your pipeline. You now need to extract the value of slaveName and feed it into the agent->node->label field.
You can specify the node using the node property inside the agent.
Like this -
agent
{
node
{
label "${slaveName}"
}
}
The following script worked for me to run the multiple jobs parallelly on different Node.
I have taken the reference from the build step plugin documentation.
https://www.jenkins.io/doc/pipeline/steps/pipeline-build-step/
def build_one()
{
parallel one: {
stage('XYZ') {
catchError(buildResult: 'SUCCESS', stageResult:'FAILURE') {
build job: 'yourDownStreamJob', parameters: [[$class: 'NodeParameterValue', name: 'NodeToRun',labels: ['nodeName'], nodeEligibility: [$class: 'AllNodeEligibility']], string(name: 'ParentBuildName', value: "XX"), string(name: 'Browser', value: 'chrome'), string(name: 'Environment', value: 'envName')]
}
}
},
two : {
stage('SecondArea') {
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
build job: 'yourDownStreamJob', parameters: [[$class: 'NodeParameterValue', name: 'NodeToRun',labels: ['Your'], nodeEligibility: [$class: 'AllNodeEligibility']], string(name: 'ParentBuildName', value: "XYX"), string(name: 'Browser', value: 'firefox'), string(name: 'Environment', value: 'envName')]
}
}
}
}
build_one()

Append to Job properties

My job parameters defined in job-dsl.groovy are overwritten by those defined in pipeline.
I am using job-dsl-plugin and Jenkins pipeline to generate Jenkins job for each git branch. Sine my code is stored in gitLab they require gitLab integration. I am providing that using gitlab-plugin. The problem is with the 'gitLabConnection' it looks like it can be only applied from inside the Jenkins pipeline.
So if in job-dsl I would do:
branches.each { branch ->
String safeBranchName = branch.name.replaceAll('/', '-')
if (safeBranchName ==~ "^release.*")
{
return
}
def branch_folder = "${basePath}/${safeBranchName}"
folder branch_folder
pipelineJob("$branch_folder/build") {
logRotator {
numToKeep 20
}
parameters {
stringParam("BRANCH_NAME", "${safeBranchName}", "")
stringParam("PROJECT_NAME", "${basePath}", "")
{
}
And then in my Jenkins pipeline I would add the 'gitLabConnection'
node('node_A') {
properties([
gitLabConnection('gitlab.internal')
])
stage('clean up') {
deleteDir()
}
///(...)
I have to do it like:
node('node_A') {
properties([
gitLabConnection('gitlab.internal'),
parameters([
string(name: 'BRANCH_NAME', defaultValue: BRANCH_NAME, description: ''),
string(name: 'PROJECT_NAME', defaultValue: PROJECT_NAME, description: '')
])
])
stage('clean up') {
deleteDir()
}
///(...)
So that my BRANCH_NAME and PROJECT_NAME are not overwritten.
Is there another way to tackle this ?
Is it possible to append the 'gitLabConnection('gitlab.internal')' to the properties in the Jenkins pipeline ?
Unfortunately it doesn't seem like there is a way to do this yet. There's some discussion about this at https://issues.jenkins-ci.org/browse/JENKINS-43758 and I may end up opening a feature request to allow people to "append to properties"
There are 2 ways for solving this. The first one uses only Jenkins pipeline code, but if you choose this path the initial job run will most likely fail. This initial fail will happen, because at the time of first job run, the pipeline creates Jenkins job parameters. Once the parameters are created, job will work.
Option '1' - using Jenkins pipeline Only.
In 'Pipeline Syntax'/'Snippet Generator' check:
'This project is parameterised'.
Add parameter(s) you need, and hit 'Generate Pipeline Script'. In my case I get:
properties([
gitLabConnection(gitLabConnection: 'my_gitlab_connection', jobCredentialId: '', useAlternativeCredential: false),
[$class: 'JobRestrictionProperty'],
parameters([
string(defaultValue: 'test', description: 'test', name: 'test', trim: false)
]),
throttleJobProperty(categories: [], limitOneJobWithMatchingParams: false, maxConcurrentPerNode: 0, maxConcurrentTotal: 0, paramsToUseForLimit: '', throttleEnabled: false, throttleOption: 'project')
])
Option '2' - It's more complicated but, also far more powerfull. The one I finally took, because of the issues described above.
Use Jenkins job DSL plugin - https://github.com/jenkinsci/job-dsl-plugin
Gitlab plugin works quite well with it https://github.com/jenkinsci/gitlab-plugin#declarative-pipeline-jobs

How can I pass parameters from parallel builds downstream in a jenkins pipeline

I have been trying to set up a pipeline in jenkins which runs all my robot test builds in parallel and then, after they all finish, runs another build which includes sending 1 email with results for all the tests (rather than spamming with 1 per build).
I know that the robot plugin returns the variables $(ROBOT_PASSPERCENTAGE) and $(ROBOT_PASSRATIO) which we currently use. I was hoping there was a way of extracting them and using as a parameter for the downstream pipline build.
Just as a test I was trying groovy of the form below, but can't figure out how you get the variables and pass into the downstream build.
Any help appreciated.
stage('set up') {
node {
build job: 'setup', propagate: false
}
}
stage('run suites') {
parallel 'test set 1':{
node {
build job: 'test set 1', propagate: false
def 1_PASSPERCENTAGE = build.buildVariableResolver.resolve("ROBOT_PASSPERCENTAGE")
def 1_PASSRATIO = build.buildVariableResolver.resolve("ROBOT_PASSRATIO")
println "FOO=$CRM_PASSPERCENTAGE"
println "FOO=$CRM_PASSRATIO"
}
}, 'test set 2':{
node {
build job: 'thankQ Robot Mission Personnel Tests', propagate: false
def 2_PASSPERCENTAGE = build.buildVariableResolver.resolve("ROBOT_PASSPERCENTAGE")
def 2_PASSRATIO = build.buildVariableResolver.resolve("ROBOT_PASSRATIO")
println "FOO=$MP_PASSPERCENTAGE"
println "FOO=$MP_PASSRATIO"
}
}
}
stage('results') {
node {
println "FOO=$2_PASSPERCENTAGE"
println "FOO=$2_PASSRATIO"
println "FOO=$1_PASSPERCENTAGE"
println "FOO=$1_PASSRATIO"
}
}
From Jenkins pipeline steps reference, you can call a downstream job with parameters like this :
build job: downstreamJob, parameters: [
[$class: 'StringParameterValue', name: 'passPercentage', value: "${1_PASSPERCENTAGE}"],
[$class: 'StringParameterValue', name: 'passRatio', value: "${1_PASSRATIO}"]
]
As for how to get your Robot variables I have never used it but I guess you could always use the URL of the test build (e.g. your test set 1 job) and parse the log file or the build page for the variables you are looking for. Something like this :
def robotLog = script: 'curl http://your-jenkins/job/test-set-1/lastBuild/robot.log', returnStdout: true // First determine which URL corresponds to the robot.log file, or use the main page of your build.
def percentageMatcher = robotLog.trim() =~ 'Pass percentage.*(\\d+)%' // Again, find the exact regex here
def 1_PASSPERCENTAGE = percentageMatcher[0][1]
... // Same thing with pass ratio...

Resources