20-bo‘lim
Amaliy loyiha - to'liq quvur
Darslikdagi hamma narsani bitta loyihaga yig'amiz: tekshiruv, obraz, reliz va deploy - to'rtta workflow fayli.
Ushbu bo‘lim mundarijasi
Endi hamma bo'laklarni birlashtiramiz. Natijada real loyihada ishlatsa bo'ladigan to'liq quvur chiqadi.
Loyiha talablari #
| Talab | Yechim |
|---|---|
| Har PR da testlar va linter ishlasin | tekshiruv.yml |
main ga tushgan kod obrazga aylansin | obraz.yml |
| Teg qo'yilganda reliz chiqsin | reliz.yml |
| Deploy tugma bilan bo'lsin, tasdiq bilan | deploy.yml |
| Qizil kod hech qachon serverga bormasin | Tarmoq himoyasi + needs |
Fayl tuzilmasi #
loyiha/
├── .github/
│ ├── workflows/
│ │ ├── tekshiruv.yml
│ │ ├── obraz.yml
│ │ ├── reliz.yml
│ │ └── deploy.yml
│ ├── dependabot.yml
│ └── CODEOWNERS
├── src/
├── Dockerfile
├── compose.yml
├── package.json
└── package-lock.json
1-fayl: tekshiruv #
name: Tekshiruv
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
concurrency:
group: tekshiruv-${{ github.ref }}
cancel-in-progress: true
jobs:
linter:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npx eslint .
- run: npx prettier --check .
test:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
node: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npm test
- name: Natijani saqlash
if: always()
uses: actions/upload-artifact@v4
with:
name: test-natija-node${{ matrix.node }}
path: natijalar/
if-no-files-found: ignore
hammasi-tayyor:
if: always()
needs: [linter, test]
runs-on: ubuntu-latest
steps:
- name: Yig'ma natija
run: |
echo "linter: ${{ needs.linter.result }}"
echo "test: ${{ needs.test.result }}"
if [ "${{ needs.linter.result }}" != "success" ] || [ "${{ needs.test.result }}" != "success" ]; then
exit 1
fi
echo "Barcha tekshiruvlar o'tdi"
Tarmoq himoyasida majburiy tekshiruv sifatida faqat hammasi-tayyor
belgilanadi - shunda matritsa o'zgarsa ham sozlama buzilmaydi.
2-fayl: obraz #
name: Obraz
on:
push:
branches: [main]
permissions:
contents: read
packages: write
jobs:
obraz:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=sha,format=short
type=raw,value=latest,enable={{is_default_branch}}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Hisobot
run: |
{
echo "## Obraz tayyor"
echo ""
echo '```'
echo "${{ steps.meta.outputs.tags }}"
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
3-fayl: reliz #
name: Reliz
on:
push:
tags: ['v*']
permissions:
contents: write
packages: write
jobs:
reliz:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: versiya
run: |
teg="${GITHUB_REF#refs/tags/}"
echo "teg=$teg" >> "$GITHUB_OUTPUT"
echo "raqam=${teg#v}" >> "$GITHUB_OUTPUT"
- name: Versiya mosligini tekshirish
run: |
faylda=$(node -p "require('./package.json').version")
if [ "$faylda" != "${{ steps.versiya.outputs.raqam }}" ]; then
echo "package.json ($faylda) va teg (${{ steps.versiya.outputs.raqam }}) mos emas"
exit 1
fi
- id: ozgarishlar
run: |
oldingi=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -z "$oldingi" ]; then
royxat=$(git log --pretty=format:'- %s')
else
royxat=$(git log "$oldingi..HEAD" --pretty=format:'- %s')
fi
{
echo 'matn<<ROYXAT'
echo "$royxat"
echo 'ROYXAT'
} >> "$GITHUB_OUTPUT"
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ steps.versiya.outputs.raqam }}
ghcr.io/${{ github.repository }}:barqaror
- uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.versiya.outputs.teg }}
name: ${{ steps.versiya.outputs.teg }}
body: |
## O'zgarishlar
${{ steps.ozgarishlar.outputs.matn }}
4-fayl: deploy #
name: Deploy
on:
workflow_dispatch:
inputs:
versiya:
description: 'Qaysi versiya (masalan 1.4.2)'
required: true
type: string
permissions:
contents: read
concurrency:
group: deploy-ishlab-chiqarish
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: ishlab-chiqarish
url: https://misol.uz
steps:
- name: Serverda yangilash
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KALIT }}
script: /home/deploy/deploy.sh ${{ inputs.versiya }}
- name: Salomatlikni kutish
run: |
for i in $(seq 1 30); do
if curl -sSf https://misol.uz/salomatlik > /dev/null; then
echo "Xizmat javob bermoqda"
exit 0
fi
sleep 2
done
exit 1
- name: Xato bo'lsa xabar berish
if: failure()
env:
TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
CHAT: ${{ secrets.TELEGRAM_CHAT_ID }}
run: |
havola="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
curl -sS -X POST "https://api.telegram.org/bot${TOKEN}/sendMessage" \
-d "chat_id=${CHAT}" \
-d "text=Deploy yiqildi - ${{ inputs.versiya }} - ${havola}"
Qo'shimcha sozlamalar #
.github/dependabot.yml:
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
.github/CODEOWNERS:
* @siz
/.github/workflows/ @siz
/Dockerfile @siz
Repozitoriy sozlamalarida:
| Bo'lim | Sozlama |
|---|---|
| Branches | main uchun himoya, majburiy hammasi-tayyor |
| Environments | ishlab-chiqarish + majburiy tasdiq |
| Actions -> General | Workflow permissions: read-only |
| Code security | Secret scanning + push protection |
Ishga tushirish tartibi #
| Qadam | Nima qilinadi |
|---|---|
| 1 | tekshiruv.yml ni qo'shing va PR da ishlashini ko'ring |
| 2 | Tarmoq himoyasini yoqing, majburiy tekshiruvni belgilang |
| 3 | Dockerfile yozing va mahalliy quring |
| 4 | obraz.yml ni qo'shing, GHCR da obraz paydo bo'lishini tekshiring |
| 5 | Serverda deploy.sh skriptini tayyorlang |
| 6 | Sirlarni qo'shing va deploy.yml ni sinov muhitida sinang |
| 7 | ishlab-chiqarish muhitini tasdiq bilan sozlang |
| 8 | reliz.yml ni qo'shing va birinchi tegni qo'ying |
Quvur - kod kabi: kichik boshlab, bosqichma-bosqich o'stiriladi.
Birinchi kuni faqat npm test ishlaydigan bitta fayl yozing va uni
ishlating.
Har bosqichda quvur yashil bo'lishiga erishing, keyin keyingisini qo'shing. Bir vaqtning o'zida to'rtta faylni yozib, keyin uch kun xatolarni qidirish - eng ko'p uchraydigan yo'l va eng uzun yo'l.
- Yangi repozitoriy yarating va unga kichik ilova joylang.
tekshiruv.ymlni qo'shib, PR da ishlashiga erishing.hammasi-tayyorjobini yozing va uni majburiy tekshiruv qiling.- Qizil PR ni birlashtirib bo'lmasligini tasdiqlang.
Dockerfileyozing va obrazni mahalliy sinang.obraz.ymlni qo'shib, GHCR da obraz paydo bo'lishini ko'ring.ishlab-chiqarishmuhitini majburiy tasdiq bilan sozlang.deploy.ymlni sinov serveriga qarab sozlang va ishga tushiring.v0.1.0tegini qo'yib, reliz avtomatik chiqishini kuzating.- Butun quvurni 19-bo'limdagi xavfsizlik ro'yxati bo'yicha tekshiring.
Xulosa #
- To'liq quvur to'rtta fayldan iborat: tekshiruv, obraz, reliz, deploy.
- Har bir fayl o'z hodisasiga javob beradi - hammasini bitta faylga tiqish shart emas.
hammasi-tayyorjobi matritsani tarmoq himoyasidan ajratadi.- Obraz faqat
mainda quriladi va aniq teglar bilan saqlanadi. - Reliz teg bilan boshlanadi; versiya mosligi avtomatik tekshiriladi.
- Deploy tugma va tasdiq bilan ishlaydi,
concurrencyesa navbatni saqlaydi. - Har bir workflow'da
permissionseng kam huquq bilan yoziladi. - Dependabot amallar va paketlarni yangilab turadi.
- Salomatlik tekshiruvi deploy natijasini haqiqatda tasdiqlaydi.
- Quvurni bosqichma-bosqich o'stiring: har qadamda yashil natijaga erishing.
Siz endi kommitdan serverga boradigan to'liq, tekshirilgan va xavfsiz yo'lni qura olasiz. Keyingi qadam - uni o'z loyihangizda ishlatish va har hafta bittadan yaxshilash.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.