JenkinsFile, aproaching to enviroment dependent - jenkins

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

Related

Jenkins multibranch pipeline postbuild only on specific branch (declarative)

How can you create a pipeline that does its stages on every branch, but the postbuild action only on specific branches.
I have seen the when {branch 'production'} option, but it seems to me, that this only works for stage blocks and not for post blocks.
Is there a way to do something like
pipeline {
agent { any }
stages {
stage('build') {
steps {
bat script:"echo build"
}
post {
always {
when {
branch 'production'
}
bat script:"echo publish"
}
}
}
}
}
the if (env.BRANCH_NAME == 'production') seems to be only for scripted pipelines
Conditional post section in Jenkins pipeline has an answer: use script and if inside the post condition.
post {
always {
script {
if (env.BRANCH_NAME == 'production') {
// I have not verified whether your step works here;
// conditional emailext works as expected.
bat script:"echo publish"
}
}
}
}

Using Declarative Jenkins pipeline from SCM - Subversion - How to get svn Url?

This looks like very basic question about Jenkins usage.
I have Jenkinsfile located in root folder of my Subversion repository tree. There are many branches (versions/tags) of the product - everywhere is the same Jenkinsfile. So far very basic setup, I suppose.
I need to provide some steps with current Subversion repository branch/url.
There are some similar questions like this or this, but none is working solution for Subversion.
pipeline {
agent { label 'master' }
stages {
stage("test") {
steps {
echo "Start pipeline "
// commented-out = not working
//echo scm.getUserRemoteConfigs()
//echo scm
script {
println "Current svn url/branch: "//??? + scm.getUserRemoteConfigs()[0].getUrl()
}
}
}
}
}
It will be like this
pipeline {
agent any;
stages {
stage('test'){
steps {
script {
def s = checkout scm;
if (s.GIT_URL != null) {
print s.GIT_URL
print s.GIT_BRANCH
print s.GIT_COMMIT
}
else if (s.SVN_URL != null) {
print s.SVN_REVISION
print s.SVN_REVISION_1
print s.SVN_URL
print s.SVN_URL_1
}
}
}
}
}
}
Note- This works fine with GIT and SVN, but a bit differently.

Jenkins pipeline if else not working

I am creating a sample jenkins pipeline, here is the code.
pipeline {
agent any
stages {
stage('test') {
steps {
sh 'echo hello'
}
}
stage('test1') {
steps {
sh 'echo $TEST'
}
}
stage('test3') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
}
this pipeline fails with following error logs
Started by user admin
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 15: Not a valid stage section definition: "if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}". Some extra configuration is required. # line 15, column 9.
stage('test3') {
^
WorkflowScript: 15: Nothing to execute within stage "test3" # line 15, column 9.
stage('test3') {
^
But when i execute the following example from this url, it executes successfully and print the else part.
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
The only difference i can see is that in the working example there is no stages but in my case it has.
What is wrong here, can anyone please suggest?
your first try is using declarative pipelines, and the second working one is using scripted pipelines. you need to enclose steps in a steps declaration, and you can't use if as a top-level step in declarative, so you need to wrap it in a script step. here's a working declarative version:
pipeline {
agent any
stages {
stage('test') {
steps {
sh 'echo hello'
}
}
stage('test1') {
steps {
sh 'echo $TEST'
}
}
stage('test3') {
steps {
script {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
}
}
}
you can simplify this and potentially avoid the if statement (as long as you don't need the else) by using "when". See "when directive" at https://jenkins.io/doc/book/pipeline/syntax/. you can also validate jenkinsfiles using the jenkins rest api. it's super sweet. have fun with declarative pipelines in jenkins!
It requires a bit of rearranging, but when does a good job to replace conditionals above. Here's the example from above written using the declarative syntax. Note that test3 stage is now two different stages. One that runs on the master branch and one that runs on anything else.
stage ('Test 3: Master') {
when { branch 'master' }
steps {
echo 'I only execute on the master branch.'
}
}
stage ('Test 3: Dev') {
when { not { branch 'master' } }
steps {
echo 'I execute on non-master branches.'
}
}
If you wanted to create a condition to execute only a stage based on expression you can use keyword when
stage ('test3'){
when { expression { return env.BRANCH_NAME == 'master'} }
steps {
echo 'I only execute on the master branch.'
}
}
}
With the expression key word you can add any condition.
e.g. if stage is dependent on generated file in workspace.
stage ('File Dependent stage'){
when { expression { return fileExists ('myfile') } }
steps {
echo "file exists"
}
}
}
if ( params.build_deploy == '1' ) {
println "build_deploy 是 ${params.build_deploy}"
jobB = build job: 'k8s-core-user_deploy', propagate: false, wait: true, parameters: [
string(name:'environment', value: "${params.environment}"),
string(name:'branch_name', value: "${params.branch_name}"),
string(name:'service_name', value: "${params.service_name}"),
]
println jobB.getResult()
}

Cannot define variable in pipeline stage

I'm trying to create a declarative Jenkins pipeline script but having issues with simple variable declaration.
Here is my script:
pipeline {
agent none
stages {
stage("first") {
def foo = "foo" // fails with "WorkflowScript: 5: Expected a step # line 5, column 13."
sh "echo ${foo}"
}
}
}
However, I get this error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: Expected a step # line 5, column 13.
def foo = "foo"
^
I'm on Jenkins 2.7.4 and Pipeline 2.4.
The Declarative model for Jenkins Pipelines has a restricted subset of syntax that it allows in the stage blocks - see the syntax guide for more info. You can bypass that restriction by wrapping your steps in a script { ... } block, but as a result, you'll lose validation of syntax, parameters, etc within the script block.
I think error is not coming from the specified line but from the first 3 lines. Try this instead :
node {
stage("first") {
def foo = "foo"
sh "echo ${foo}"
}
}
I think you had some extra lines that are not valid...
From declaractive pipeline model documentation, it seems that you have to use an environment declaration block to declare your variables, e.g.:
pipeline {
environment {
FOO = "foo"
}
agent none
stages {
stage("first") {
sh "echo ${FOO}"
}
}
}
Agree with #Pom12, #abayer. To complete the answer you need to add script block
Try something like this:
pipeline {
agent any
environment {
ENV_NAME = "${env.BRANCH_NAME}"
}
// ----------------
stages {
stage('Build Container') {
steps {
echo 'Building Container..'
script {
if (ENVIRONMENT_NAME == 'development') {
ENV_NAME = 'Development'
} else if (ENVIRONMENT_NAME == 'release') {
ENV_NAME = 'Production'
}
}
echo 'Building Branch: ' + env.BRANCH_NAME
echo 'Build Number: ' + env.BUILD_NUMBER
echo 'Building Environment: ' + ENV_NAME
echo "Running your service with environemnt ${ENV_NAME} now"
}
}
}
}
In Jenkins 2.138.3 there are two different types of pipelines.
Declarative and Scripted pipelines.
"Declarative pipelines is a new extension of the pipeline DSL (it is basically a pipeline script with only one step, a pipeline step with arguments (called directives), these directives should follow a specific syntax. The point of this new format is that it is more strict and therefore should be easier for those new to pipelines, allow for graphical editing and much more.
scripted pipelines is the fallback for advanced requirements."
jenkins pipeline: agent vs node?
Here is an example of using environment and global variables in a Declarative Pipeline. From what I can tell enviroment are static after they are set.
def browser = 'Unknown'
pipeline {
agent any
environment {
//Use Pipeline Utility Steps plugin to read information from pom.xml into env variables
IMAGE = readMavenPom().getArtifactId()
VERSION = readMavenPom().getVersion()
}
stages {
stage('Example') {
steps {
script {
browser = sh(returnStdout: true, script: 'echo Chrome')
}
}
}
stage('SNAPSHOT') {
when {
expression {
return !env.JOB_NAME.equals("PROD") && !env.VERSION.contains("RELEASE")
}
}
steps {
echo "SNAPSHOT"
echo "${browser}"
}
}
stage('RELEASE') {
when {
expression {
return !env.JOB_NAME.equals("TEST") && !env.VERSION.contains("RELEASE")
}
}
steps {
echo "RELEASE"
echo "${browser}"
}
}
}//end of stages
}//end of pipeline
You are using a Declarative Pipeline which requires a script-step to execute Groovy code. This is a huge difference compared to the Scripted Pipeline where this is not necessary.
The official documentation says the following:
The script step takes a block of Scripted Pipeline and executes that
in the Declarative Pipeline.
pipeline {
agent none
stages {
stage("first") {
script {
def foo = "foo"
sh "echo ${foo}"
}
}
}
}
you can define the variable global , but when using this variable must to write in script block .
def foo="foo"
pipeline {
agent none
stages {
stage("first") {
script{
sh "echo ${foo}"
}
}
}
}
Try this declarative pipeline, its working
pipeline {
agent any
stages {
stage("first") {
steps{
script {
def foo = "foo"
sh "echo ${foo}"
}
}
}
}
}

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