How can I run a perl script in a jenkins pipeline step - jenkins

I have configued a pipeline script in jenkins . In one stage , I need to run a perl script with arguments ,like :
pipeline{
agent any
stages {
stage('First Stage')
{
steps
{
dir ("path_to_script")
sh "#!/usr/bin/perl -w test.pl --arg ar1 --arg ar2 --arg ar3"
}
}
This code is not helping me. How can I execute the script test.pl ?

It feels a bit odd to me that you're supplying everything to the shebang. Essentially, you're saying that the interpreter for the remainder of the file is perl with the full set of arguments (which then gets no code to execute supplied). Why I can imagine that this still works, I'd recommend to just call perl:
sh "/usr/bin/perl -w test.pl --arg ar1 --arg ar2 --arg ar3"
and not bring in the shebang definition.
This would only make sense to me, if you would supply a perl script (and then also _Michael J_s' answer would make sense to me because of the multi-line quotes:
sh """#!/usr/bin/perl
use strict;
use warnings;
print "Hello, World!\n";"""

I know this thread is a couple years old now, but just for the record...
steps
{
dir ("path_to_script")
sh "#!/usr/bin/perl -w test.pl --arg ar1 --arg ar2 --arg ar3"
}
Unlike cd, dir is not a command that takes effect and persists. Rather, in keeping with the declarative pipeline, it's a block, for example:
dir ("path_to_script") {
sh "/usr/bin/perl -w ./test.pl --arg ar1"
}
I believe the shebang from the documentation was for if the script was inline. For that matter, if test.pl has the shebang as its first line (#!/usr/bin/perl -w), then this reduces to:
dir ("path_to_script") {
sh "./test.pl --arg ar1"
}

Replace the quotes around your call to perl with three single quotes. This worked for me:
pipeline
{
agent any
stages
{
stage('First Stage')
{
steps
{
sh '''#!/usr/bin/perl -v'''
}
}
}
}

Related

Script in Jenkins file giving exit code 1

I want to get a line from a file in my workspace. I am using this script :
stage('Test') {
steps {
script {
outputJenkins = 'output-jenkins.log'
sh "cd invoker && mvn clean install && mvn exec:java -Dexec.mainClass=\"com.JenkinsRunner\" -Dexec.args=\"qal ${GIT_COMMIT_HASH}\" > ../${outputJenkins}"
logFile = readFile(outputJenkins)
echo logFile
adminRepoLogLine = sh "echo logFile | grep \"Admin repo url is :::\""
echo adminRepoLogLine
}
}
}
But I am getting this error:
+ echo logFile
+ grep Admin repo url is :::
script returned exit code 1
The script works fine in my shell when I try it locally. Are there any contains around doing it in a JenkinsFile?
If we apply various fixes and improvements to the code in the question to achieve the desired functionality, then it will succeed:
stage('Test') {
steps {
script {
dir('invoker') {
sh(label: 'Maven Clean Install', script: 'mvn clean install')
// assign maven output to variable
String output = sh(label: 'Maven Git Log', script: "mvn exec:java -Dexec.mainClass=\"com.JenkinsRunner\" -Dexec.args=\"qal ${GIT_COMMIT_HASH}\"", returnStdout: true)
}
// assign regex return to variable
def adminRepoLogLine = output =~ /(.*Admin repo url is :::.*)/
// print extracted string from return
print adminRepoLogLine[0][1]
}
}
}
Note that GIT_COMMIT_HASH is neither an intrinsic Jenkins environment variable, nor defined in the pipeline code in the question, so it will need to be defined at Pipeline scope elsewhere in your code.
This is because the string literal logFile does not contain the string Admin repo url is :::. If there's no such match, then grep will exit with status 1.
You probably want to use
cat logFile | grep \"Admin repo url is :::\"
instead, or, even simpler:
grep \"Admin repo url is :::\" logFile
Append || true (or ||:) to the command if you want to avoid the errors when the log line does not appear.

How to use shell regular expression in jenkinsfile for jenkins pipeline?

I am trying to replace the '/' from Git branch name with '_' in my jenkinsfile so that I can tag my docker image with the branch name. In bash the below command works fine
echo "${git_branch_name//\//_}"
But when use the above command in jenkinsfile as below it throws an error.
#!/usr/bin/env groovy
def commit_id
def imagetag
def branch_name
def git_branch_name
node('Nodename') {
stage('checkout') {
checkout (scm).$Branch_Param
sh "git rev-parse --short HEAD > .git/commit-id"
commit_id = readFile('.git/commit-id').trim()
sh "git rev-parse --abbrev-ref HEAD > .git/branch-name"
git_branch_name = readFile('.git/branch-name').trim()
branch_name= sh "echo ${git_branch_name//\//_}"
sh "echo ${commit_id}"
sh "echo ${branch_name}"
sh "echo Current branch is ${branch_name}"
}
}
WorkflowScript: 15: end of line reached within a simple string 'x' or "x" or /x/;
solution: for multi-line literals, use triple quotes '''x''' or """x""" or /x/ or $/x/$ # line 15, column 28.
sh "branch_name = echo ${git_branch_name//\//_}"
What am I doing wrong here? Should I use Groovy regular expression instead of shell? why is shell not being interpreted correctly?
Thank you
The issue is that you're asking Groovy itself to interpret the expression ${git_branch_name//\//_}, not the shell. Using double-quotes around the string you pass to the sh step is what causes that. So if you instead write the following, this first error will go away:
sh 'echo ${git_branch_name//\\//_}' // <- Note the single-quotes
Basically, always use single-quotes unless you specifically need to use groovy's string interpolation (see the very last echo at the bottom of this answer).
Interestingly, it seems when I tested I didn't need the shebang (#!/bin/bash) to specify bash as some comments suggest; this ${variable//x/y} replace syntax worked in an sh step as-is. I guess the shell spawned was bash. I don't know if that's always the case, or if our Jenkins box has been specifically setup that way.
Also note you need to escape the escape sequence ('\\/') because what you're passing to the sh step is a string literal in groovy code. If you don't add that extra backslash, the line passed to the shell to be interpreted by it will be echo ${git_branch_name////_}, which it won't understand.
But there are other issues as well. First, assigning the output of the sh step to branch_name as you do means branch_name will always equal null. To get the stdout from a line of shell code you need to pass the extra parameter returnStdout: true to sh:
branch_name = sh (
script: 'echo ${git_branch_name//\\//_}',
returnStdout: true
).trim () // You basically always need to use trim, because the
// stdout will have a newline at the end
For bonus points, we could wrap that sh call in a closure. I find myself using it often enough to make this a good idea.
// Get it? `sh` out, "shout!"
def shout = { cmd -> sh (script: cmd, returnStdout: true).trim () }
//...
branch_name = shout 'echo ${git_branch_name//\\//_}'
But finally, the major problem is that bash (or whatever shell is actually spawned) doesn't have access to groovy variables. As far as it knows, echo ${git_branch_name} outputs an empty string, and therefore so does echo ${git_branch_name//\//_}.
You have a couple of choices. You could skip the creation of .git/branch-name and just immediately output the string-replaced result of git rev-parse:
branch_name = shout 'name=$(git rev-parse --abbrev-ref HEAD) && echo ${name//\\//_}'
Or to simplify that further you could use groovy's string replace function rather than the bash syntax:
branch_name = shout ('git rev-parse --abbrev-ref HEAD').replace ('/', '_')
Personally, I find the latter quite a bit more readable. YMMV. So bringing it all together at last:
#!groovy
def shout = { cmd -> sh (script: cmd, returnStdout: true).trim () }
// Note that I'm not declaring any variables up here. They're not needed.
// But you can if you want, just to clearly declare the environment for
// future maintainers.
node ('Nodename') {
stage ('checkout') {
checkout (scm).$Branch_Param
commit_id = shout 'git rev-parse --short HEAD'
branch_name = shout ('git rev-parse --abbrev-ref HEAD').replace ('/', '_')
echo commit_id
echo branch_name
echo "The most recent commit on branch ${branch_name} was ${commit_id}"
}
}

Syntax error while using backslash in Jenkinsfile

I try to make simple pipeline on Jenkins to remove files from few directories time to time. I decided not to create python script with Jenkinsfile as new project, instead of it I try to define new pipeline script in Jenkins job.
pipeline {
agent any
stages {
stage('Check virtualenv') {
steps {
sh """
rm -r /mnt/x/some/directory/Problem\ 1.0/path
"""
}
}
}
}
And I got an error WorkflowScript: 4: unexpected char: '\'. How can I use path with whitespace on it without using backslash? Any other ideas how define path?
The '\' character is a special character in Groovy. If you tried to compile this kind of code with the normal Groovy compiler, it would give you a better error message. The easiest way to handle it would be to escape it:
"""
rm -r /mnt/x/some/directory/Problem\\ 1.0/path
"""
You can modify the shell command as follows:
sh """
rm -r /mnt/x/some/directory/Problem""" + """ 1.0/path"""
Provide space before 1.0 as required. Hope this helps.

Using env variables to set other variables in Jenkins pipeline as code

I cannot use environment variables set in previous blocks in access stage below.
pipeline{
agent any
stages{
stage("set env variable"){
steps{
script{
env.city = "Houston"
}
}
}
}
stage("access"){
steps{
sh """
set brf = ${env.city}
echo $brf
"""
}
}
}
}
ERROR: groovy.lang.MissingPropertyException: No such property: brf for class: groovy.lang.Binding
What is an easier way to use jenkins declarative pipeline env variables ?
I cannot use environment variables set in previous blocks in access stage below.
If you look closely at the error, you can see Jenkins is actually unable to access brf, not env.city.
The issue here is caused by the way Jenkins interprets $var inside sh block:
if you use "double quotes", $var in sh "... $var ..." will be interpreted as Jenkins variable;
if you use 'single quotes', $var in sh '... $var ...' will be interpreted as shell variable.
Since the sh code in your script is wrapped in "double quotes", $brf is considered to be a Jenkins variable, while there is no such variable defined, therefore the error occurs.
To use shell variable inside double-quoted block add \ before $:
sh "echo \$var"
works the same way as
sh 'echo $var'
This should fix your pipeline script:
pipeline{
agent any
stages{
stage("set env variable"){
steps{
script{
env.city = "Houston"
}
}
}
stage("access"){
steps{
sh """
brf=${env.city}
echo \$brf
"""
}
}
}
}
Output from the pipeline:
[test] Running shell script
+ brf=Houston
+ echo Houston
Houston
You should not have any problem to get the variables with this code:
stage("access"){
steps{
sh "set brf = ${env.city}"
echo '$brf'
//or
sh "set brf = ${env.city} && echo $brf"
}
}
I think this is what you had asked but let me know if you have another doubt.

Jenkins: Unable to create directory using the date

I want to create a directory using jenkins with the days date.
I'm using the new jenkins declarative syntax.
When i run the build as described in the job below it fails.
The mkdir command though, works perfectly well on the console.
pipeline {
agent any
stages {
stage('Prepare') {
steps {
echo "Checking for the existence of a debian packages directory for this package"
sh "mkdir -p {env.JENKINS_HOME}/workspace/debian_packages/api-config/$(date +"%d-%m-%Y")"
}
}
}
}
This is the error I get (I've tried escaping the $ characters but it still fails)
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
failed:
WorkflowScript: 19: illegal string body character after dollar sign;
solution: either escape a literal dollar sign "\$5" or bracket the
value expression "${5}" # line 19, column 17.
sh "mkdir -p
{env.JENKINS_HOME}/workspace/debian_packages/api-
config/$(date +'%d-%m-%Y')"
What could be the issue? Isn't the jenkins "sh" meant to take commands as they would have been issued directly on the console?
This is workaround that I could come up:
stage('Prepare') {
steps {
script{
sh '(date +"%d-%m-%Y") > outFile'
def curDate = readFile 'outFile'
echo "The current date is ${curDate}"
sh "mkdir -p {env.JENKINS_HOME}/workspace/${curDate}"
}
}
}

Resources