No such DSL method '$' found among steps - env.CHANGE_BRANCH - jenkins

I have a condition in my groovy file, which checks if env.CHANGE_BRANCH is not equal null. In that case variable branch is set as env.CHANGE_BRANCH, otherwise branch is env.BRANCH_NAME.
When env.CHANGE_BRANCH is null I get a following error:
java.lang.NoSuchMethodError: No such DSL method '$' found among steps
def branch = ""
script {
if (env.CHANGE_BRANCH != null) {
branch = env.CHANGE_BRANCH
} else {
branch = env.BRANCH_NAME
}
echo "Print branch"
}
echo ${branch}

Your echo statement has to be in double quotes for string interpolation to work.
echo "${branch}"
or do
println branch

Related

What will be the groovy syntax to return null as a null object not a string in Jenkins pipeline

BRANCH = "develop"
BRANCH = "${BRANCH=="develop"?"null":"${BRANCH}"}"
print (BRANCH.getClass()) # class org.codehaus.groovy.runtime.GStringImpl
What is the correct syntax for null to be treated as a NUllObject?
Expecting to return class org.codehaus.groovy.runtime.NullObject
As a very minimal example to actually run as a pipeline, you can use this:
pipeline {
agent any
stages {
stage('Hello') {
steps {
script {
def BRANCH = "develop"
BRANCH = "${BRANCH}" == "develop" ? null : "${BRANCH}"
print (BRANCH.getClass())
}
}
}
}
}
The output looks then like this:

JenkinsFile, aproaching to enviroment dependent

I'm new on Jenkins and I don't know how to approach to a multi-environment jenkinsfile.
Note: I'm using multibranch pipeline
Firstly I thought about writing 3 different files of Jenkins, depending of the branch. But, I think there must be another way to do it with only 1 Jenkinsfile which could execute different process depending of the branch you are working on.
Something like:
if branch == 'master' then
procces to do
else if branch == 'test' then
other proccess
else
process for developer branch
edit:
I found that there's the possibility of using env variables. I tried:
echo "$BRANCH_NAME"
echo "$env.BRANCH_NAME"
echo 'BRANCH NAME: ' + env.BRANCH_NAME
echo ${env.BRANCH_NAME}
echo "${env.BRANCH_NAME}"
...
but nothing works.
In Jenkins you use when clauses to define when stages should be run
pipeline {
agent any
stages {
stage("Release if Required") {
when {
anyOf {
branch 'master'
branch 'main'
}
}
steps {
script {
publishRelease()
}
}
}
}
}
If you need to do the check while in the steps you can use the environment vars
script {
if(env.BRANCH_NAME =~ 'master' || env.BRANCH_NAME =~ 'main') {
echo "On the main branch"
}
}
Problem was not using it on script { section.
stage('Checkout code') {
script {
echo "${env.BRANCH_NAME}"
if ("master" == env.BRANCH_NAME) {
do something
...
} else if ("Test" == env.BRANCH_NAME) {
do something
...
} else {
do something
...
}
}

Jenkinsfile when condition that contains branch pattern does not apply

I want by pipeline to run on any branch that matches the pattern alerta/ (and anything beyond the slash (/).
So I have tried the following 2 approaches in terms of Jenkinsfile
expression {
env.BRANCH_NAME ==~ 'alerta\/.*'
}
expression {
env.BRANCH_NAME == '*/alerta/*'
}
both of them have the corresponding stages being skipped.
How should I format my when conditional to meet my purpose?
You forgot to return the state in the expression
expression
Execute the stage when the specified Groovy expression evaluates to
true, for example: when { expression { return params.DEBUG_BUILD } }
Note that when returning strings from your expressions they must be
converted to booleans or return null to evaluate to false. Simply
returning "0" or "false" will still evaluate to "true".
pipeline {
agent any
stages {
stage('alerta-branch'){
when{
expression {
return env.BRANCH_NAME ==~ /alerta\/.*/
}
}
steps {
echo 'run this stage - ony if the branch contains alerta in branch name'
}
}
}
}
This should work for you

Why is this condition in Jenkins pipeline not working?

I am getting mad about the following pipeline code, as it does not do what I expect. Does anyone have an idea what I am doing wrong?
Here is my pipeline code to define the parameter
pipeline {
agent any
parameters { booleanParam(name: 'bForceCheckout', defaultValue: false, description: '') }
...
And here the stage itself
stage('SVN Checkout') {
// Get code from SVN repository
steps {
script {
// If project is not yet checked out, setup checkout structure, i.e. which
// folders will be checked out and which will not be checked out
retry (5) {
try {
def svnInfoError = bat (returnStatus: true, script: "svn info ${projectName}")
// bForceCheckout has to be set as parameter in the job
println "---> " + ((svnInfoError != 0) || bForceCheckout)
if ((svnInfoError != 0) || bForceCheckout) {
println "svnInfoError: " + svnInfoError
println "bForceCheckout: " + bForceCheckout
timeout(activity: true, time: 90, unit: 'MINUTES') {
// Clean up
deleteDir ()
... some SVN related stuff ...
}
}
} catch (Exception ex) {
// Clean up
deleteDir ()
println(ex.toString());
error ("SVN checkout: directory structure could not be set up")
}
}
}
}
}
And here is the console output. As you can see, svnInfoError and bForceCheckout are 0 / false, but the part in the if condition still get executed...
12:51:22
[Pipeline] echo
12:51:22 --->false
[Pipeline] echo
12:51:23 svnInfoError: 0
[Pipeline] echo
12:51:23 bForceCheckout: false
[Pipeline] timeout
12:51:23 Timeout set to expire after 1 hr 30 min without activity
[Pipeline] {
[Pipeline] deleteDir
[Pipeline] bat
12:55:21
Thank you guys, it did turn out to be an issue of the data type.
I also now found the following question leading to the same answer: booleanParam in jenkins dsl
Defining a parameter as follows will still give you a variable of type string.
parameters { booleanParam(name: 'bForceCheckout', defaultValue: false, description: '') }
Checking the data type:
println bForceCheckout.getClass()
...will give you
09:06:03 class java.lang.String
In my opinion this is a bug, so I created a Jenkins issue: https://issues.jenkins-ci.org/browse/JENKINS-57499
For now I ended up changing the code above to the following (yes, I will do some renaming as the variable does not hold a boolean value), and now it works:
if ((svnInfoError != 0) || bForceCheckout.toBoolean()) {
EDIT: I found that actually you should use the following syntax to access parameters and this is working as expected:
if ((svnInfoError != 0) || params.bForceCheckout) {

Jenkinsfile and different strategies for branches

I'm trying to use Jenkins file for all our builds in Jenkins, and I have following problem.
We basically have 3 kind of builds:
pull-request build - it will be merged to master after code review, and if build works
manual pull-request build - a build that does the same as above, but can be triggered manually by the user (e.g. in case we have some unstable test)
an initial continuous deliver pipeline - this will build the code, deploy to repository, install artifacts from repository on the target server and start the application there
How should I contain all of the above builds into a single Jenkinsfile.
Right now the only idea I have is to make a giant if that will check which branch it is and will do the steps.
So I have two questions:
1. Is that appropriate way to do it in Jenkinsfile?
How to get the name of currently executing branch in multi-branch job type?
For reference, here's my current Jenkinsfile:
def servers = ['server1', 'server2']
def version = "1.0.0-${env.BUILD_ID}"
stage 'Build, UT, IT'
node {
checkout scm
env.PATH = "${tool 'Maven'}/bin:${env.PATH}"
withEnv(["PATH+MAVEN=${tool 'Maven'}/bin"]) {
sh "mvn -e org.codehaus.mojo:versions-maven-plugin:2.1:set -DnewVersion=$version -DgenerateBackupPoms=false"
sh 'mvn -e clean deploy'
sh 'mvn -e scm:tag'
}
}
def nodes = [:]
for (int i = 0; i < servers.size(); i++) {
def server = servers.get(i)
nodes["$server"] = {
stage "Deploy to INT ($server)"
node {
sshagent(['SOME-ID']) {
sh """
ssh ${server}.example.com <<END
hostname
/apps/stop.sh
yum -y update-to my-app.noarch
/apps/start.sh
END""".stripIndent()
}
}
}
}
parallel nodes
EDIT: removed opinion based question
You can add If statement for multiple stages if you want to skip multiple stages according to the branch as in:
if(env.BRANCH_NAME == 'master'){
stage("Upload"){
// Artifact repository upload steps here
}
stage("Deploy"){
// Deploy steps here
}
}
or, you can add it to individual stage as in:
stage("Deploy"){
if(env.BRANCH_NAME == 'master'){
// Deploy steps here
}
}
Using this post, this worked for me:
stage('...') {
when {
expression { env.BRANCH_NAME == 'master' }
}
steps {
...
}
}
1) I don't know if it is appropriate, but if it resolves your problem, I think is appropriate enough.
2) In order to know the name of the branch you can use BRANCH_NAME variable, its name is taken from the branch name.
${env.BRANCH_NAME}
Here is the answer:
Jenkins Multibranch pipeline: What is the branch name variable?
We followed the model used by fabric8 for builds, tweaking it as we needed, where the Jenkinsfile is used to define the branch and deployment handling logic, and a release.groovy file for build logic.
Here's what our Jenkinsfile looks like for a pipeline that continuously deploys into DEV from master branch:
#!groovy
import com.terradatum.jenkins.workflow.*
node {
wrap([$class: 'TimestamperBuildWrapper']) {
checkout scm
echo "branch: ${env.BRANCH_NAME}"
def pipeline = load "${pwd()}/release.groovy"
if (env.DEPLOY_ENV != null) {
if (env.DEPLOY_ENV.trim() == 'STAGE') {
setDisplayName(pipeline.staging() as Version)
} else if (env.DEPLOY_ENV.trim() == 'PROD') {
setDisplayName(pipeline.production() as Version)
}
} else if (env.BRANCH_NAME == 'master') {
try {
setDisplayName(pipeline.development() as Version)
} catch (Exception e) {
hipchatSend color: 'RED', failOnError: true, message: "<p>BUILD FAILED: </p><p>Check console output at <a href='${env.BUILD_URL}'>${env.JOB_NAME} [${env.BUILD_NUMBER}]</a></p><p><pre>${e.message}</pre></p>", notify: true, room: 'Aergo', v2enabled: false
throw e; // rethrow so the build is considered failed
}
} else {
setDisplayName(pipeline.other() as Version)
}
}
}
def setDisplayName(Version version) {
if (version) {
currentBuild.displayName = version.toString()
}
}
Note: you can find the code for our global pipeline library here.
Don't know if this what you want..
I prefer because it's look more structured.
Jenkinsfile
node {
def rootDir = pwd()
def branchName = ${env.BRANCH_NAME}
// Workaround for pipeline (not multibranches pipeline)
def branchName = getCurrentBranch()
echo 'BRANCH.. ' + branchName
load "${rootDir}#script/Jenkinsfile.${branchName}.Groovy"
}
def getCurrentBranch () {
return sh (
script: 'git rev-parse --abbrev-ref HEAD',
returnStdout: true
).trim()
}
Jenkinsfile.mybranch.Groovy
echo 'mybranch'
// Pipeline code here
for questions 2 you may be able to do
sh 'git branch > GIT_BRANCH'
def gitBranch = readFile 'GIT_BRANCH'
since you're checking out from git
In my scenarium, I have needed run a stage Deploy Artifactory only if the branch was master(webhook Gitlab), otherwise I couldn't perform the deploy.
Below the code of my jenkinsfile:
stages {
stage('Download'){
when{
environment name: 'gitlabSourceBranch', value: 'master'
}
steps{
echo "### Deploy Artifactory ###"
}
}
}

Resources