How to create Array for branches in Jenkins Groovy - jenkins

How to create an Array after git branch -r.
my goal is I want to delete/clean up all branches, which are older than 2 months.
so my Jenkisn Script looks like this:
pipeline {
agent { label "base" }
stages {
stage('Get All Branches') {
steps{
withCredentials([usernamePassword(credentialsId: "${config.git.credentialsId}", usernameVariable: 'GITUSER', passwordVariable: 'GITPASSWD')]) {
// test -d "./.git" && git fetch || git clone -n http://$GITUSER:$GITPASSWD#${srcurl} .
sh """
test -d "./.git" && git fetch || git clone -n gitRepo .
git branch -r --sort=-committerdate > .git/branchesList
"""
}
}
}
stage('show branches'){
steps{
branchesList = readFile(".git/branchesList").trim()
echo branchesList // this line I want to get all branches
// the Question is How to create an Array from branchesList
}
}
}
}
Any solutions?

You can readfile in Jenkins using : readFile(file: '<Filepath>').
stage('show branches'){
steps{
// Define Array containing branches
def BRANCHES = []
// Give your path of file. Please change the path according to your requirements
def branchesList = readFile(file: 'C:\\Data\\.git\\branchesList.txt')
// I assumed your file contains one branch per line, that is why i split with "\n".
// You can change this line as per your condition
BRANCHES = branchesList.split("\n")
for (branch in BRANCHES){
println ("Branch is : ${branch}")
}
}

Related

jenkins pipeline : when condition and mercurial tags

I am trying to run the last step of my jenkins build (deploy) only if the current revision has been tagged with a version number.
I tried to follow the following example but it is only for GIT.
Here is what I have setup:
Jenkins polls my repository and pull the jenkinsfile from it
The following jenkinsfile is executed
// --- Get sources from mercurial ---
stage ('Checkout') {
steps {
bat "Hg purge --config extensions.purge= --all --print"
checkout([$class: 'MercurialSCM', credentialsId: '', revision: 'default', source: 'MY_REPO'])
}
}
// --- BUILD ---
stage ('Build') {
// my build
}
// --- DEPLOY MASTER ---
stage ('Deploy') {
when { tag "release*" }
steps {
bat "\"${env.WORKSPACE}\\jenkins\\deploy.bat\" \"M:\\dev-FU4\""
}
}
Unfortunately, the deploy part is ignored each time...
Screenshot of the build:
The problem seems to be the following :
Mercurial tags are indeed a commit with a line added in the .hgtags file
When I pull the revision that will be tagged, it is not deployed as there is no tag yet
When I pull the revision with the "tag commit", it is not beeing deployed, ad the tag refer to an older revision.
Do you have any idea about how to do this ?
Sorry for the bothering guys, I have figured it out.
I have added :
A step that determine if the commit is a mercurial tag.
A step that update to the tag revision, if the tag begins with "release"
The variable ${hgTagVersion} is available to use for whichever script will need it.
Here are the sources:
// Pipeline stages
stages {
// --- Get sources from mercurial ---
stage ('Checkout') {
steps {
bat "Hg purge --config extensions.purge= --all --print"
checkout([$class: 'MercurialSCM', credentialsId: '', revision: 'default', source: 'MY_REPO'])
}
}
stage ('Deployment determination') {
steps {
// Determine if Deploy is needed
script {
HG_LATEST_DESC = bat (
script: '#echo off & hg log --template {desc} --limit 1',
returnStdout: true
).trim()
// dummy test of a tag commit
// HG_LATEST_DESC = "Added tag release-test for changeset 1dcf7a76d27c"
deployIsNeeded = false
hgTag = ""
hgChgSet = ""
hgTagVersion = ""
hgsplit = HG_LATEST_DESC.split("Added tag ")
if (hgsplit.length == 2)
{
hgsplit = hgsplit[1].split(" for changeset ")
if(hgsplit.length == 2)
{
hgTag = hgsplit[0]
hgChgSet = hgsplit[1]
if(hgTag.contains("release-"))
{
deployIsNeeded = true;
hgTagVersion = hgTag.split("release-")[1]
}
}
}
if (deployIsNeeded)
{
println "Deploy is needed. Hg will checkout to tag and master will be deployed."
println "HG tag: ${hgTag}"
println "HG changeset: ${hgChgSet}"
println "Deploy version: ${hgTagVersion}"
}
else
{
println "Deploy is not needed. Build will remain local."
}
}
}
}
// --- Checkout to deploy tag ---
stage ('Deploy tag checkout')
{
when { expression { return deployIsNeeded; } }
steps {
bat "hg update --clean --rev ${hgChgSet}"
}
}
// --- BUILD ---
stage ('Build') {
// my build steps
}
// --- DEPLOY MASTER ---
stage ('Deploy') {
when { expression { return deployIsNeeded; } }
steps {
// my deployment script
}
}
}
Here is the pipeline viewed from blueocean when there is no need to deploy:
And when deploy is needed:

jenkins Pipeline Script: How to get the return value from shell script

I have a jenkins pipeline where I am executing different scripts at different stages. However in one stage I want to get the output of the stage to a variable where I want to pass that variable as an input to next stage . Here is my code in Jenkinsfile
timestamps
{
node('cf_slave')
{
checkout scm
stage('Download HA image from GSA')
{
withCredentials(usernamePassword(credentialsId: 'ssc4icp_GSA', usernameVariable: 'GSA_USERNAME', passwordVariable: 'GSA_PASSWORD')
{
environment {
script {
OUTPUT = """${sh(
returnStdout: true,
script: 'bash jenkins/try_install.sh $VAR_ABC'
)}"""
echo $OUTPUT
}
}
}
}
}
}
Here i am getting syntax error. I want to get the OUTPUT in OUTPUT variable and pass that to next stage. Please help me how to do that in a correct way
When referencing variable outside of a string you should not us a dollar sign ($). The code should be (including changes suggested by Matt):
timestamps
{
node('cf_slave')
{
checkout scm
stage('Download HA image from GSA')
{
withCredentials(usernamePassword(credentialsId: 'ssc4icp_GSA', usernameVariable: 'GSA_USERNAME', passwordVariable: 'GSA_PASSWORD'))
{
environment {
script {
OUTPUT = sh returnStdout: true,
script: "bash jenkins/try_install.sh $VAR_ABC"
echo OUTPUT
}
}
}
}
}
}

Is it possible to check if checked out from a specific repository in a Jenkins declarative pipeline?

I would like to have a release stage in my Jenkinsfile that only runs when it's checked out from the original repository. This is to avoid error messages on cloned repositories, because of missing keys etc. there.
stage('Release')
{
when
{
allOf
{
// TODO Check for repository url https://github.com/PowerStat/TemplateEngine.git
branch 'master'
}
}
steps
{
script
{
if (isUnix())
{
sh 'mvn --batch-mode release:clean'
sh 'mvn --batch-mode release:prepare'
sh 'mvn --batch-mode release:perform'
}
else
{
bat 'mvn --batch-mode release:clean'
bat 'mvn --batch-mode release:prepare'
bat 'mvn --batch-mode release:perform'
}
}
}
}
I have studied Pipeline Syntax: when but have no idea how to do the test I would like to have.
Also I thought about using an environment variable Global Variable Reference, but found non with the repository URL in it.
So my question is: how to implement this check in a decalarative pipeline?
You can get remote repository URL from git config remote.origin.url command. You can execute this command using expression directive inside the when block - it defines a closure that returns a boolean value.
Consider the following example:
def expectedRemoteUrl = "https://github.com/PowerStat/TemplateEngine.git"
pipeline {
agent any
stages {
stage("Release") {
when {
allOf {
branch 'tmp'
expression {
def remoteUrl = isUnix() ?
sh(script: "git config remote.origin.url", returnStdout: true)?.trim() :
bat(script: "git config remote.origin.url", returnStdout: true)?.trim()
return expectedRemoteUrl == remoteUrl
}
}
}
steps {
echo "Do your release steps here..."
}
}
}
}
Alternatively, if git command is not available in the node that runs the pipeline, you can get the remote repository URL with scm.userRemoteConfigs?.first()?.url. Consider the following example:
def expectedRemoteUrl = "https://github.com/PowerStat/TemplateEngine.git"
pipeline {
agent any
stages {
stage("Release") {
when {
allOf {
branch 'tmp'
expression {
def remoteUrl = scm.userRemoteConfigs?.first()?.url
return expectedRemoteUrl == remoteUrl
}
}
}
steps {
echo "Do your release steps here..."
}
}
}
}

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

Get username logged in Jenkins from Jenkins Workflow (Pipeline) Plugin

I am using the Pipeline plugin in Jenkins by Clouldbees (the name was Workflow plugin before), I am trying to get the user name in the Groovy script but I am not able to achieve it.
stage 'checkout svn'
node('master') {
// Get the user name logged in Jenkins
}
Did you try installing the Build User Vars plugin? If so, you should be able to run
node {
wrap([$class: 'BuildUser']) {
def user = env.BUILD_USER_ID
}
}
or similar.
To make it work with Jenkins Pipeline:
Install user build vars plugin
Then run the following:
pipeline {
agent any
stages {
stage('build user') {
steps {
wrap([$class: 'BuildUser']) {
sh 'echo "${BUILD_USER}"'
}
}
}
}
}
Here's a slightly shorter version that doesn't require the use of environment variables:
#NonCPS
def getBuildUser() {
return currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId()
}
The use of rawBuild requires that it be in a #NonCPS block.
It is possible to do this without a plugin (assuming JOB_BASE_NAME and BUILD_ID are in the environment):
def job = Jenkins.getInstance().getItemByFullName(env.JOB_BASE_NAME, Job.class)
def build = job.getBuildByNumber(env.BUILD_ID as int)
def userId = build.getCause(Cause.UserIdCause).getUserId()
There is also a getUserName, which returns the full name of the user.
This works for me without the Build User plugin:
// get first entry of JSONArray
def buildCause = currentBuild.getBuildCauses()[0]
def buildPrincipal = [type:"unknown", name:""]
if (buildCause._class ==~ /.+BranchEventCause/) {
def branchCause = currentBuild.getRawBuild().getCause(jenkins.branch.BranchEventCause)
buildPrincipal = [type:"branch",name:buildCause.shortDescription]
} else
if (buildCause._class ==~ /.+TimerTriggerCause/) {
def timerCause = currentBuild.getRawBuild().getCause(hudson.triggers.TimerTrigger.TimerTriggerCause)
buildPrincipal = [type:"timer", name:"Timer event"]
} else
if (buildCause._class ==~ /.+UserIdCause/) {
def buildUserCause = currentBuild.getRawBuild().getCause(hudson.model.Cause.UserIdCause)
buildPrincipal = [type:"user", name:buildCause.userId]
} else
// ... other causes
def jobUserId, jobUserName
//then somewhere
wrap([$class: 'BuildUser']) {
jobUserId = "${BUILD_USER_ID}"
jobUserName = "${BUILD_USER}"
}
//then
println("Started By: ${jobUserName}")
We were using this plugin : Build User Vars Plugin. More variables are available.
//Below is a generic groovy function to get the XML metadata for a Jenkins build.
//curl the env.BUILD_URL/api/xml parse it with grep and return the string
//I did an or true on curl, but possibly there is a better way
//echo -e "some_string \c" will always return some_string without \n char
//use the readFile() and return the string
def GetUserId(){
sh """
/usr/bin/curl -k -s -u \
\$USERNAME:\$PASSWORD -o \
/tmp/api.xml \
\$BUILD_URL/api/xml || true
THE_USERID=`cat /tmp/api.xml | grep -oP '(?<=<userId>).*?(?=</userId>)'`
echo -e "\$THE_USERID \\c" > /tmp/user_id.txt
"""
def some_userid = readFile("/tmp/user_id.txt")
some_userid
}
I modified #shawn derik response to get it to work in my pipeline:
stage("preserve build user") {
wrap([$class: 'BuildUser']) {
GET_BUILD_USER = sh ( script: 'echo "${BUILD_USER}"', returnStdout: true).trim()
}
}
Then I can reference that variable later on by passing it or in the same scope as ${GET_BUILD_USER} . I installed the same plugin referenced.
Edit: I re-read the question - the below only gets you the user running the build (which technically is often more interesting), not the one triggering the build in the frontend (be it REST-API or WebUI).
If you have Jenkins impersonation enabled, then I believe the result should be equivalent, otherwise this will only get you the user who owns the jenkins agent on the build machine.
Original answer:
Another way would be to
sh 'export jenkins_user=$(whoami)'
Downside: Linux-dependent, difficult to port across multiple agents in a single build (but then, the auth context may be different on each slave)
Upside: No need to install plugins (which on shared/large Jenkins instances can be tricky)
The Build User Vars Plugin is useful when you are executing the stage on an agent.
The alternative is to use the current build clause (see https://code-maven.com/jenkins-get-current-user), which also works when your stage is set with agent none.
The following code is inspired by Juergen's solution but I added more possible trigger reason and display them in a formatted manner:
String getTriggerReason() {
def buildCause = currentBuild.getBuildCauses()[0]
if (buildCause._class ==~ /.+(BranchEventCause|BranchIndexingCause)/) {
if (env.JOB_BASE_NAME == 'master') {
return 'Triggered by master commit'
} else {
return "Triggered by ${buildCause.shortDescription}"
}
}
if (buildCause._class ==~ /.+TimerTriggerCause/) {
return 'Triggered by timer'
}
if (buildCause._class ==~ /.+BuildUpstreamCause/) {
return "Triggered by build #${buildCause.upstreamBuild}"
}
if (buildCause._class ==~ /.+UserIdCause/) {
def userName = buildCause.userName.replaceFirst(/\s?\(.*/, '')
return "Triggered by user ${userName}"
}
return 'Unknown trigger'
}

Resources