Return String After Character in Jenkins - jenkins

I'm using shared libraries in groovy.
I have this variable which will return : feature/nameofthebranch
def BRANCH = steps.sh(returnStdout: true, script: 'git rev-parse --abbrev-ref HEAD').trim()
However I only need the character after the "/"
I've tried split and other stuff but doesn't work as I would like to, maybe because I'm clumsy at groovy.
Expected result should be from feature/nameofthebranch to "nameofthebranch"

You can do it like this
def BRANCH = steps.sh(returnStdout: true, script: 'git rev-parse --abbrev-ref HEAD').trim()
echo "${BRANCH.split('/')[1]}"

Related

script: "git rev-parse ${latestTag}^{commit}" fails in Jenkinsfile

Below line in Jenkinsfile
latestTagSHA1 = sh(returnStdout: true, script: "git rev-parse ${latestTag}^{commit}")
results in script.sh: ^{commit}: not found error.
Is there a way to escape ^{commit} part?
I tried to use ^\{commit\} to no avail.
It's important to note that i want to actually run command
git rev-parse ${latestTag}^{commit}, for example git rev-parse 2.0.0^{commit} where latestTag equals 2.0.0.
This command returns SHA1 of git tag. For example, for existing tagged commit 850d25580a894befbce6d922bee954c7669cf70c with tag 1.0 below command will return the SHA1 of the tag:
git rev-parse 1.0^{commit}
850d25580a894befbce6d922bee954c7669cf70c
added full Jenkinsfile using the failing line:
pipeline {
agent {
node {
label 'some_label'
customWorkspace "workspace/${JOB_NAME}/${params.PROJECT}/${params.REPO_NAME}/${BUILD_NUMBER}/"
}
}
parameters {
string defaultValue: "${REPO_NAME}", name: 'REPO_NAME', trim: true
string defaultValue: "${PROJECT}", name: 'PROJECT', trim: true
string defaultValue: "${SRC_BRANCH_NAME}", name: 'SRC_BRANCH_NAME', trim: true
string defaultValue: "${PR_MERGER_EMAIL}", name: 'PR_MERGER_EMAIL', trim: true
string defaultValue: "${SHA1}", name: 'SHA1', trim: true
}
options {
lock resource: "${params.REPO_NAME}" // lock on repo to avoid concurrent releases on the same repo
}
stages {
stage("package") {
steps {
dir("/tmp/${params.PROJECT}/${params.REPO_NAME}") {
checkout(
[
$class: 'GitSCM',
branches: [[name: 'refs/heads/master']],
extensions: [
[$class: 'LocalBranch', localBranch: "master"]
],
userRemoteConfigs: [[
url: env.GIT_URL, credentialsId: "smth"
]]
]
)
script {
sh "cd /tmp/${params.PROJECT}/${params.REPO_NAME}"
latestTag = sh(returnStdout: true, script: "git describe --tags `git rev-list --tags --max-count=1`")
latestTagSHA1 = sh(returnStdout: true, script: "git rev-parse ${latestTag}^{commit}")
latestSHA1Timestamp = sh(returnStdout: true, script: "git show -s --format='%ct' ${latestTagSHA1}")
currentCommitSHA1Timestamp = sh(returnStdout: true, script: "git show -s --format='%ct' ${params.SHA1}")
if (latestSHA1Timestamp > currentCommitSHA1Timestamp) {
currentBuild.result = 'ABORTED'
error('some')
}
}
}
}
}
}
}
You don't have to escape anything in line that throws the error. The problem is that the sh step returns an output with a trailing newline.
returnStdout (optional)
If checked, standard output from the task is returned as the step value as a String, rather than being printed to the build log. (Standard error, if any, will still be printed to the log.) You will often want to call .trim() on the result to strip off a trailing newline.
Source: https://www.jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script
That is why what Jenkins is trying to execute in your case is:
git rev-parse 1.0.0
^{commit}
instead of
git rev-parse 1.0.0^{commit}
The solution to this problem is simple: when you return the output of the sh step, call trim() in the end to remove a trailing newline.
latestTag = sh(returnStdout: true, script: "git describe --tags `git rev-list --tags --max-count=1`").trim()
Keep in mind that you will have to trim the output of all variables that are later use as a part of the next command.
You can try: "git rev-parse ${latestTag}"^${commit}""
You need to add the $ for all variables you want to call

How to pass shell commnds as variables in Jenkins [duplicate]

This question already has answers here:
How do I get the output of a shell command executed using into a variable from Jenkinsfile (groovy)?
(10 answers)
How to execute a command in a Jenkins 2.0 Pipeline job and then return the stdout
(2 answers)
Closed 1 year ago.
I have a command that retrieves my most recent git commit hash.
git rev-parse HEAD
Is it possible to pass this as an environment variable to a Jenkins pipeline stage?
I've tried to do this,
environment {
CURRENT_COMMIT_HASH=`git rev-parse HEAD`
}
but when I echo it in a later stage
stage ('Issues Report') {
steps {
sh '''
echo "${CURRENT_COMMIT_HASH}"
'''
}
}
It comes out blank.
+ echo
This should work
stage ('Stage-Name') {
environment {
current_hash = """${sh(
returnStdout: true,
script: "git rev-parse HEAD"
)}"""
steps {
sh '''
echo "My current commit hash is $current_hash"
'''
}
}

git checkouts many times despite checking out only one-time in Jenkins pipeline

I have a Jenkins pipeline code that has 4 stages viz
1. CHECKOUT <--- git checkout only happens here
2. DEV
3. DEV2
3. DEV3
I do git checkout only in the first stage i.e CHECKOUT
Below is my pipeline code
stages {
stage('checkout') {
steps{
script {
def git_params = checkout([$class: 'GitSCM'])
println "*/${GIT_BRANCH}"
// Loading environment variables
checkout([
$class: 'GitSCM',
branches: [
[name: "*/${GIT_BRANCH}"]
],
extensions: [
[$class: 'WipeWorkspace'],
],
userRemoteConfigs: [[credentialsId: MYAPP_GIT_CREDENTIAL_ID, url: MYAPP_GIT_REPOSITORY]]
])
PIPELINE_NODE = NODE_NAME
dir('temp1'){
checkout([
$class: 'GitSCM',
branches: [
[name: '*/master']
],
userRemoteConfigs: [[credentialsId: MY_GIT_CREDENTIAL_ID, url: MY_GIT_REPOSITORY]]
])
}
stash name: "temp1", includes: "temp1/*"
//Load variable file from GitSCM inorder to get Maven variable
load "temp1/${APP_NAME}_${STARTENV}_EnvFile"
//load "temp1/${APP_NAME}_*_EnvFile"
sh 'chmod 755 temp1/git_version.sh'
env.APP_VERSION = sh(script: "temp1/git_version.sh", returnStdout: true).toString().trim()
sh 'echo REL#=$APP_VERSION'
}
}
}
}
stage('DEV'){
agent any
when {
branch 'develop'
}
steps{
script {
env.APP_VERSION = sh(script: "temp1/git_version.sh", returnStdout: true).toString().trim()
}
}
}
stage('DEV2'){
agent any
when {
branch 'develop2'
}
steps{
script {
env.APP_VERSION = sh(script: "temp1/git_version.sh", returnStdout: true).toString().trim()
}
}
}
stage('DEV3'){
agent any
when {
branch 'develop3'
}
steps{
script {
env.APP_VERSION = sh(script: "temp1/git_version.sh", returnStdout: true).toString().trim()
}
}
}
However, in the output you can see that the checkout can be seen multiple times in the logs when i expected it to show only one time. Although DEV & DEV2 stages are skipped the git checkout gets logged after the skip as you can see in the below output.
......
Stage "DEV" skipped due to when conditional
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (DEV2)
[Pipeline] node
Running on JENKINS_SLAVE5-SLAVE-01 in /apps/jenkins/workspace/ASERVE_release_2.0.4#2
[Pipeline] {
[Pipeline] checkout
The recommended git tool is: /bin/git
using credential JENKINS_CREDEN
Fetching changes from the remote Git repository
Fetching without tags
Checking out Revision a547d4a01537e9869ae3fccc8debf66a9343f723 (release/2.0.4)
Commit message: "VelocityAdapter_Jenkinsfile edited online with Bitbucket"
> /bin/git config remote.origin.url https://bitbucket.mycomp.com/scm/mhmwp/adapter.git # timeout=10
> /bin/git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
> /bin/git config core.sparsecheckout # timeout=10
> /bin/git checkout -f a547d4a01537e9869ae3fccc8debf66a9343f723 # timeout=10
[Pipeline] withEnv
[Pipeline] {
> /bin/git rev-parse --is-inside-work-tree # timeout=10
> /bin/git config remote.origin.url https://bitbucket.mycomp.com/scm/mhmwp/adapter.git # timeout=10
Fetching upstream changes from https://bitbucket.mycomp.com/scm/mhmwp/adapter.git
> /bin/git --version # timeout=10
> git --version # 'git version 1.8.3.1'
using GIT_ASKPASS to set credentials JENKINS_CREDEN
> /bin/git fetch --no-tags --progress https://bitbucket.mycomp.com/scm/mhmwp/adapter.git +refs/heads/*:refs/remotes/origin/* # timeout=10
> /bin/git config core.sparsecheckout # timeout=10
> /bin/git checkout -f a547d4a01537e9869ae3fccc8debf66a9343f723 # timeout=10
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
Stage "DEV2" skipped due to when conditional
........
......
Can you please suggest ?

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}"
}
}

Is it possible to capture the stdout from the sh DSL command in the pipeline

For example:
var output=sh "echo foo";
echo "output=$output";
I will get:
output=0
So, apparently I get the exit code rather than the stdout. Is it possible to capture the stdout into a pipeline variable, such that I could get:
output=foo
as my result?
Now, the sh step supports returning stdout by supplying the parameter returnStdout.
// These should all be performed at the point where you've
// checked out your sources on the slave. A 'git' executable
// must be available.
// Most typical, if you're not cloning into a sub directory
gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
// short SHA, possibly better for chat notifications, etc.
shortCommit = gitCommit.take(6)
See this example.
Note: The linked Jenkins issue has since been solved.
As mention in JENKINS-26133 it was not possible to get shell output as a variable. As a workaround suggested using of writ-read from temporary file. So, your example would have looked like:
sh "echo foo > result";
def output=readFile('result').trim()
echo "output=$output";
Try this:
def get_git_sha(git_dir='') {
dir(git_dir) {
return sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
}
}
node(BUILD_NODE) {
...
repo_SHA = get_git_sha('src/FooBar.git')
echo repo_SHA
...
}
Tested on:
Jenkins ver. 2.19.1
Pipeline 2.4
You can try to use as well this functions to capture StdErr StdOut and return code.
def runShell(String command){
def responseCode = sh returnStatus: true, script: "${command} &> tmp.txt"
def output = readFile(file: "tmp.txt")
if (responseCode != 0){
println "[ERROR] ${output}"
throw new Exception("${output}")
}else{
return "${output}"
}
}
Notice:
&>name means 1>name 2>name -- redirect stdout and stderr to the file name
I had the same issue and tried almost everything then found after I came to know I was trying it in the wrong block. I was trying it in steps block whereas it needs to be in the environment block.
stage('Release') {
environment {
my_var = sh(script: "/bin/bash ${assign_version} || ls ", , returnStdout: true).trim()
}
steps {
println my_var
}
}
A short version would be:
echo sh(script: 'ls -al', returnStdout: true).result
def listing = sh script: 'ls -la /', returnStdout:true
Reference : http://shop.oreilly.com/product/0636920064602.do Page 433

Resources