✅ धडा 03 — तुमची पहिली pipeline: प्रत्येक push वर हिरवा check
📍 तुम्ही इथे आहात: 12 पैकी धडा 03 · मागे: lesson-02-pipeline-anatomy · पुढे: lesson-04-cache-parallel-matrix
📦 या ब्रँचमध्ये काय आहे
धडे 01–02, आणि तुमच्या fork मध्ये courier ची पहिली फेरी: एक push, एक run page, एक हिरवा check — आणि तुम्ही मुद्दाम घडवलेला एक लाल. खऱ्या files:
- .github/workflows/ci.yml — प्रत्येक push आणि pull request वर चालणारा
testjob; जुने runs रद्द करणाराconcurrency:block - app/server.test.js — ✅ की ❌ ठरवणाऱ्या तीन तपासण्या;
/healthzबिघडवा आणि दुसरी fail होते - .circleci/config.yml, .gitlab-ci.yml, Jenkinsfile — तोच test job इतर तीन बोलींमध्ये
🧒 5 वर्षांच्या मुलाला समजावल्यासारखे
आज mailroom खरोखर उघडते. तुम्ही फटीत एक कागद टाकता 📮 (एक
git push), घंटा वाजते, आणि तीन सारख्या तपासणी डेस्कवरचे ✅ तीन कारकून तुमच्या
गृहपाठावर तीच उत्तरपत्रिका चालवतात — Node 20 ची फूटपट्टी, 22 ची, आणि 24 ची.
प्रत्येक कारकून शेवटी शिक्का मारतो. ✅ हिरवा: प्रत्येक तपासणी पास झाली. ❌ लाल: एक पास झाली नाही, आणि कारकून कोणत्या step ने हार मानली हे सांगणारी छोटी चिठ्ठी लावतो. शिक्का तुमच्या commit वर लागतो आणि, कागद एखाद्या pull request चा भाग असेल तर, PR वरही — merge करण्याआधी reviewer नेमके जिथे पाहतो तिथेच.
आणखी एक नियम: पहिली फेरी संपण्याआधी दुसरा कागद टाकला तर कारकून जुनी फेरी सोडून
नव्या कागदाकडे वळतो — तुम्ही आधीच बदललेला गृहपाठ तपासण्यात काही अर्थ नाही. तेच म्हणजे
cancel-in-progress सह concurrency. आणि शिक्क्यावर विश्वास ठेवण्याचा सर्वोत्तम
मार्ग म्हणजे मुद्दाम एक लाल शिक्का मिळवणे. म्हणून आपण तेच करणार आहोत.
🗺️ आकृती
flowchart LR
push["🧑💻 git push"]
run["📮 one run of ci.yml<br/>one page, three jobs"]
j["✅ checking desks<br/>node --test on 20, 22, 24"]
green["✅ green check<br/>on the commit and the PR"]
red["❌ red X<br/>annotation plus log line"]
fix["🔧 fix, push again"]
push -->|"1 on push or pull_request"| run
run -->|"2 three fresh runners"| j
j -->|"3 exit code 0"| green
j -->|"4 exit code 1"| red
red -->|"5 read the log"| fix
fix -->|"6 newer push cancels the older run"| run
❓ काय
- Run = एका event ने सुरू झालेले एका workflow चे एक execution: एक URL, एक status, आणि त्याचे jobs आणि steps दाखवणारे page.
- Check = commit किंवा pull request वरचा ✅ / ❌ / 🟡 badge. प्रत्येक job एक देतो; कोणताही job लाल असेल तर run लाल असतो.
- Annotation = GitHub log मधून उचलून run summary वर ठेवतो ती ओळ
("Process completed with exit code 1", किंवा
::error::message). ती कुठे ते सांगते; log का ते सांगतो. - Pull-request check = PR च्या प्रस्तावित merge निकालावर चालवलेला तोच workflow. Branch protection त्याला required करू शकते (धडा 08).
- Concurrency group = एक नाव; ते वाटून घेणारे runs आळीपाळीने चालतात.
cancel-in-progress: trueअसेल तर नवा run जुना रद्द करतो.
🧠 शिक्का म्हणजे exit code
command exits 0 → step passes → job passes → run is green → commit / PR gets ✅
command exits non-zero → step fails → job fails → run is red → commit / PR gets ❌
मूलतः एवढाच संपूर्ण करार आहे. CI ला tests बद्दल "माहीत" नसते — त्याला एवढेच माहीत
असते की एखादी fail झाली की node --test non-zero exit करते.
🤔 का
जी pipeline तुम्ही फक्त वाचली आहे ती एक वचन आहे. जी तुम्ही हिरवी, लाल आणि पुन्हा हिरवी होताना पाहिली आहे ती एक tool आहे: failure कसे दिसते, message कुठे असतो, आणि फेरीला किती वेळ लागतो हे तुम्हाला माहीत असते — शुक्रवार संध्याकाळच्या hotfix आधीच. तो जलद, दिसणारा प्रतिसाद हाच धडा 01 च्या mailroom चा मुद्दा आहे. "प्रवासाआधी तपासा" हीच कल्पना Docker शाळेचा धडा 12 CI मध्ये built image चा smoke test करतो तेव्हा पुन्हा दिसते.
🔧 कसे (या repo मध्ये)
ci.yml मधली घंटा — on: push: आणि
pull_request:, धडा 02 मध्ये उद्धृत — हिला branch filter नाही, म्हणून तुमच्या fork
च्या कोणत्याही branch वरचा push ती वाजवतो, आणि pull request सुद्धा (fork मधल्याच
branch वरून आलेला PR दोन्ही वाजवतो — प्रत्येक push ला दोन runs अपेक्षित ठेवा). शिक्का
ठरवणारी step server.test.js चालवते आणि कोणत्याही failure
वर non-zero exit करते:
- name: 🧪 test
run: >
node --test
--test-reporter=spec --test-reporter-destination=stdout
--test-reporter=junit --test-reporter-destination=test-results.xml
Run page वाचणे. Actions tab → ✅ ci → runs ची यादी. एक उघडा:
प्रत्येक job साठी एक box — test (node 20), test (node 22), test (node 24) —
डाव्या sidebar मध्येही पुन्हा दिसतात. Steps पाहण्यासाठी job वर click करा; प्रत्येक
step उघडली की तिचा log दिसतो. लाल run मध्ये fail झालेल्या step वर खूण असते आणि summary
मध्ये annotation असते. Re-run jobs तोच commit पुन्हा चालवते; Re-run failed jobs
फक्त लाल असलेले.
जुने runs स्वतःच रद्द होतात:
concurrency: # a newer push cancels the older run of the same branch
group: ci-${{ github.ref }}
cancel-in-progress: true
Group च्या नावात branch (github.ref) आहे, म्हणून फक्त त्याच branch चा जुना run
रद्द होतो; तो लाल नाही तर राखाडी दिसतो (GitHub च्या API मध्ये status चे स्पेलिंग
cancelled आहे).
दुसरा workflow. तुमच्या fork मध्ये main वरचा push
ship.yml सुद्धा वाजवतो: त्याचे test आणि build jobs
चालतात, तर push आणि deploy यांना if: vars.AWS_ROLE_ARN != '' चे संरक्षण आहे
आणि ते skipped दिसतात — हे जाणूनबुजून; fork मध्ये AWS variables नसतात आणि तरीही
तो हिरवाच राहतो.
🔁 हेच CircleCI मध्ये
docker:
- image: cimg/node:<< parameters.node >>
working_directory: ~/repo/app
steps:
- checkout:
path: ~/repo
# … restore_cache / prepare / save_cache: lesson 04
- run:
name: 🧪 test
command: |
mkdir -p test-results
node --test --test-reporter=spec --test-reporter-destination=stdout \
--test-reporter=junit --test-reporter-destination=test-results/junit.xml
Docker image हा executor आहे, checkout ही स्पष्ट step आहे; workflows: node पुरवते.
🦊 हेच GitLab CI मध्ये
test:
stage: test
image: node:${NODE}-alpine
parallel:
matrix: # lesson 04: three rulers
- NODE: ["20", "22", "24"]
script:
- cd app
- node prepare.js # prints "already exists" on a cache hit
- node --test --test-reporter=spec --test-reporter-destination=stdout
--test-reporter=junit --test-reporter-destination=test-results.xml
Checkout step नाही — GitLab आधी clone करते. प्रत्येक script: ओळ एक step आहे; non-zero exit job थांबवतो.
🎩 हेच Jenkins मध्ये
stage('✅ test') {
matrix { // lesson 04: three rulers, in parallel
axes { axis { name 'NODE'; values '20', '22', '24' } }
agent { docker { image "node:${NODE}-alpine" } }
stages {
stage('test') {
steps {
dir('app') {
// … prepare step: lesson 04
sh '''node --test --test-reporter=spec --test-reporter-destination=stdout \
--test-reporter=junit --test-reporter-destination=test-results.xml'''
agent { docker { … } } हा कारकून, sh ही step; stage shell च्या exit code नुसार चालते.
🧪 करून पाहा
# 0) in your fork (lesson 02): enable Actions once in the Actions tab, then ring the bell
latest() { gh run list --workflow ci.yml --limit 1 --json databaseId --jq '.[0].databaseId'; }
git commit --allow-empty -m "ring the bell" && git push
gh run watch "$(latest)" # three jobs → ✅ (a minute or two; a cold runner takes longer)
# 1) earn a red stamp on purpose: /healthz answers "okay" instead of "ok"
sed -i.bak "s/end('ok/end('okay/" app/server.js && rm app/server.js.bak
git commit -am "break /healthz on purpose" && git push
gh run watch "$(latest)" # ❌ on all three rulers
gh run view "$(latest)" --log-failed | grep -A3 healthz # expected 'ok\n', actual 'okay\n'
# 2) fix it (the good file is one commit back), then push twice quickly: the first run is canceled
git checkout HEAD~1 -- app/server.js && git commit -am "fix /healthz" && git push
git commit --allow-empty -m "and again" && git push
gh run list --workflow ci.yml --limit 3 # "fix /healthz" canceled, "and again" ✅
# 3) a pull-request check: same workflow, second bell (-R keeps the PR inside YOUR fork)
ME=$(gh api user --jq .login)
git checkout -b pr-check && git commit --allow-empty -m "try a PR" && git push -u origin pr-check
gh pr create -R "$ME/learn-cicd-school" --base main --head pr-check --fill
gh pr checks pr-check -R "$ME/learn-cicd-school" --watch # the checks a reviewer sees
⚠️ नेहमीच्या चुका
- नव्या fork मध्ये push करून काहीच न दिसणे — Actions tab मध्ये एकदा enable करेपर्यंत fork मधले workflows बंद असतात
- फक्त लाल X वाचणे — annotation "exit code 1" सांगते; कारण test step च्या log मध्ये त्याच्या काही ओळी वर असते (
gh run view --log-failed) - राखाडी canceled run ला failure समजणे —
cancel-in-progressने त्याच branch चा जुना run मुद्दाम थांबवला; त्याऐवजी सगळ्यात नवा run पाहा
⏭️ पुढे
तुमच्या अगदी पहिल्या run मध्ये तीनही डेस्कनी node prepare.js सुरुवातीपासून चालवले.
नंतरच्या runs नी तसे केले नाही. Mailroom नेमके त्यासाठीच तासलेल्या पेन्सिलींचा ड्रॉवर 🗄️
ठेवते — जर तुम्ही तिला ड्रॉवरची किल्ली कशावरून आहे ते सांगितले तर. ⚡
git checkout lesson-04-cache-parallel-matrix