20-bo‘lim

Amaliy loyiha - to'liq quvur

Darslikdagi hamma narsani bitta loyihaga yig'amiz: tekshiruv, obraz, reliz va deploy - to'rtta workflow fayli.

🕑 7 daqiqa o‘qish 📄 529 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Loyiha talablari
  2. Fayl tuzilmasi
  3. 1-fayl: tekshiruv
  4. 2-fayl: obraz
  5. 3-fayl: reliz
  6. 4-fayl: deploy
  7. Qo'shimcha sozlamalar
  8. Ishga tushirish tartibi
  9. Xulosa

Endi hamma bo'laklarni birlashtiramiz. Natijada real loyihada ishlatsa bo'ladigan to'liq quvur chiqadi.

Loyiha talablari #

TalabYechim
Har PR da testlar va linter ishlasintekshiruv.yml
main ga tushgan kod obrazga aylansinobraz.yml
Teg qo'yilganda reliz chiqsinreliz.yml
Deploy tugma bilan bo'lsin, tasdiq bilandeploy.yml
Qizil kod hech qachon serverga bormasinTarmoq himoyasi + needs

Fayl tuzilmasi #

Natija
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 #

YAML
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 #

YAML
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 #

YAML
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 #

YAML
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}"
To'rtta fayl - to'liq yo'l tekshiruv.yml PR va push linter + testlar obraz.yml main ga tushganda GHCR ga yuboriladi reliz.yml teg qo'yilganda changelog + obraz deploy.yml tugma bilan tasdiq bilan Himoya qatlamlari Tarmoq himoyasi: qizil PR birlashtirilmaydi Muhit tasdig'i: deploy odam ruxsatisiz ketmaydi permissions: har workflow eng kam huquq bilan Salomatlik tekshiruvi: xizmat javob bermasa - qizil Natija Kommitdan serverga yo'l avtomatik, tekshirilgan va istalgan paytda orqaga qaytariladigan
To'rtta fayl butun yo'lni qoplaydi - har biri o'z hodisasiga javob beradi

Qo'shimcha sozlamalar #

.github/dependabot.yml:

YAML
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:

Natija
*                     @siz
/.github/workflows/   @siz
/Dockerfile           @siz

Repozitoriy sozlamalarida:

Bo'limSozlama
Branchesmain uchun himoya, majburiy hammasi-tayyor
Environmentsishlab-chiqarish + majburiy tasdiq
Actions -> GeneralWorkflow permissions: read-only
Code securitySecret scanning + push protection

Ishga tushirish tartibi #

QadamNima qilinadi
1tekshiruv.yml ni qo'shing va PR da ishlashini ko'ring
2Tarmoq himoyasini yoqing, majburiy tekshiruvni belgilang
3Dockerfile yozing va mahalliy quring
4obraz.yml ni qo'shing, GHCR da obraz paydo bo'lishini tekshiring
5Serverda deploy.sh skriptini tayyorlang
6Sirlarni qo'shing va deploy.yml ni sinov muhitida sinang
7ishlab-chiqarish muhitini tasdiq bilan sozlang
8reliz.yml ni qo'shing va birinchi tegni qo'ying
Hammasini birdan yozmang

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.

Amaliy topshiriq
  1. Yangi repozitoriy yarating va unga kichik ilova joylang.
  2. tekshiruv.yml ni qo'shib, PR da ishlashiga erishing.
  3. hammasi-tayyor jobini yozing va uni majburiy tekshiruv qiling.
  4. Qizil PR ni birlashtirib bo'lmasligini tasdiqlang.
  5. Dockerfile yozing va obrazni mahalliy sinang.
  6. obraz.yml ni qo'shib, GHCR da obraz paydo bo'lishini ko'ring.
  7. ishlab-chiqarish muhitini majburiy tasdiq bilan sozlang.
  8. deploy.yml ni sinov serveriga qarab sozlang va ishga tushiring.
  9. v0.1.0 tegini qo'yib, reliz avtomatik chiqishini kuzating.
  10. 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-tayyor jobi matritsani tarmoq himoyasidan ajratadi.
  • Obraz faqat main da quriladi va aniq teglar bilan saqlanadi.
  • Reliz teg bilan boshlanadi; versiya mosligi avtomatik tekshiriladi.
  • Deploy tugma va tasdiq bilan ishlaydi, concurrency esa navbatni saqlaydi.
  • Har bir workflow'da permissions eng 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.

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.