Jenkins Pipeline - inserting variable in shell creates a new line - jenkins

I am using Choice param in my jenkins file to select environment as follows:
pipeline {
agent any
parameters {
choice(
name: 'ENVIRONMENT_URL',
choices: "https://beta1.xyz.com\nhttps://beta2.xyz.com\nhttps://beta3.xyz.com",
description: 'interesting stuff' )
}
in the Stage section, i have the following piece
stage('execute tests') {
steps {
script {
sh """URL=${ENVIRONMENT_URL} npm run e2e:tests"""
sh 'echo -e "\nTest Run Completed.\n"'
}
}
}
However, when i run the pipeline job by selecting the choice parameter i added, the following gets executed (the inserted choice param creates a line break):
+ URL=https://beta1.xyz.com
+ npm run e2e:tests
Using the variable is causing a line break and that's what is causing issue.
I have tried different ways to avoid line break. Tried using a variable but that didn't help. tried with different quotations, that didn't either.
What can i do to avoid line break ?

You can use the trim method on a String class type to remove trailing whitespace and newline:
sh "URL=${params.ENVIRONMENT_URL.trim()} npm run e2e:tests"
Note I also specified your parameter is in the params map and removed the triple quotes as those are for multiline string formatting.
Alternatively, you can specify the choices as an array instead of as a multiline string. The choices argument would then appear like:
choice(
name: 'ENVIRONMENT_URL',
choices: ['https://beta1.xyz.com', 'https://beta2.xyz.com', 'https://beta3.xyz.com'],
description: 'interesting stuff'
)
Either solution would fix your issue.

Related

Jenkins pipeline returns "Bad Subtitution" for shell command

I'm attempting to run the following command in a shell block in my Jenkins pipeline:
jq '.Resources[].TargetService.Properties.TaskDefinition = "'"arn:aws:ecs:us-east-1:${ACCOUNT_NUMBER}:task-definition/${TASK_NAME}:${NEW_REVISION}"'"'
This command works perfectly fine when I run it directly on the Jenkins node in shell.
When I insert it into the Pipeline like this:
stage('process json') {
steps {
dir('mydir') {
sh """
NEW_REVISION=\$(cat revision.txt)
jq '.Resources[].TargetService.Properties.TaskDefinition = "'"arn:aws:ecs:us-east-1:\${env.AWS_ACCOUNT_NUMBER}:task-definition/\${env.TASK_NAME}:\${NEW_REVISION}"'"'
"""
}
}
}
I get a Bad substitution error without any more information. As far as I know, I'm escaping variables and quotation correctly. I can bypass the error if I remove the double quotes like this:
jq '.Resources[].TargetService.Properties.TaskDefinition = "arn:aws:ecs:us-east-1:${ACCOUNT_NUMBER}:task-definition/${TASK_NAME}:${NEW_REVISION}"'
But that ends up processing the variables literally.
Notes: I'm aware of the security issue by not passing jq --arg and prepared to modify my command after I can get the simpler format working. revision.txt contains a numeric value. The env.* variables are declared earlier as part of the pipeline environment.
env is a Jenkins Object and you seem to be escaping env.* variables as well. If you have already exported these variables as Environment variables they should be available to you in the shell environment. So simply drop the env part from the variables or remove the escape characters from such variables and let Jenkins interpolate them.
stage('process json') {
steps {
dir('mydir') {
sh """
NEW_REVISION=\$(cat revision.txt)
jq '.Resources[].TargetService.Properties.TaskDefinition = "'"arn:aws:ecs:us-east-1:\${AWS_ACCOUNT_NUMBER}:task-definition/\${TASK_NAME}:\${NEW_REVISION}"'"'
"""
}
}
}

Expand ENV vars from String

How can I expand ${ENV} variables in Jenkins Pipeline if they are in a string I do not control?
For example I have configured my Pipeline Job to load the Pipeline from a parameterized SCM:
If I now access that branch via scm.branches[0].name inside the Pipeline I am currently getting ${REF}, too.
(The checkout scm part of the pipeline works fine, thats not the problem.)
I have tried the tm() step, but that throws org.jenkinsci.plugins.tokenmacro.MacroEvaluationException: Unrecognized macro 'REF' in '${REF}'
I for example cannot use to update the build name:
currentBuild.displayName = "${scm.branches[0].name} (#$BUILD_NUMBER)"
If REF is an Environment variable you can use String interpolation. Just put the variable into double quotes within the pipeline.
echo "${REF}"
Update
Not sure if there is better groovy way to do this. But following is an option you can use.
steps {
script {
script {
echo "${scm.branches[0].name}"
String branchName = "${scm.branches[0].name}"
String envNameOnly = branchName.substring(2, branchName.length()-1)
def env = System.getenv()[envNameOnly]
echo "$env"
}
}
}

Map parameter to label

I have a pipeline parameterized by env which takes specific values shown below. The parameter is used in the script and cannot change. But the admin tells me that the labels for the agent have to depend on the parameter env and another fixed one (e.G. LABELX).
The problem I encounter is that, while the script requires exactly the values shown below, the label for the agent is not always ${params.env}, but in one case there's a mapping/translation to be made.
This is the extremely reduced groovy script:
pipeline {
agent {label "${params.env} && LABELX"}
parameters {
choice(
name: 'env',
choices: ['development', 'staging', 'production'],
)
}
stages {
stage('Process') {
steps {
sh """
# use ${params.env} in bash script
""""
}
}
}
}
The mapping I need is as follows:
env
label
development
development
staging
test
production
production
How can I replace the parameter staging with the label test before choosing an agent? I cannot do that in a script, because scripts are run by agents... I have to somehow do this before, inside the ${params.env} maybe. Or do I need an additional parameter (params.label)?
One way to solve it is to create a constant label mapping before your pipeline, and then use it in your pipeline to retrieve the needed value.
Something like:
LABELS = ['development':'development', 'staging':'test', 'production':'production']
pipeline {
agent {
label "${LABELS[params.env]} && LABELX"
}
parameters {
choice(
name: 'env',
choices: ['development', 'staging', 'production'],
)
}
stages {
stage('Process') {
steps {
sh """
# use ${params.env} in bash script
"""
}
}
}
}
By the way, it is not recommended to call your parameter env as it may override or collide in some cases with the default env map that contains all the environment parameters of the job, including those defined in the environment directive.

Each loop failing in Groovy DSL Pipeline for Jenkins Jobs Builder

I'm trying to create dynamic Jenkins job pipeline stages based on an array of values but I can't seem to get the loop functioning as expected, it complains about the syntax I'm using but I can't figure it out, is this a Groovy issue?
Approach
uat_nodes:
- 'node1'
- 'node2'
dsl: |
stage('Update UAT dist') {{
build job: '{key}-{module}-DP-BuildNamedDist-UAT'
}}
def UAT_NODES = {uat_nodes}
UAT_NODES.each { UAT_NODE ->
stage('Deploy code to UAT node: ' . ${{UAT_NODE}}) {{
build job: '{key}-{module}-DP-UAT-Nodes', parameters: [
string(name: 'LIMIT', value: '${{UAT_NODE}}'),
string(name: 'PLAYBOOK', value: '{playbook}')
]
}}
}
Error
WorkflowScript: 8: Ambiguous expression could be either a parameterless closure expression or an isolated open code block;
solution: Add an explicit closure parameter list, e.g. {it -> ...}, or force it to be treated as an open block by giving it a label, e.g. L:{...} # line 8, column 56.
e to UAT node: ' . ${{UAT_NODE}}) {{
As the error states, there is a problem with this piece of code: . ${{UAT_NODE}}
If strings would have a $ method, that would call it with a closure inside a closure, that returns UAT_NODE.
I can only assume, that you want to concat strings here similar to perl or php. This is not how it works in groovy.
Use: "Deploy code to UAT node: ${UAT_NODE}". Note the double quotes "! Single quotes ' won't give you replacement (this is every other string you are using in your code).

What is use of sh ''' <command > ''' - three ticks - in a Jenkinsfile?

I have a Jenkinsfile which uses three tick marks surrounding a command to execute as in:
sh ''' command '''
We have no idea why three tick marks are required or what role they perform.
This syntax is seen in the Jenkinsfile doc set.
This has nothing at all to do with bash (in which triple-quotes have no special meaning at all), and everything to do with Groovy (the separate, non-bash interpreter that parses Jenkinsfiles).
In Groovy, but not in bash, strings must use triple-quotes to span multiple lines.
In the context of a sh directive in a Jenkinsfile, the content of your triple-quoted string is passed to a shell as a script to execute; however, the syntax is parsed by Groovy, so it's only Groovy that cares about the quotes themselves (as opposed to the quoted content).
Can you give more idea about what kind of command is it, is it a unix command or some script ?
The single quote and its variation like '''(3 ticks) as mentioned in question skip the variable expansion, and it could used to show what is being executed.
echo '''Updating JAVA_HOME variable :
export $JAVA_HOME="$NEW_JAVA_HOME" '''
However in your question, a command (some string) is enclosed between 3 ticks marks and sh tries to execute this command or script. One such example below
$ echo "echo hello" > /tmp/tesh.sh
$ sh '''/tmp/test.sh'''
hello

Resources