နားလည်ထားရမယ့် အချက်
Runner ဆိုတာ job တစ်ခုကို execute လုပ်ပေးတဲ့ machine ပါ။ GitHub-hosted runner ကို သုံးတဲ့အခါ runs-on: ubuntu-latest လို့ ရေးလိုက်ရင် GitHub က သင့် job အတွက် virtual machine အသစ် တစ်လုံးကို ဆောက်ပေးပါတယ် - ဆောက်ထားပြီးသား tool တွေ (git, node, python, docker စတာတွေ) ပါဝင်ပြီး၊ သင့် repository ရဲ့ file တစ်ခုမှ မပါဘဲ ဗလာဖြစ်နေပါတယ်။ ဒါကြောင့် actions/checkout ကို ကိုယ်တိုင် ခေါ်ပေးရတာပါ။ job ပြီးတာနဲ့ အဲဒီ machine ကို ဖျက်ပစ်ပါတယ်။
ဒီအချက်တစ်ခုတည်းက Actions အကြောင်း အခြားအရာ အားလုံးကို ရှင်းပြပေးပါတယ်။ job နှစ်ခုဟာ machine နှစ်လုံး သီးခြားစီပေါ်မှာ ရှိလို့ file system ကို လုံးဝ မမျှဝေပါဘူး။ build job မှာ npm ci လုပ်ပြီး node_modules ရလာတာဟာ test job အတွက် ရှိမနေပါဘူး။ build job က ထုတ်လိုက်တဲ့ dist/ folder ကို deploy job က မမြင်ပါဘူး။ တစ်ခုကနေ တစ်ခုကို ပေးချင်ရင် artifact (file တွေအတွက်) ဒါမှမဟုတ် job outputs (string အသေးအဖွဲ့တွေအတွက်) နဲ့ တိတိကျကျ လွှဲပေးရပါတယ်။ ဒါကို နောက်ပိုင်း သင်ခန်းစာတွေမှာ အသေးစိတ် ဆက်လေ့လာပါမယ်။
အစဉ်လိုက် လိုချင်ရင် needs ကို သုံးပါတယ်။ needs: [lint, test] လို့ ရေးထားတဲ့ job ဟာ lint နဲ့ test နှစ်ခုလုံး အောင်မြင်မှသာ စတင်ပါတယ်။ တစ်ခုခု ကျရှုံးရင် အဲဒီ job က skipped ဖြစ်သွားပြီး ကျရှုံးတာ မဟုတ်ပါဘူး - Actions tab မှာ အနီရောင်မဟုတ်ဘဲ မီးခိုးရောင် ဖြစ်နေတာကို မကြာခဏ တွေ့ရပါလိမ့်မယ်။
job တစ်ခုအတွင်းမှာတော့ step တွေက အစဉ်လိုက် run ပြီး၊ zero မဟုတ်တဲ့ exit code ပြန်တဲ့ step တစ်ခု ရှိတာနဲ့ ကျန် step အားလုံးကို ချက်ချင်း ကျော်ပစ်ပါတယ်။ ဒါက များသောအားဖြင့် မှန်ကန်တဲ့ အပြုအမူပါ - build ကျရှုံးထားတာကို deploy လုပ်လို့ မဖြစ်ပါဘူး။ ဒါပေမယ့် test ကျရှုံးရင်တောင် coverage report ကို upload ချင်တာမျိုး ရှိပါတယ်။ အဲဒီအခါ အဲဒီ step မှာ if: always() ထည့်ပေးရပါတယ်။
THREE JOBS, THREE RUNNERS, ONE GATE
-----------------------------------
trigger: push to main
|
+---------------+---------------+
v v
+--------------------+ +--------------------+
| job: lint | | job: test |
| runner A | | runner B |
| fresh VM, empty | | fresh VM, empty |
| 1 checkout | | 1 checkout |
| 2 npm ci | | 2 npm ci |
| 3 npm run lint | | 3 npm test |
+--------------------+ +--------------------+
| |
+---------------+---------------+
v
both succeeded?
no | yes
skipped | v
+--------------------------+
| job: deploy |
| needs: [lint, test] |
| runner C, fresh VM |
+--------------------------+
runner A, B and C share NO files. Nothing carries over.
A destroyed VM takes node_modules, dist/ and /tmp with it.လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
အောက်က workflow မှာ job သုံးခု ရှိပါတယ်။ lint နဲ့ test က တစ်ပြိုင်နက် စတင်ပြီး၊ deploy ကတော့ needs: [lint, test] ကြောင့် စောင့်နေပါတယ်။ ဒီနေရာမှာ ဂရုစိုက်ရမှာက deploy job ထဲမှာလည်း actions/checkout ကို ပြန်ခေါ်ထားရတာပါ - runner C ဟာ runner A နဲ့ B တို့ရဲ့ file တွေကို လုံးဝ မမြင်ပါဘူး၊ သူ့မှာ deploy script တောင် မရှိသေးပါဘူး။
test job ရဲ့ နောက်ဆုံး step ကို ကြည့်ပါ။ npm test ကျရှုံးရင် သာမန်အားဖြင့် အဲဒီနောက်က step အားလုံး ကျော်ခံရမှာပါ - ဒါဆိုရင် coverage report က ဘယ်တော့မှ ရမှာ မဟုတ်တော့ဘဲ၊ တကယ် လိုအပ်တဲ့အချိန် (test ကျရှုံးတဲ့အချိန်) မှာပဲ ပျောက်နေမှာပါ။ if: always() က အဲဒီ step ကို အရင် step ဘာဖြစ်ဖြစ် run ခိုင်းပါတယ်။ if: failure() ဆိုရင်တော့ ကျရှုံးမှသာ run ပြီး၊ if: success() က default အပြုအမူပါ။
continue-on-error: true ဆိုတဲ့ option လည်း ရှိပါသေးတယ် - step တစ်ခု ကျရှုံးပေမယ့် job ကို ဆက်သွားခိုင်းတာပါ။ ဒါကို သတိထားပါ။ flaky test တစ်ခုကို ဖုံးဖိဖို့ သုံးလိုက်ရင် pipeline က အစိမ်းရောင် ပြနေပေမယ့် ဘာမှ မကာကွယ်တော့တဲ့ အခြေအနေ ရောက်သွားပါတယ်။ deploy job မှာ environment: production ထည့်ထားရင် repository setting မှာ သတ်မှတ်ထားတဲ့ reviewer တွေ approve မှသာ ဆက်သွားလို့ - Continuous Delivery ကို ဒီနေရာကနေ စတင်နိုင်ပါတယ်။
အတူတူ စမ်းရေးကြည့်မယ်
name: Jobs and Runners
on:
push:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- name: Lint
run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- name: Unit tests
run: npm test -- --coverage
- name: Upload coverage even when the tests failed
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
retention-days: 7
deploy:
needs: [lint, test]
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./scripts/deploy.sh
main ကို push လုပ်တာနဲ့ lint နဲ့ test job နှစ်ခုက runner သီးသန့်စီပေါ်မှာ တစ်ပြိုင်နက် စတင်ပါတယ်။ deploy job ကတော့ နှစ်ခုလုံး အောင်မြင်မှသာ စတင်ပြီး၊ တစ်ခုခု ကျရှုံးရင် failed မဟုတ်ဘဲ skipped အဖြစ် မှတ်ခံရပါတယ်။ test job ထဲမှာ npm test ကျရှုံးရင် job က ကျရှုံးပေမယ့် if: always() ကြောင့် coverage upload step ကတော့ ဆက်ပြီး run လို့ artifact ကို ရနေဆဲပါ။ deploy job မှာ environment: production ရှိလို့ အဲဒီ environment မှာ required reviewer သတ်မှတ်ထားရင် job က approve စောင့်ပြီး ရပ်နေပါလိမ့်မယ်။ deploy runner ဟာ machine အသစ်ဖြစ်လို့ checkout ပြန်လုပ်မှသာ deploy script ကို တွေ့ပါတယ်။၅ မိနစ် စမ်းကြည့်
test job ထဲမှာ echo "built" > out.txt လုပ်တဲ့ step တစ်ခု ထည့်ပြီး၊ deploy job ထဲမှာ cat out.txt လုပ်တဲ့ step ထည့်ပါ။ needs ချိတ်ထားပြီးသားမို့ အလုပ်လုပ်မယ်လို့ ထင်ရပေမယ့် push လုပ်ကြည့်ပါ - ဘာကြောင့် ကျရှုံးလဲ ရှင်းပြပါ။ ပြီးရင် coverage upload step က if: always() ကို ဖြုတ်ပြီး test တစ်ခုကို တမင် ကျရှုံးအောင်လုပ်ကာ artifact ရသေးလား စစ်ကြည့်ပါ။
သတိလေးတစ်ချက်
needs နဲ့ ချိတ်ထားရင် ရှေ့ job ရဲ့ file တွေ ပါလာမယ်လို့ ထင်တာ - needs က အစဉ်လိုက်ဖြစ်အောင်သာ လုပ်ပေးပြီး file ဘာတစ်ခုမှ မကူးပေးပါဘူး။
step တစ်ခု ကျရှုံးလို့ ဆက်သွားစေချင်တာနဲ့ continue-on-error: true ကို အလွယ်တကူ ထည့်လိုက်တာ - job က အစိမ်းရောင်ပြနေပေမယ့် တကယ်တော့ ဘာမှ မကာကွယ်တော့ပါဘူး။
GitHub Docs - Choosing where your workflow runs — CI/CD with GitHub Actions