I want to enable deployment only from the branch names(starting with hotfix and master). How can I do that? - jenkins-pipeline

I am writing a Jenkinsfile and trying to enable deployment from the branch names(starting with master and hotfix). How can I do that? Below is my groovy code. This works if I specify only one branch. How can I do that for multiple branches?
// Create and Deploy to STAGE Environment
stage ('Create and Deploy to k8s stage Environment') {
when {
allOf {
expression {
branch_name.startsWith('master')
}
}
}
options {
skipDefaultCheckout()
}
steps {
withCredentials([string(credentialsId: "$env.K8S_STAGE_NS_TOKEN" , variable: 'STAGE_TOKEN')]) {
kubernetesDeploy(hcEnv: 'stage', hcToken: "${STAGE_TOKEN}")
}
}
}
The below code doesn't work if I specify 2 branch names but the above one works.
// Create and Deploy to PROD Environment
stage ('Create and Deploy to k8s production Environment') {
when {
allOf {
expression {
branch_name.startsWith('hotfix')
branch_name.startsWith('master')
}
}
}
options {
skipDefaultCheckout()
}
steps {
withCredentials([string(credentialsId: "$env.K8S_PROD_NS_TOKEN" , variable: 'PROD_TOKEN')]) {
kubernetesDeploy(hcEnv: 'prod', hcToken: "${PROD_TOKEN}")
}
}
}

You can use this
expression { return (env.GIT_BRANCH.startsWith('origin/master') || env.GIT_BRANCH.startsWith('hotfix'))}
OR
you can also try this
expression { return (env.BRANCH_NAME.startsWith('origin/master') || env.GIT_BRANCH.startsWith('origin/hotfix'))}
I am not sure if your branch name starts with origin or without origin so use it according to you. I would suggest instead of startsWith use contains.
Also instead of allOf i guess you need anyOf because you want to run stage for either if it's master branch or hotfix branch and both at the same time can't be true so

Related

How to avoid building twice in a Jenkinsfile in order to have different image names?

In our project, we append the branch name when we build, unless it's master. And we tag them with the build_id and "latest". This is what we want.
- myapp:latest
- myapp:1
- myapp:2
- myapp:3
- myapp-branch-x:latest
- myapp-branch-x:1
- myapp-branch-x:2
- myapp-branch-x:3
- myapp-branch-y:latest
- myapp-branch-y:1
- myapp-branch-y:2
- myapp-branch-y:3
In order to achieve this, we are building twice when it's on the master branc. I think it's weird. How can we avoid that?
pipeline {
environment {
dockerCredentials = 'myapp-dockerhub'
dockerRegistryUrl = 'https://dockerhub.example.com'
imageName = "dockerhub.example.com/myapp/myapp"
build_id = "${BUILD_ID}"
branch_name = "${BRANCH_NAME.toLowerCase().replace('-$', '')}"
app = ''
}
agent any
stages {
stage('Build') {
steps {
script {
app = docker.build(imageName + '-' + branch_name)
withDockerRegistry(credentialsId: dockerCredentials, url: dockerRegistryUrl) {
app.push(build_id)
app.push('latest')
}
}
}
}
stage('Build-Master') {
when {
branch 'master'
}
steps {
script {
app = docker.build(imageName)
withDockerRegistry(credentialsId: dockerCredentials, url: dockerRegistryUrl) {
app.push(build_id)
app.push('latest')
}
}
}
}
}
}
Currently the first stage executes for all situations, and the second stage executes only on the master branch according to the when expression when { branch 'master' }. You can add a when expression to the first stage to only build non-master branches. Then the master branch will not execute for both stages:
stage('Build') {
when { not { branch 'master' } }
...
}
You can check the when expression documentation for more information.

Getting a jenkinsfile stage to run on master branch and tag

I tried to get a stage to run when user push to master branch or push a tag to origin. This is the when condition that i set in the stage:
when {
expression {
branch 'master' || tag 'v*'
}
}
It throws an error that No such field found: field org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable v*. Is there another way to do a conditional expression in such a way that it works?
I have a Jenkinsfile to automate the process to build a docker image and push it to the docker registry. In this example the docker image is build when someone push a tag in master branch:
stage('Master Docker Prepare') {
when {
expression {
return (env.BRANCH_NAME=="master" && env.GIT_TAG!=null && env.GIT_TAG != '')
}
}
steps {
echo 'Deploying'
script {
dockerImage = docker.build DOCKER_REGISTRY_PUT+"/"+DOCKER_IMAGE + ":" + env.GIT_TAG
}
script {
docker.withRegistry( 'http://'+DOCKER_REGISTRY_PUT, DOCKER_REGISTRY_CREDENTIAL ) {
dockerImage.push()
}
}
}
}
I think you can make something similar.
Use anyOf inside when as shown below
when {
anyOf {
branch 'master'
expression { tag =~ 'v*' }
}
}

Is there a way to move the entire post {} build section in Jenkinsfile to the global pipeline library?

I'm relatively new to Jenkins pipelines, but having implemented already a few, I've realised I need to start using jenkins shared library before I go mad.
Have already figured out how to define some repetitive steps in the library and call them with less clutter from Jenkinsfile, but not sure if the same thing can be done for the entire post build section (thought I've read about to how to define the entire pipeline in the lib and similar), as this is pretty much static end of every single pipeline code:
#Library('jenkins-shared-library')_
pipeline {
agent none
stages {
stage ('System Info') { agent any
steps { printSysInfo() }
}
stage ('Init'){ agent {label 'WinZipSE'}
steps { init('SCMroot') }
}
stage('Build') { agent any
steps { doMagic() }
}
}
// This entire 'post {}' section needs to go to a shared lib
// and be called just with a simple methed call, e.g.
// doPostBuild()
post {
always {
node ('master') {
googlechatnotification (
message: '[$BUILD_STATUS] Build $JOB_NAME $BUILD_NUMBER has finished',
url: 'id:credential_id_for_Ubuntu')
step (
[$class: 'Mailer',
recipients: 'sysadmins#example.com me#example.com',
notifyEveryUnstableBuild: true,
sendToIndividuals: true]
)
}
}
success {
node ('master') {
echo 'This will run only if successful'
}
}
failure {
node ('master') {
echo 'This will run only if failed'
}
}
// and so on
}
}
I just dunno how to syntactically achieve that. For sure, I can define the entire post build section an a lib/var like: doPotBuild.groovy
def call () {
post {...}
}
but how I will eventually call it from within my Jenkinsfile outside of that defined post {} build block section (AKA stages).
I can call it within some stage('post build){doPostBuild()}, but it won't serve the way how the true post {} section is supposed to work, e.g. it won't get executed it there was failure in one of the previous stages.
Any thoughts on that and mainly working examples?
I am not entirely if this will work as I don't use declarative pipelines, so am unsure how rigid the top level structure is. But I would revert to a script block.
#Library('jenkins-shared-library')_
pipeline {
agent none
stages {
stage ('System Info') { agent any
steps { printSysInfo() }
}
stage ('Init'){ agent {label 'WinZipSE'}
steps { init('SCMroot') }
}
stage('Build') { agent any
steps { doMagic() }
}
}
// This entire 'post {}' section needs to go to a shared lib
// and be called just with a simple methed call, e.g.
// doPostBuild()
script {
doPostBuild()
}
}

How can I define multiple agents in declarative jenkinsfile?

In my Jenkinsfile I want a particular stage to run on both the agents in parallel.for example:
stage('abc'){
agent {
label "dev6" && "dev7"
}
steps {
xyz()
}
}
I have two slaves with label dev6 and dev7. I want xyz() to start on both the agents dev6 and dev7 at same time parallely. What is the correct way to do it? Do i need parallel block ? from the above code it just starts the functions on one of dev6 or dev7. I tried with
label "dev6 || dev7"
label "dev6 && dev7"
but it doenst work. Can someone help??
Thanks
You need parallel on level of stages, the reason for that is actually you want this to run twice on separate agents. Unless I misunderstood you.
pipeline {
agent none
stages {
stage('Test') {
parallel {
stage('Test On dev6') {
agent {
label "dev6"
}
steps {
xyz()
}
}
stage('Test On dev7') {
agent {
label "dev7"
}
steps {
xyz()
}
}
}
}
}

exit declarative pipeline prematurely based on script output

While I am aware of this question clean way to exit declarative Jenkins pipeline as success I am to green to understand how to put it to use (from where does the skipBuild variable come?).
I have a script that determines whether the pipeline should continue or not but I am unsure how to piece it together (I am free to construct the script as needed).
pipeline {
agent {
docker { image 'python:3-alpine' }
}
stage('Should I continue') {
steps {
python should_i_continue.py
}
when { ? == true }
stages {
...
}
}
}
I am aware that the capabilities increase tenfold if I use a scripted pipeline but I wonder if it is possible to do what I want with a declarative one?
You can use any custom variable, which you will set as true|false based on some condition in the steps of your pipeline and all stages that need to be executed based on that condition have to have following format:
stage('Should Continue?') {
setBuildStatus("Build complete", "SUCCESS");
when {
expression {skipBuild == true }
}
}
In other words to provide you a bit clean picture, check this abstract example:
node {
skipBuild = false
stage('Checkout') {
...
your checkout code here
...
}
stage('Build something') {
...
some code goes here
skipBuild = true
...
}
stage('Should Continue?') {
setBuildStatus("Build complete", "SUCCESS");
when {
expression {skipBuild == true }
}
}
}

Resources