Ravindra BagaleCourses & study guides मराठी

Chapter 21: Jenkins Pipeline and Jenkinsfile

21.4 Same Node.js app — project shape reminder

Why: the problem

Before you write a big Jenkinsfile, you must know the app. A pipeline only runs commands that already work on a laptop. Think of a Swiggy developer. If npm test fails on her laptop, Jenkins will fail too. Jenkins is not magic. It is a clean machine that runs your commands in order. So first we fix the shape of the badge Node app. It must install with npm ci, build into a dist folder, and test with npm test. Each command must exit with 0 when good and non zero when bad. Jenkins reads only that exit code. In this lesson you will make the project from zero, run every command by hand, and only then hand it to Jenkins.

What we will build

You will create the badge Node app with package.json, a tiny build script and a test. You will run npm ci, npm run build and npm test by hand and check exit codes. Then you will add the Jenkinsfile and see the same output in Jenkins.

What: every term in plain English

  • package.json — The Node project file. It lists scripts and packages.
  • package-lock.json — Exact versions of every package, so all machines install the same thing.
  • npm ci — Clean install from the lock file. Fails if the lock file and package.json do not match.
  • npm run build — Runs the build script from package.json.
  • npm test — Runs the test script.
  • Exit code — A number a command returns. 0 means good. Anything else means failed.
  • dist — The output folder made by the build.
  • Workspace — The folder on the agent where Jenkins clones and builds.
Create the project Add a test tool Run the build by hand Run the tests by hand Clean install check Commit
Laptop commands to the same Jenkins stages

How: step by step

  1. Create the project

    mkdir badge-node && cd badge-node
    npm init -y
    

    What it does: Makes a blank package.json.

    Output

    Wrote to /home/asha/badge-node/package.json
    
  2. Add a test tool

    npm install --save-dev jest@29
    

    What it does: Adds Jest and writes package-lock.json.

    Output

    added 270 packages in 12s
    
  3. Run the build by hand

    npm run build; echo "exit=$?"
    

    What it does: Checks the build and its exit code.

    Output

    build done: dist/index.html
    exit=0
    
  4. Run the tests by hand

    npm test; echo "exit=$?"
    

    What it does: Checks the tests and their exit code.

    Output

    Tests: 2 passed, 2 total
    exit=0
    
  5. Clean install check

    rm -rf node_modules && npm ci
    

    What it does: Proves a fresh machine can install.

    Output

    added 270 packages in 8s
    
  6. Commit

    git init && git add . && git commit -m "badge app"
    

    What it does: The app is ready for Jenkins.

    Output

    [main (root-commit) 1f7e8a0] badge app
    

Example 1: The app files

Stack. Node.js 20, npm

Goal. The app files.

package.json

{
  "name": "badge-node",
  "version": "1.0.0",
  "scripts": {
    "build": "node build.js",
    "test": "jest --ci"
  },
  "devDependencies": {
    "jest": "^29.7.0"
  }
}

build.js

const fs = require('fs');
const { badge } = require('./src/badge');
fs.mkdirSync('dist', { recursive: true });
fs.writeFileSync('dist/index.html', badge('build', 'passing'));
console.log('build done: dist/index.html');

src/badge.js

function badge(label, status) {
  if (!label) throw new Error('label required');
  return 'svg-badge ' + label + ': ' + status;
}
module.exports = { badge };

What each line does

  • scripts.build — npm run build runs node build.js.
  • scripts.test — npm test runs jest in CI mode.
  • fs.mkdirSync dist — Makes the output folder.
  • badge() — The tiny function we test.
  • throw new Error — Bad input fails loudly.

Green output

$ npm run build
> badge-node@1.0.0 build
> node build.js
build done: dist/index.html

Expected result. The build works on the laptop and writes dist/index.html.

Example 2: The test and a failing test on purpose

Stack. Jest 29

Goal. The test and a failing test on purpose.

test/badge.test.js

const { badge } = require('../src/badge');
test('makes a badge', () => {
  expect(badge('build', 'passing')).toBe('svg-badge build: passing');
});
test('needs a label', () => {
  expect(() => badge('', 'x')).toThrow('label required');
});

break it

sed -i 's/passing/failing/' test/badge.test.js
npm test; echo "exit=$?"

What each line does

  • test() — One test case with a name.
  • expect().toBe() — Checks the exact value.
  • toThrow — Checks that bad input throws an error.
  • sed -i — Changes the test to fail on purpose.
  • echo exit — Shows the exit code Jenkins will see.

Green output

FAIL test/badge.test.js
  x makes a badge
    Expected: "svg-badge build: failing"
    Received: "svg-badge build: passing"
Tests: 1 failed, 1 passed, 2 total
exit=1

Expected result. Exit code 1 is what makes a Jenkins stage red. Undo with git checkout test/.

Example 3: The same commands in Jenkins

Stack. Jenkins Pipeline, Node.js 20

Goal. The same commands in Jenkins.

Jenkinsfile

pipeline {
  agent any
  stages {
    stage('Install') { steps { sh 'node --version && npm ci' } }
    stage('Build')   { steps { sh 'npm run build && ls -l dist' } }
    stage('Test')    { steps { sh 'npm test' } }
  }
}

What each line does

  • node --version — Proves Node exists on the agent first.
  • npm ci — Same clean install as the laptop.
  • ls -l dist — Shows the build output in the log.
  • npm test — Exit 0 green, exit 1 red.

Green output

[Pipeline] stage (Install)
+ node --version
v20.15.1
+ npm ci
added 270 packages in 9s
[Pipeline] stage (Build)
build done: dist/index.html
-rw-r--r-- 1 jenkins jenkins 31 Oct 25 10:12 index.html
[Pipeline] stage (Test)
Tests: 2 passed, 2 total
Finished: SUCCESS

Expected result. Jenkins output matches the laptop output. That is the goal.

Example 4: Pin the Node version so laptop and Jenkins match

Stack. Node.js, nvm, Jenkins

Goal. Pin the Node version so laptop and Jenkins match.

.nvmrc

20.15.1

package.json (part)

{
  "engines": { "node": "20.x" }
}

Jenkinsfile stage

stage('Check Node') {
  steps {
    sh 'echo "wanted $(cat .nvmrc) got $(node --version)"'
    sh 'node -e "process.exit(process.version.startsWith(\'v20\') ? 0 : 1)"'
  }
}

What each line does

  • .nvmrc — One line with the Node version. nvm use reads it on the laptop.
  • engines — Tells npm which Node the app needs.
  • process.version.startsWith — Fails the stage when the agent has the wrong major version.
  • Why — Most passes on laptop but fails in Jenkins problems are version gaps.

Green output

+ echo wanted 20.15.1 got v20.15.1
wanted 20.15.1 got v20.15.1
+ node -e ...
Finished: SUCCESS

(on an agent with Node 18)
wanted 20.15.1 got v18.20.4
ERROR: script returned exit code 1

Expected result. The build stops early with a clear reason, not a strange error ten minutes later.

Verify: did it work?

  1. Check the workspace

    docker exec jenkins ls /var/jenkins_home/workspace/badge-scm/dist
    

    What it does: The build output is on the agent.

    Output

    index.html
    
  2. Check exit code idea

    bash -c "exit 3"; echo $?
    

    What it does: Any non zero code fails a sh step.

    Output

    3
    

When it is red 1

npm ERR! `npm ci` can only install packages when your package.json and package-lock.json are in sync.

Cause. You changed package.json without updating the lock file.

Fix, step by step

  1. Run npm install on the laptop.
  2. Commit package-lock.json.

When it is red 2

sh: 1: npm: not found

Cause. Node is not installed on the agent.

Fix, step by step

  1. Install Node on the agent or use tools (lesson 21.7).
  2. Or run in a node:20 Docker agent.

When it is red 3

Error: Cannot find module ./src/badge

Cause. A file is missing in Git.

Fix, step by step

  1. Run git status.
  2. Add and push the file.

Cleanup

  1. Remove build output

    rm -rf dist node_modules
    

    What it does: Cleans the laptop folder.

    Output

    (no output)
    
  2. Reset test change

    git checkout -- test/
    

    What it does: Undoes the failing test.

    Output

    (no output)
    

Ravindra Bagale's Tip

Aadhi laptop var command chalvun bagha, mag Jenkins madhe. Exit code 0 mhanje green. Lakshat theva!

Practice tasks

Easy Create the app

Why: You need a working app.

What to do: Make badge-node.

How:
  1. npm init, jest.

Check: npm test passes.

Medium See exit codes

Why: Exit codes drive Jenkins.

What to do: Break and fix a test.

How:
  1. echo exit.

Check: You see 1 then 0.

Hard Fresh install check

Why: Agents are clean machines.

What to do: Delete node_modules and use npm ci.

How:
  1. Commit the lock file.

Check: Install works from zero.

Easy Say the badge Node app shape in two lines

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

What to do: Write two short lines about the badge Node app shape for a fresher who knows only Linux basics.

How:
  1. Write what problem it solves.
  2. Write the one command or menu 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 exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

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

Medium Break it on purpose

Why: You must know the red message by face. During an 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 one-page runbook

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

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

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

Check: A teammate can follow it alone.

Medium Repeat it on a cloud VM

Why: A laptop is not a server. Real Jenkins runs on EC2 or a company VM.

What to do: Do the main steps of this lesson again on a small Ubuntu 22.04 EC2 instance.

How:
  1. Launch t3.small with 20 GB disk.
  2. Open port 22 only to your IP.
  3. Repeat the steps and compare the output.

Check: Same green output on the VM as on your laptop.

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 command you ran, 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 who talks to whom and in what order.

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

How:
  1. Start at the developer push, go through the controller and agent, end at the result.

Check: Each box matches a real thing you saw on screen.

Homework: try at home

Try at home

At home, create the badge app, run each command by hand with echo exit, then run it in Jenkins and compare the logs.

Recap

  • A pipeline runs commands that already work.
  • Use npm ci, npm run build and npm test.
  • Exit code 0 means green.
  • Commit package-lock.json.
  • Print tool versions first in Jenkins.

FAQ

Why npm ci and not npm install?

npm ci is clean, fast and fails on lock mismatch, which is safer in CI.

Do I commit node_modules?

No. Agents install it with npm ci.

Do I commit dist?

No. Jenkins builds it and archives it.

Can I use yarn or pnpm?

Yes. Use their frozen lock install command.

Why does it pass locally but fail in Jenkins?

Different Node version, missing file in Git or missing env variable.

Interview questions

  1. Why must CI commands work locally first?

    The pipeline only automates commands. If they fail locally they fail in Jenkins.

  2. How does Jenkins know a step failed?

    From the exit code of the shell command.

  3. npm ci vs npm install?

    npm ci installs exactly from the lock file and removes node_modules first.

  4. A build passes locally and fails in Jenkins. What do you check?

    Tool versions, uncommitted files, environment variables and agent OS.

  5. Why print node --version in CI?

    To prove which tool version ran, for faster debugging.

Quick quiz

Q1. Which command installs from the lock file?

npm ci.

Q2. What exit code means success?

0.

Q3. Why run commands on the laptop first?

Jenkins only runs commands that already work.

Q4. What makes a stage red?

A non zero exit code.

Q5. Where does Jenkins build?

In the workspace on the agent.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards