aidoc.uz

7-qism · DevOps va yetakchilik·17-bob

GitHub Actions — CI/CD workflow'larini chuqur qurish

Workflow anatomiyasidan tortib matrix build'lar, keshlash strategiyasi, Environment orqali tasdiqlash bosqichlari va do'konlarga avtomatik deploy qilishgacha — GitHub Actions'ni Senior darajada tushunish.

13-bobda CI/CD tushunchalarining umumiy manzarasini ko'rib chiqqan edik — build flavor'lar, imzolash, versiyalash, do'konga topshirish. Lekin amaliyotda aksariyat jamoa aynan GitHub Actions'ning o'zi bilan ishlaydi, va intervyuda "CI qanday ishlaydi" degan umumiy savoldan keyin ko'pincha darhol "GitHub Actions'da buni qanday yozasiz" degan aniq, texnik savol keladi. Bu bobda faqat GitHub Actions'ning ichki mexanizmiga chuqur kiramiz: workflow fayli qanday o'qiladi, matrix build nima, sirlar qanday himoyalanadi va real Flutter loyihasi uchun to'liq ishlaydigan deploy pipeline qanday yoziladi. Bu — "CI haqida eshitgan" bilan "CI'ni qurgan" o'rtasidagi farqni ko'rsatadigan mavzu.

1. Workflow anatomiyasi#

Har bir GitHub Actions workflow — .github/workflows/ papkasidagi bitta YAML fayl. Repo'da nechta fayl bo'lsa, shuncha mustaqil workflow bo'ladi (masalan, ci.yml, deploy.yml, release.yml — alohida fayllarga ajratish odatiy amaliyot).

# .github/workflows/ci.yml
name: CI
 
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.24.0"
          channel: "stable"
      - run: flutter pub get
      - run: flutter analyze
      - run: flutter test
name
Workflow nomi
GitHub UI'da Actions tabida ko'rinadigan inson o'qiy oladigan nom — majburiy emas, lekin bir nechta workflow bo'lsa farqlash uchun shart.
on
Trigger'lar
Workflow qachon ishga tushishini belgilaydi: push, pull_request, schedule, workflow_dispatch va boshqalar.
jobs
Job'lar to'plami
Har biri alohida runner (virtual mashina)da ishlaydigan mustaqil ish birligi. Standart holatda barcha job'lar parallel ishga tushadi.
steps
Qadamlar
Bitta job ichidagi ketma-ket bajariladigan buyruqlar yoki tayyor action'lar (uses:) — bitta muvaffaqiyatsiz qadam butun job'ni to'xtatadi.

Runner tanlash — runs-on qaysi virtual mashinada job ishlashini belgilaydi: ubuntu-latest eng arzon va tez (Android build, testlar, analyze uchun yetarli), macos-latest esa faqat iOS build kerak bo'lganda ishlatiladi, chunki Xcode faqat macOS'da ishlaydi. macOS runner'lar sezilarli qimmatroq (keyinroq 10-bo'limda ko'ramiz) — shuning uchun Android va iOS build'larni bitta job'da emas, alohida job'larda, faqat kerakli runner'da ishga tushirish narx-samaradorlik nuqtai nazaridan muhim.

2. Trigger'lar chuqur tahlili#

on: bo'limi — workflow qachon ishga tushishini belgilaydi, va bu yerdagi tanlov xavfsizlik va samaradorlikka bevosita ta'sir qiladi.

push va branch/path filter'lari:

on:
  push:
    branches: [main, "release/**"]
    paths:
      - "lib/**"
      - "pubspec.yaml"
      - ".github/workflows/ci.yml"

paths: filtri — faqat ko'rsatilgan fayllar o'zgarganda workflow ishga tushishini ta'minlaydi. Agar faqat README.md o'zgargan bo'lsa, butun Flutter build pipeline behuda ishga tushmaydi.

pull_request va pull_request_target — muhim xavfsizlik farqi:

on:
  pull_request:
    branches: [main]

pull_request trigger'i PR muallifining kod fork qilingan branch'idan ishga tushadi va maqsad repo'ning sirlariga kirish huquqiga ega emas — bu default va xavfsiz. pull_request_target esa aksincha, asosiy repo kontekstida (sirlar bilan) ishga tushadi, lekin PR'dan kelgan kodni bajaradi.

Boshqa keng tarqalgan trigger'lar:

on:
  schedule:
    - cron: "0 3 * * 1"   # Har dushanba, UTC 03:00'da
  workflow_dispatch:
    inputs:
      environment:
        description: "Qaysi muhitga deploy qilish"
        required: true
        type: choice
        options: [staging, production]
  release:
    types: [published]
  • schedule — cron sintaksisi bilan, masalan haftalik dependency audit yoki performance regression testlarini avtomatik ishga tushirish uchun.
  • workflow_dispatch — GitHub UI'da "Run workflow" tugmasi orqali qo'lda ishga tushirish, inputs bilan parametr qabul qilish mumkin (masalan, qaysi muhitga deploy qilishni tanlash).
  • release — GitHub'da yangi release yaratilganda (odatda Git tag bilan birga) avtomatik deploy job'ini ishga tushirish uchun ishlatiladi.

3. Job'lar, bog'liqliklar va matrix build'lar#

needs: orqali tartib berish:

jobs:
  test:
    runs-on: ubuntu-latest
    steps: [...]
 
  build:
    needs: test
    runs-on: ubuntu-latest
    steps: [...]

build job'i test job'i muvaffaqiyatli tugagunicha boshlanmaydi. needs: bo'lmasa, ikkalasi bir vaqtda, parallel ishga tushadi — bu tezroq, lekin mantiqiy bog'liqlik bo'lsa (masalan, build'ni faqat testlar o'tgandan keyin qilish kerak), needs: shart.

Matrix build — bir nechta flavor/platforma uchun parallel build:

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        flavor: [dev, staging, production]
        platform: [android, ios]
        exclude:
          - flavor: dev
            platform: ios
    runs-on: ${{ matrix.platform == 'ios' && 'macos-latest' || 'ubuntu-latest' }}
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.24.0"
      - run: flutter pub get
      - name: Build ${{ matrix.platform }} (${{ matrix.flavor }})
        run: |
          if [ "${{ matrix.platform }}" = "android" ]; then
            flutter build apk --flavor ${{ matrix.flavor }} --release
          else
            flutter build ipa --flavor ${{ matrix.flavor }} --release
          fi

matrix — bitta job ta'rifini bir nechta kombinatsiya bo'yicha avtomatik ko'paytiradi: yuqoridagi misolda 3 flavor × 2 platforma = 6 ta mustaqil job (exclude bilan bittasi chiqarib tashlangani uchun 5 ta) parallel ishga tushadi, har biri o'z natijasi (muvaffaqiyat/xato) bilan alohida ko'rinadi. fail-fast: false — agar bitta kombinatsiya muvaffaqiyatsiz bo'lsa, qolganlarini ham darhol to'xtatib qo'ymaydi (standart holat fail-fast: true), bu barcha flavor/platformalar bo'yicha to'liq natijani bir marotabada ko'rish uchun foydali.

4. Flutter uchun keshlash (caching)#

CI'da har safar Flutter SDK'ni noldan yuklab olish va flutter pub get'ni to'liq bajarish — daqiqalab vaqt yeydi. actions/cache bu ikkalasini ham tezlashtiradi.

steps:
  - uses: actions/checkout@v4
 
  - uses: subosito/flutter-action@v2
    with:
      flutter-version: "3.24.0"
      cache: true   # Flutter SDK'ning o'zini keshlaydi
 
  - name: Cache pub packages
    uses: actions/cache@v4
    with:
      path: |
        ~/.pub-cache
        .dart_tool
      key: pub-${{ runner.os }}-${{ hashFiles('**/pubspec.lock') }}
      restore-keys: |
        pub-${{ runner.os }}-

key: — keshni noyob identifikatsiya qiladigan satr. Bu yerda pubspec.lock faylining hash'i ishlatilgan: agar biror paket versiyasi o'zgarsa, hash o'zgaradi, demak yangi (bo'sh) kesh yaratiladi va yangi paketlar to'g'ri o'rnatiladi. restore-keys: — aniq mos kesh topilmasa, eng yaqin mos prefiks bilan eskiroq keshni oladi (to'liq bo'sh boshlashdan ko'ra tezroq).

5. Sirlar va Environment'lar#

Repository secrets — Settings → Secrets and variables → Actions bo'limida saqlanadi, workflow'da ${{ secrets.NOM }} orqali o'qiladi:

steps:
  - name: Decode keystore
    run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore

GitHub sirlarni loglarda avtomatik maskalaydi (qiymat log'da *** bilan almashtiriladi), lekin bu faqat aniq shu satr sifatida chiqarilganda ishlaydi — agar sirni boshqa formatga o'tkazib (masalan, base64'dan qayta kodlab) chiqarsangiz, maskalash ishlamay qolishi mumkin. Shu sababli sirlarni hech qachon echo/print orqali debug qilish uchun log'ga chiqarmang.

Environment'lar — tasdiqlash bosqichi bilan deploy:

jobs:
  deploy-production:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://play.google.com/store/apps/details?id=com.example.app
    steps:
      - name: Deploy to Play Store
        run: bundle exec fastlane android deploy
        env:
          PLAY_STORE_JSON_KEY: ${{ secrets.PLAY_STORE_JSON_KEY }}

GitHub Environment (Settings → Environments) — bu nafaqat sirlarni muhit bo'yicha ajratish (staging'ning kaliti production'nikidan boshqa) imkonini beradi, balki "required reviewers" sozlamasi orqali job avtomatik ishga tushmasdan, belgilangan odam(lar) tasdiqlashini talab qilish mumkin. Amaliyotda bu — production deploy job'i build tugagach avtomatik emas, balki jamoa yetakchisi "Approve" tugmasini bosgandan keyingina ishga tushishini ta'minlaydigan mexanizm.

6. Artifact'lar va qayta ishlatiladigan workflow'lar#

Artifact'lar — job'lar orasida fayl uzatish:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: flutter build apk --release
      - uses: actions/upload-artifact@v4
        with:
          name: release-apk
          path: build/app/outputs/flutter-apk/app-release.apk
 
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: release-apk
      - run: echo "APK yuklandi, deploy qilishga tayyor"

Har bir job — o'z alohida, toza virtual mashinasida ishlaydi, ya'ni build job'idagi fayllar deploy job'iga avtomatik ko'chmaydi. upload-artifact/ download-artifact juftligi — build natijasini keyingi job'ga aniq, nazorat qilingan tarzda uzatish usuli (bonus: artifact GitHub UI'dan qo'lda yuklab olish uchun ham mavjud bo'ladi, debug uchun foydali).

Composite action vs reusable workflow:

Composite action
Bir nechta qadamni bitta 'action'ga o'raydi (action.yml), boshqa workflow ichida bitta 'uses:' qatori bilan chaqiriladi — takrorlanuvchi QADAMLAR to'plamini ulashish uchun
Reusable workflow (workflow_call)
Butun workflow faylini (job'lar, matrix, hammasi bilan) boshqa repolardan chaqirish mumkin qiladi — takrorlanuvchi PIPELINE'ning o'zini ulashish uchun

Amaliy farq: agar bir nechta Flutter repo'da bir xil "checkout + Flutter o'rnatish + kesh" qadamlari takrorlansa — composite action yetarli. Agar butun "analyze → test → build → deploy" pipeline'i tashkilotdagi 10 ta Flutter loyihada bir xil bo'lishi kerak bo'lsa — reusable workflow (workflow_call) to'g'ri yechim, chunki u markazlashgan bitta joyda saqlanadi va barcha repolar shunchaki uni chaqiradi:

# Chaqiruvchi repo'dagi workflow
jobs:
  ci:
    uses: my-org/flutter-ci-templates/.github/workflows/flutter-ci.yml@main
    with:
      flutter-version: "3.24.0"
    secrets: inherit

7. Concurrency boshqaruvi#

concurrency:
  group: ci-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Faol jamoada bitta PR'ga qisqa vaqt ichida bir necha marta push qilinishi odatiy hol — har bir push o'z workflow run'ini boshlaydi. concurrency guruhi bir xil group qiymatiga ega ishlayotgan eski run'larni avtomatik bekor qiladi, yangi push kelganda. Bu ikki narsani beradi: (1) CI daqiqalarini behuda sarflamaslik — eskirgan kod uchun build tugallanmaydi, (2) tezroq fikr-mulohaza — navbatda kutayotgan eski run'lar yo'qolgani uchun yangi run tezroq boshlanadi.

8. Majburiy tekshiruvlar va branch protection#

Workflow'dagi har bir job nomi — GitHub'ning branch protection sozlamalarida "required status check" sifatida tanlanishi mumkin (Settings → Branches → Branch protection rules). Bu tanlangandan keyin, o'sha job muvaffaqiyatli tugamaguncha PR "Merge" tugmasi bosilmaydi — hatto repo administratori uchun ham (agar shunday sozlansa).

  1. Workflow yoziladi

    flutter analyze, flutter test, build job'lari alohida yoki bitta workflow'da belgilanadi.

  2. Branch protection sozlanadi

    main branch uchun "Require status checks to pass before merging" yoqiladi va kerakli job nomlar (masalan, test, build) ro'yxatga qo'shiladi.

  3. PR ochiladi

    Workflow avtomatik ishga tushadi, natija PR sahifasida yashil/qizil belgi bilan ko'rinadi.

  4. Merge bloklanadi yoki ruxsat etiladi

    Agar biror required check muvaffaqiyatsiz bo'lsa, "Merge" tugmasi kulrang (bosib bo'lmaydigan) holatda qoladi — bu inson e'tiborsizligiga bog'liq bo'lmagan, mexanik ravishda ta'minlangan sifat nazorati.

Bu — CI'ning eng muhim rolini ko'rsatadi: u shunchaki "avtomatlashtirish" emas, balki siyosatni majburlash mexanizmi. "Testsiz kod merge qilinmasin" degan qoida odamlarning intizomiga emas, GitHub'ning texnik cheklovi orqali ta'minlanadi.

9. Do'konlarga deploy qilish — to'liq workflow#

Quyida — analyze/test'dan Play Console'ga yuklashgacha bo'lgan, production Environment orqali tasdiqlanadigan, realistik workflow:

name: Release
 
on:
  push:
    tags: ["v*"]
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.24.0"
          cache: true
      - run: flutter pub get
      - run: flutter analyze
      - run: flutter test
 
  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: "3.24.0"
          cache: true
      - run: flutter pub get
 
      - name: Decode keystore
        run: |
          echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > android/app/release.keystore
 
      - name: Write key.properties
        run: |
          cat <<EOF > android/key.properties
          storePassword=${{ secrets.KEYSTORE_PASSWORD }}
          keyPassword=${{ secrets.KEY_PASSWORD }}
          keyAlias=${{ secrets.KEY_ALIAS }}
          storeFile=release.keystore
          EOF
 
      - run: flutter build appbundle --release --flavor production
 
      - uses: actions/upload-artifact@v4
        with:
          name: release-aab
          path: build/app/outputs/bundle/productionRelease/*.aab
 
  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://play.google.com/store/apps/details?id=com.example.app
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: release-aab
 
      - name: Upload to Play Console
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_JSON_KEY }}
          packageName: com.example.app
          releaseFiles: "*.aab"
          track: production
          status: inProgress
          userFraction: 0.1

Bu workflow'da e'tibor beriladigan joylar: test va build alohida job (fail-fast signal tezroq keladi), deploy job'i environment: production orqali required reviewer tasdig'ini kutadi, va userFraction: 0.1 — 13-bobda ko'rgan staged rolloutning aynan shu workflow ichida amalga oshirilishi (dastlab 10% foydalanuvchiga chiqariladi).

10. Xarajat va self-hosted runner'lar#

GitHub-hosted runner daqiqalari metrlangan (public repo'larda bepul, private repo'larda reja bo'yicha limit bor). Muhim nuqta: macOS runner'lar Linux runner'lardan ~10 barobar qimmat hisoblanadi (masalan, 1 daqiqa macOS ishlatish — hisobda 10 daqiqa sifatida hisoblanadi). Flutter jamoalari uchun bu amalda shuni anglatadi — iOS build'lar CI byudjetining katta qismini yeydi.

OmilGitHub-hostedSelf-hosted
NarxDaqiqa bo'yicha to'lov, macOS qimmatFaqat serverning o'zi (bir martalik/oylik xarajat), daqiqa limiti yo'q
SozlashDeyarli sozlashsiz, darhol tayyorO'zingiz o'rnatasiz va yangilaysiz (OS, Flutter SDK, Xcode)
TezlikStandart hardwareReal, kuchli Mac mini/Studio'da iOS build sezilarli tezroq bo'lishi mumkin
XavfsizlikGitHub boshqaradiO'zingiz mas'ulsiz (ayniqsa fork PR'lar uchun ehtiyot kerak)

Jamoa CI hisobi oyiga bir necha yuz dollarga chiqsa yoki navbatda kutish vaqti (queue time) muammo bo'lsa — bu odatda self-hosted runner'ga o'tish signalidir, ayniqsa iOS build'lar uchun maxsus Mac mini fermasi tashkil qilish orqali.

11. Monorepo uchun path filter'lari#

Agar repo'da Flutter ilovasidan tashqari boshqa paketlar/hujjatlar ham bo'lsa, paths/paths-ignore orqali keraksiz build'larning oldini olish mumkin:

on:
  push:
    paths-ignore:
      - "docs/**"
      - "**.md"
      - ".github/ISSUE_TEMPLATE/**"

Bu — faqat hujjat yoki metama'lumot o'zgarganda og'ir Flutter build pipeline'i ishga tushmasligini ta'minlaydi, CI daqiqalarini va kutish vaqtini tejaydi.

Tez-tez so'raladigan intervyu savollari#

Savol: push va pull_request trigger'lari orasidagi amaliy farq nima, va nega ikkalasini ham qo'shish tavsiya etiladi?

Javob: push — branch'ga to'g'ridan-to'g'ri push qilinganda (masalan, mainga merge qilingandan keyin) ishga tushadi. pull_request — PR ochilganda yoki unga yangi commit qo'shilganda ishga tushadi, va PR'ning merge natijasini simulyatsiya qiluvchi vaqtinchalik birlashtirish (merge commit) ustida ishlaydi. Ikkalasini ham qo'shish tavsiya etiladi: pull_request — muammoni merge qilishdan OLDIN ushlaydi (asosiy maqsad), push (odatda faqat mainga) — merge qilingandan keyingi haqiqiy holatni tasdiqlaydi va deploy job'lari uchun trigger bo'ladi.

Savol: Nega pull_request_target'ni PR kodini to'g'ridan-to'g'ri bajarish uchun ishlatish xavfli?

Javob: pull_request_target maqsad repo kontekstida (barcha sirlarga kirish huquqi bilan) ishga tushadi, lekin trigger — begona (hatto fork qilingan) repo'dan kelgan PR bo'lishi mumkin. Agar workflow PR muallifining kodini checkout qilib bajarsa, zararli PR muallifi o'z kodi orqali secrets.* qiymatlarini o'qib, tashqariga yuborishi mumkin. Xavfsiz foydalanish — faqat PR metama'lumotlari (label qo'yish, komment yozish) bilan ishlash, PR kodini hech qachon shu kontekstda bajarmaslik.

Savol: strategy.matrixda fail-fast: true (standart) va false orasidagi farq amaliy qanday ta'sir qiladi?

Javob: fail-fast: true bo'lsa, matrix'dagi bitta kombinatsiya (masalan, ios + production) muvaffaqiyatsiz bo'lishi bilan GitHub qolgan barcha ishlayotgan kombinatsiyalarni ham darhol bekor qiladi — bu tezroq signal beradi, lekin boshqa kombinatsiyalar (masalan, android + staging) haqiqatan ham ishlaganmi yoki yo'qmi, noma'lum qolib ketadi. false qilib qo'yish — barcha kombinatsiyalar oxirigacha ishlashini ta'minlaydi, natijada bitta pull request'da "qaysi platforma/flavor kombinatsiyalari aynan buzilgan" degan to'liq rasmni bir martada ko'rish mumkin — kattaroq matrix'larda odatda shu tanlanadi.

Savol: Kesh key'ini noto'g'ri tanlash qanday xatoga olib keladi, va buni qanday aniqlash mumkin?

Javob: Agar kesh key pubspec.lockning hash'iga bog'liq bo'lmasa (masalan, statik key: pub-cache), yangi paket versiyasi qo'shilgan/yangilangan taqdirda ham CI eski keshlangan paketlardan foydalanadi. Bu — lokal muhitda (yangi pub get bilan) ishlaydigan, lekin CI'da tushunarsiz, versiya nomuvofiqligiga oid xato bilan qulaydigan build'ning klassik sababi. Aniqlash usuli — kesh key'i tarkibida hashFiles('**/pubspec.lock') borligini tekshirish, va shubha tug'ilganda keshni GitHub UI'dan (Actions → Caches) qo'lda o'chirib, qayta urinib ko'rish.

Savol: GitHub Environment'dagi "required reviewers" sozlamasi qanday ishlaydi, va uni qachon ishlatish kerak?

Javob: Job'da environment: production ko'rsatilganda, agar shu Environment uchun "required reviewers" yoqilgan bo'lsa, job avtomatik boshlanmaydi — u "Waiting" holatida to'xtab, ko'rsatilgan reviewer(lar)dan biri GitHub UI'da "Approve and deploy" tugmasini bosishini kutadi. Bu — production'ga chiqishni avtomatlashtirish bilan inson nazoratini yo'qotmaslik o'rtasidagi muvozanat: build va test to'liq avtomatik, lekin haqiqiy foydalanuvchilarga yetkazish qadami ongli, qo'lda tasdiqlangan qaror bo'lib qoladi.

Savol: Composite action va reusable workflow'ni qanday tanlaysiz — real vaziyatda qaysi birini tanlagan bo'lardingiz?

Javob: Agar bitta workflow ichida takrorlanadigan bir nechta qadam bo'lsa (masalan, "Flutter o'rnatish + kesh tiklash + pub get" har bir job'da qaytarilsa), composite action shu qadamlarni bitta uses: qatoriga jamlaydi. Agar butun pipeline (bir nechta job, matrix, deploy mantig'i bilan) bir nechta repo orasida bir xil bo'lishi kerak bo'lsa — masalan, tashkilotdagi barcha Flutter mikroservis-ilovalari bir xil "analyze → test → build → deploy" jarayonidan o'tishi kerak bo'lsa — reusable workflow (workflow_call) to'g'ri tanlov, chunki markazlashgan yangilash imkonini beradi (bitta joyni o'zgartirsangiz, barcha repolar yangi mantiqni oladi).

Savol: concurrency guruhisiz jamoa ishlaganda qanday muammo yuzaga keladi?

Javob: Har bir push (hatto bir necha soniya ichida ketma-ket kelgan push'lar ham) o'zining to'liq workflow run'ini boshlaydi va oxirigacha ishlaydi — hech biri bekor qilinmaydi. Natijada: (1) CI daqiqalari behuda sarflanadi (eskirgan kod uchun build hali ham to'liq bajariladi), (2) PR sahifasida bir nechta run parallel "Running" holatida turadi, qaysi biri eng so'nggi kodni aks ettirishini aniqlash chalkashtiradi, (3) agar runner'lar cheklangan bo'lsa, navbat uzayadi va haqiqiy natija kechikadi.

Savol: Nega Android va iOS build'larini bitta runs-on: macos-latest job'ida birlashtirish yomon amaliyot hisoblanadi?

Javob: macOS runner Linux runner'dan sezilarli qimmat (~10x), shuning uchun Android build (unga macOS kerak emas, Linux'da bemalol ishlaydi) uchun ham macOS narxini to'lash — behuda xarajat. To'g'ri yondashuv — ikkita alohida job: Android uchun ubuntu-latest, iOS uchun macos-latest, ular parallel ishlaydi va umumiy narx ham, umumiy vaqt ham kamayadi (Linux job tezroq boshlanadi, chunki bu runner'lar odatda ko'proq va navbat qisqaroq).

Savol: Branch protection'da "required status check" sifatida tanlangan job workflow faylidan o'chirilsa nima bo'ladi?

Javob: GitHub bu holatda PR'ni "kutilayotgan" holatda cheksiz ushlab turadi — chunki tizim kerakli check hech qachon kelmasligini avtomatik tushunmaydi, u faqat "hali tugamadi" deb hisoblaydi. Bu — real jamoalarda uchraydigan noqulay holat: workflow job nomi o'zgartirilsa yoki fayl o'chirilsa, PR'lar sababsiz bloklanib qoladi. Shuning uchun job nomini o'zgartirishdan oldin branch protection sozlamalarini ham yangilash kerak.

Savol: actions/cache va actions/upload-artifact orasidagi maqsad farqini tushuntiring.

Javob: cache — takroriy run'lar orasida (bugungi build va ertagi build) vaqt tejash uchun, ma'lumot ehtiyotkorlik bilan "eski bo'lishi mumkin" deb qaraladi va key mos kelmasa e'tiborsiz qoldiriladi. artifact — bitta workflow run ichidagi job'lar orasida ma'lumot (masalan, qurilgan APK) aniq va ishonchli uzatish uchun, va odatda run tugagandan keyin ham (standart 90 kun) saqlanib, qo'lda yuklab olish yoki keyingi run'da audit qilish uchun mavjud bo'ladi. Ular bir-birining o'rnini bosmaydi — ikkalasi ham turli maqsadga xizmat qiladi.

Savol: Self-hosted runner ishlatishning eng katta xavfsizlik xavfi nima, ayniqsa public repo uchun?

Javob: Public repo'da har kim fork qilib PR ochishi mumkin, va agar workflow'lar self-hosted runner'da ishga tushadigan qilib sozlangan bo'lsa (GitHub buni ochiq maslahat sifatida ta'kidlaydi), begona PR kodini o'z serveringizda bajarish imkoniyatiga ega bo'ladi — bu potensial ravishda serveringizga (va u orqali ichki tarmog'ingizga) kirish eshigini ochib qo'yishi mumkin. Shu sabab self-hosted runner'lar odatda faqat private repo'larda yoki fork PR'lar uchun alohida, cheklangan sozlamalar (masalan, "Require approval for first-time contributors") bilan ishlatiladi.

Savol: workflow_dispatch qanday amaliy holatlarda foydali, avtomatik trigger'lar yetarli bo'lmaydi?

Javob: Masalan: (1) muayyan staging build'ni QA jamoasi so'rovi bo'yicha istalgan vaqtda qayta yig'ish, (2) hotfix'ni production'ga favqulodda, oddiy "tag push" jarayonini kutmasdan chiqarish, (3) ma'lum bir eski commit'dan build yig'ish (masalan, regressiya tekshirish uchun). inputs orqali parametr (qaysi branch, qaysi flavor) qabul qilingani uchun bitta workflow bir nechta qo'lda boshqariladigan stsenariyga xizmat qila oladi, alohida workflow fayl yaratmasdan.

Savol: needs: bilan job'lar zanjiri qurilganda, agar zanjirdagi birinchi job muvaffaqiyatsiz bo'lsa, keyingilari avtomatik o'tkazib yuboriladimi?

Javob: Ha, standart holatda — agar needs: orqali ko'rsatilgan job muvaffaqiyatsiz tugasa, undan keyingi (unga bog'liq) job'lar avtomatik "skipped" holatida qoladi, ishga tushmaydi. Agar muvaffaqiyatsizlikdan qat'i nazar keyingi job'ni baribir ishga tushirish kerak bo'lsa (masalan, test natijasidan qat'i nazar Slack'ga xabar yuborish uchun), buni aniq if: always() yoki if: failure() sharti bilan ko'rsatish kerak.

Ko'p uchraydigan xato javoblar#

Savol/vaziyatXato javobTo'g'ri javob
"Sirlarni qayerda saqlaysiz?"".env faylida, repo'ga qo'shib qo'yamiz"GitHub Secrets'da (repo yoki Environment darajasida), hech qachon repo ichida
"Kesh nega ishlamayapti?""Kesh umuman ishonchsiz, ishlatmayman"Kesh key'i noto'g'ri tanlangan (odatda lockfile hash'i yetishmayapti) — sabab shu, kesh mexanizmining o'zi emas
"iOS va Android build'ini qanday tashkil qilasiz?""Bittasida, macos-latestda, ikkalasini ham"Alohida job'larda — Android ubuntu-latestda (arzon), iOS macos-latestda
"Production'ga qanday deploy qilasiz?""mainga push bo'lsa avtomatik"Environment + required reviewer orqali, inson tasdig'idan keyin
"Bir PR'ga bir nechta push kelsa nima bo'ladi?""Har biri alohida to'liq run bo'lib ishlayveradi"concurrency + cancel-in-progress bilan eskilari avtomatik bekor qilinadi
Amaliy topshiriq

Matrix build va Environment tasdig'i bilan workflow yozing

O'z (yoki namunaviy) Flutter loyihangiz uchun to'liq .github/workflows/release.yml yozing: test job'i (analyze + test), undan keyin build job'i matrix orqali kamida ikkita flavor va ikkita platforma (android/ios) kombinatsiyasida ishlaydigan, va nihoyat deploy job'i — faqat production Environment orqali, tasdiqdan keyin ishga tushadigan qilib. Har bir dizayn qaroringizni (nega alohida job, nega shu kesh strategiyasi) bir jumlada asoslang.

Maslahatni ko'rsatish

strategy.matrix'da kamida ikkita flavor va ikkita platforma bering, runs-on'ni platforma bo'yicha shartli tanlang, keyin alohida deploy job'ini needs: bilan bog'lab, environment: production ostiga qo'ying.