Ravindra BagaleCourses & study guides मराठी

Chapter 24: Jenkins with GitHub, GitLab and Bitbucket

24.4 Multibranch

Why: the problem

Think of Paytm. The payments repo has main, release/2.4, and twenty feature branches like feature/upi-qr. If you make one Jenkins job per branch by hand, you spend the day clicking. And when a branch is deleted, its job stays and confuses people. A Multibranch Pipeline fixes this. You make one job and point it at the repo. Jenkins scans the repo, finds every branch that has a Jenkinsfile, and makes a child job for each one by itself. A new branch gets a job on the next scan. Inside the Jenkinsfile you can use the BRANCH_NAME variable to do different things, for example deploy only from main. In this lesson you will make one Multibranch job and watch it grow.

What we will build

You will push menu-api with three branches: main, develop and feature/badge-color. You will create one Multibranch Pipeline job called menu-api-mb, scan the repo and see three child jobs. Then you will write one Jenkinsfile that tests on every branch, builds a Docker image on develop and main, and deploys only from main. Finally you will add a new branch and see Jenkins pick it up by itself.

What: every term in plain English

  • Multibranch Pipeline — A Jenkins job type that makes one child job for each branch that has a Jenkinsfile.
  • Branch source — The repo setting in a Multibranch job: which host, which repo, which credential.
  • Scan — Jenkins lists all branches and checks which ones have a Jenkinsfile.
  • Child job — The job Jenkins makes for one branch, like menu-api-mb/main.
  • BRANCH_NAME — A variable Jenkins sets in each child job, for example develop.
  • when { branch } — A Jenkinsfile rule. The stage runs only on the branch you name.
  • Discover branches — A behaviour setting. It tells Jenkins which branches to look for.
  • Folder URL encoding — A slash in a branch name becomes %2F in the URL, like feature%2Fbadge-color.
Create branches Create the Multibranch job Add the branch source Pick discover behaviours Save and scan Open the child jobs Add a new branch
Multibranch: one job, one child per branch

How: step by step

  1. Create branches

    git checkout -qb develop && git push -u gl develop && git checkout -qb feature/badge-color && git push -u gl feature/badge-color && git checkout -q main
    

    What it does: Three branches, all with the same Jenkinsfile.

    Output

    * [new branch]      develop -> develop
     * [new branch]      feature/badge-color -> feature/badge-color
    
  2. Create the Multibranch job

    New Item > menu-api-mb > Multibranch Pipeline > OK
    

    What it does: One job for the whole repo.

    Output

    Job menu-api-mb created
    
  3. Add the branch source

    Branch Sources > Add source > GitLab Project > Server gitlab.com > credential gl-read > owner shop-food > project menu-api
    

    What it does: Tells Jenkins where to scan.

    Output

    Projects: menu-api
    
  4. Pick discover behaviours

    Discover branches: All branches. Script Path: Jenkinsfile
    

    What it does: Jenkins will look for a Jenkinsfile on every branch.

    Output

    (saved)
    
  5. Save and scan

    Save > Scan Multibranch Pipeline Now
    

    What it does: Jenkins reads all branches.

    Output

    Checking branch main
      Jenkinsfile found
    Checking branch develop
      Jenkinsfile found
    Checking branch feature/badge-color
      Jenkinsfile found
    Finished: SUCCESS
    
  6. Open the child jobs

    http://localhost:8080/job/menu-api-mb/
    

    What it does: Three child jobs, each with its own build history.

    Output

    main  #1  green
    develop  #1  green
    feature/badge-color  #1  green
    
  7. Add a new branch

    git checkout -qb feature/menu-search && git push -u gl feature/menu-search
    

    What it does: On the next scan or hook, a fourth child job appears.

    Output

    * [new branch]      feature/menu-search -> feature/menu-search
    

Example 1: One Jenkinsfile that behaves by branch

Stack. Node.js, Docker, Multibranch

Goal. One Jenkinsfile that behaves by branch.

Jenkinsfile

pipeline {
  agent any
  environment { IMAGE = "shopfood/menu-api:${env.BRANCH_NAME.replace('/','-')}-${env.BUILD_NUMBER}" }
  stages {
    stage('Test') {
      steps { sh 'npm ci || npm install'; sh 'npm test' }
    }
    stage('Image') {
      when { anyOf { branch 'main'; branch 'develop' } }
      steps { sh 'docker build -t $IMAGE .' }
    }
    stage('Deploy') {
      when { branch 'main' }
      steps { sh 'echo deploying $IMAGE to production' }
    }
  }
}

What each line does

  • env.BRANCH_NAME.replace('/','-') — Docker tags cannot have a slash. feature/badge-color becomes feature-badge-color.
  • stage('Test') — No when rule, so it runs on every branch.
  • when { anyOf { branch 'main'; branch 'develop' } } — Build an image only on main and develop.
  • when { branch 'main' } — Deploy only from main.
  • sh 'docker build -t $IMAGE .' — Single quotes: the shell reads IMAGE from the environment.

Green output

menu-api-mb/feature%2Fbadge-color #1
[Pipeline] stage (Test)       menu ok
[Pipeline] stage (Image)      Stage "Image" skipped due to when conditional
[Pipeline] stage (Deploy)     Stage "Deploy" skipped due to when conditional
Finished: SUCCESS

menu-api-mb/main #1
[Pipeline] stage (Image)      Successfully tagged shopfood/menu-api:main-1
[Pipeline] stage (Deploy)     deploying shopfood/menu-api:main-1 to production
Finished: SUCCESS

Expected result. Feature branches only test. main tests, builds and deploys. One file, no copy jobs.

Example 2: Make the Multibranch job as code with Job DSL, so it is not lost

Stack. Job DSL plugin

Goal. Make the Multibranch job as code with Job DSL, so it is not lost.

seed/menu_api_mb.groovy

multibranchPipelineJob('menu-api-mb') {
  branchSources {
    branchSource {
      source {
        git {
          id('menu-api-gl')
          remote('https://gitlab.com/shop-food/menu-api.git')
          credentialsId('gl-read')
        }
      }
    }
  }
  factory { workflowBranchProjectFactory { scriptPath('Jenkinsfile') } }
  triggers { periodicFolderTrigger { interval('5m') } }
  orphanedItemStrategy { discardOldItems { numToKeep(10) } }
}

What each line does

  • multibranchPipelineJob('menu-api-mb') — Job DSL makes the Multibranch job from code.
  • git { remote(...) credentialsId('gl-read') } — Plain Git source. Works with any host.
  • scriptPath('Jenkinsfile') — Where the Jenkinsfile is in each branch.
  • periodicFolderTrigger { interval('5m') } — Scan every 5 minutes if no webhook. Honest on a laptop.
  • orphanedItemStrategy — Delete old child jobs for deleted branches. Lesson 24.6 goes deeper.

Green output

Processing DSL script seed/menu_api_mb.groovy
Added items:
    GeneratedJob{name='menu-api-mb'}
Finished: SUCCESS
Scan Multibranch Pipeline Triggered
Checking branches...
  3 branches were processed

Expected result. Run the seed job and the Multibranch job appears, the same every time.

Example 3: Java Spring Boot repo: run slow integration tests only on release branches

Stack. Java 17, Maven, Multibranch

Goal. Java Spring Boot repo: run slow integration tests only on release branches.

Jenkinsfile

pipeline {
  agent { docker { image 'maven:3.9-eclipse-temurin-17' } }
  stages {
    stage('Unit tests') { steps { sh 'mvn -B -ntp test' } }
    stage('Integration tests') {
      when { branch pattern: 'release/.*', comparator: 'REGEXP' }
      steps { sh 'mvn -B -ntp verify -Pintegration' }
    }
    stage('Package') {
      when { anyOf { branch 'main'; branch pattern: 'release/.*', comparator: 'REGEXP' } }
      steps {
        sh 'mvn -B -ntp -DskipTests package'
        archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
      }
    }
  }
}

What each line does

  • image 'maven:3.9-eclipse-temurin-17' — Maven and Java 17 inside a container.
  • branch pattern: 'release/.*', comparator: 'REGEXP' — Match any branch that starts with release/.
  • mvn -B -ntp verify -Pintegration — Runs the integration test profile. Slow, so only for release branches.
  • archiveArtifacts ... fingerprint: true — Keeps the jar on the build page.

Green output

payment-api-mb/release%2F2.4 #3
[Pipeline] stage (Unit tests)          Tests run: 84, Failures: 0
[Pipeline] stage (Integration tests)   Tests run: 12, Failures: 0
[Pipeline] stage (Package)             Archiving artifacts
Finished: SUCCESS

Expected result. Feature branches finish in 2 minutes. Release branches take 9 minutes but run every test.

Verify: did it work?

  1. List child jobs with the API

    curl -s -u ravi:$JENKINS_TOKEN "http://localhost:8080/job/menu-api-mb/api/json?tree=jobs[name,color]" | jq -r ".jobs[] | .name + \" \" + .color"
    

    What it does: Shows every branch job and its colour.

    Output

    develop blue
    feature%2Fbadge-color blue
    feature%2Fmenu-search blue
    main blue
    
  2. Read the scan log

    http://localhost:8080/job/menu-api-mb/indexing/console
    

    What it does: Shows which branches Jenkins found and why.

    Output

    Checking branch feature/menu-search
      Jenkinsfile found
      Met criteria
    Scheduled build for branch: feature/menu-search
    

When it is red 1

Checking branch develop
  'Jenkinsfile' not found
    Does not meet criteria

Cause. That branch has no Jenkinsfile, or it has a different name or path.

Fix, step by step

  1. Run git ls-tree develop --name-only.
  2. Merge main into develop to get the Jenkinsfile.
  3. Check Script Path.

When it is red 2

groovy.lang.MissingPropertyException: No such property: BRANCH_NAME

Cause. You used BRANCH_NAME in a normal Pipeline job. It is set only in Multibranch jobs.

Fix, step by step

  1. Use env.BRANCH_NAME ?: "main" for safety.
  2. Or move the job to Multibranch.

When it is red 3

ERROR: [Errno] invalid reference format: repository name must be lowercase / tag has a slash

Cause. The image tag uses the raw branch name with a slash.

Fix, step by step

  1. Use BRANCH_NAME.replace("/","-").
  2. Use toLowerCase() too if branches have capital letters.

Cleanup

  1. Delete the lab branch

    git push gl --delete feature/menu-search && git branch -D feature/menu-search
    

    What it does: Next scan marks its job as orphaned.

    Output

    To https://gitlab.com/shop-food/menu-api.git
     - [deleted]         feature/menu-search
    
  2. Rescan

    Scan Multibranch Pipeline Now
    

    What it does: Jenkins updates the child job list.

    Output

    1 orphaned item(s) will be removed
    

Ravindra Bagale's Tip

Ek job, saglya branches. Deploy fakt main varun. Lakshat theva!

Practice tasks

Easy Count the child jobs

Why: You must know what Jenkins found.

What to do: Scan and list all child jobs with the API call.

How:
  1. Run the curl from Verify.

Check: Count matches git branch -r.

Medium Add a develop-only stage

Why: Teams often deploy develop to a test server.

What to do: Add a stage that runs only on develop.

How:
  1. when { branch 'develop' }

Check: Only the develop child runs it.

Hard Seed the job with Job DSL

Why: Clicked jobs get lost. Code jobs can be rebuilt.

What to do: Make the Multibranch job from a Job DSL seed.

How:
  1. Install Job DSL.
  2. Run the seed job.

Check: Deleting and reseeding gives the same job.

Easy Say Multibranch Pipeline in two lines

Why: If you can say it simply, you understand it. Juniors and interviewers both want the short version first.

What to do: Write two short lines about Multibranch Pipeline for a fresher who knows only Linux and Git basics.

How:
  1. Write the problem it solves.
  2. Write the one Jenkinsfile step or command you use for it.
  3. Read it aloud to a friend.

Check: A fresher understands it without asking a question.

Easy Start a fresh lab Jenkins

Why: Practice needs a throwaway Jenkins. If you break it, you delete it and start again.

What to do: Run Jenkins LTS in Docker with a named volume.

How:
  1. docker volume create jenkins_home
  2. docker run -d --name jenkins -p 8080:8080 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk17
  3. docker logs jenkins 2>&1 | grep -A2 "initialAdminPassword"

Check: The Jenkins login page opens on localhost:8080.

Medium Do it on the second setup

Why: A release idea must work on a VM, on Docker and on Kubernetes. Only the deploy step should change.

What to do: Repeat this lesson on a different target than the one you used first.

How:
  1. If you used Docker, use kind or minikube now.
  2. Change only the deploy commands.
  3. Keep the same Jenkinsfile stages.

Check: Same result, and the stage names did not change.

Medium Break it on purpose

Why: You must know the red output by face. In a real outage there is no time to read slowly.

What to do: Cause one error from the "When it is red" part of this lesson and fix it.

How:
  1. Follow the error section.
  2. Copy the exact message into your notes.
  3. Write the fix in one line.

Check: You fixed it using only the steps, without searching the web.

Medium Write a release runbook page

Why: At 2 a.m. nobody remembers flags. A short page saves the on-call person.

What to do: Write a one-page runbook for this lesson.

How:
  1. Title, when to use, exact commands, how to check, how to undo.

Check: A teammate can follow it alone.

Hard Explain it like an interview

Why: Interviewers want real stories, not definitions.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the Jenkinsfile step, and one error you hit.

Check: Your answer has a real command and a real error message.

Hard Draw the flow top to bottom

Why: A drawing shows the order of work and who is waiting on whom.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at git push, go through the stages, end at the check in production.

Check: Each box matches a real step you ran.

Homework: try at home

Try at home

At home, make a Multibranch job for a repo with three branches. Add one when rule so a stage runs only on main. Push a new branch and see the new child job appear after a scan.

Recap

  • A Multibranch Pipeline makes one child job per branch with a Jenkinsfile.
  • Scans find new branches; webhooks make scans fast.
  • Use BRANCH_NAME and when rules to change behaviour per branch.
  • Clean branch names before using them in tags.
  • Keep the job as code with Job DSL.

FAQ

Do all branches need a Jenkinsfile?

Only those you want to build. Others are skipped.

Can I limit which branches build?

Yes. Use a filter by name, like main develop release/ feature/.

Is Multibranch only for GitHub?

No. It works with any Git host.

Why does the URL show %2F?

Jenkins encodes the slash in branch names.

How often does it scan?

On each webhook, or on the periodic trigger you set.

Interview questions

  1. What is a Multibranch Pipeline?

    A job that scans a repo and makes a child Pipeline job for each branch that has a Jenkinsfile.

  2. How do you deploy only from main?

    Put when { branch 'main' } on the deploy stage.

  3. How does Jenkins find new branches?

    A scan on a timer or a webhook from the host.

  4. What is the difference between a Pipeline job and Multibranch?

    A Pipeline job builds one branch you choose. Multibranch builds all matching branches by itself.

  5. How do you avoid many slow builds on feature branches?

    Run only fast tests on them and keep long tests for release branches with when rules.

Quick quiz

Q1. What does a Multibranch job create?

One child job for each branch with a Jenkinsfile.

Q2. Which variable has the branch name?

BRANCH_NAME.

Q3. How do you run a stage only on main?

when { branch 'main' }.

Q4. Why replace / in Docker tags?

Docker tags cannot contain a slash.

Q5. What shows %2F in a URL?

A slash inside a branch name.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards