← Kursa Dön
📄 Text · 30 min

CI Pipeline

Giriş — Otomatik Kalite Güvencesi

Diyelim ki büyük bir yazılım ekibindesin. Her gün onlarca PR açılıyor. Bir PR'ı review ederken "lint hatası var mı?", "testler geçiyor mu?", "build bozulmuş mu?" sorularını elle kontrol etmek insanüstü bir çaba gerektirir. Birisi bir typo yapıyor, birisi unused import bırakıyor, birisi test yazmayı unutuyor.

İşte CI pipeline bu kaosun panzehiri. Her PR açıldığında, her push yapıldığında otomatik olarak kod kalitesini kontrol eden, testleri çalıştıran, build'i doğrulayan bir sistem. "İnsan hata yapar, makine yapmaz" — CI'ın felsefesi bu.

Bu derste bir CI pipeline'ının her katmanını öğreneceksin: lint ile kod stilini, test ile doğruluğu, build ile çalışabilirliği kontrol etmeyi; artifact'larla çıktıları saklamayı; status badge'lerle durumu görselleştirmeyi; branch protection ile merge'i korumalı hale getirmeyi göreceğiz.


🎬 Analoji: Yiyecek Fabrikası Kalite Kontrol Hattı

Bir çikolata fabrikasını düşün. Çikolatalar üretim bandından geçerken birden fazla kalite kontrol noktası var:

  1. Görsel Kontrol (Lint): Çikolatanın şekli düzgün mü? Çatlak var mı? → Kod stil kurallarına uyuyor mu?

  2. Tat Testi (Unit Test): Tadı doğru mu? Acı, tatlı, tuzlu oranları tutarlı mı? → Fonksiyonlar beklenen çıktıyı veriyor mu?

  3. Paketleme (Build): Kutulama düzgün mü? Etiket doğru mu? → Kod derlenip paketlenebiliyor mu?

  4. Sertifika (Status Badge): "ISO 9001" damgası vur → "CI Passing" badge'i

Bir kontrol noktasını geçemeyen ürün hattan çıkarılır (PR merge edilemez).

PR Açıldı
    │
    ▼
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  🔍 Lint │───►│ 🧪 Test  │───►│ 🏗️ Build │───►│ 📦 Artifact│
│          │    │          │    │          │    │          │
│ ESLint   │    │ Jest     │    │ tsc/vite │    │ dist/    │
│ Prettier │    │ Coverage │    │ webpack  │    │ upload   │
└──────────┘    └──────────┘    └──────────┘    └──────────┘
    │ ❌             │ ❌             │ ❌
    │                │                │
    ▼                ▼                ▼
  Merge           Merge            Merge
  ENGELLENDİ      ENGELLENDİ      ENGELLENDİ

Katman 1: Lint — Kod Stilini Kontrol Et

Lint Nedir?

Lint (veya linter), kodun stil kurallarına uygunluğunu kontrol eden araçtır. Hata bulmaz — kodun okunabilirliğini, tutarlılığını ve yaygın kötü pratikleri tespit eder.

Lint'in yakaladığı sorunlar:
─────────────────────────────
✗ Kullanılmayan değişkenler (unused variables)
✗ Tanımlanmamış değişkenler
✗ Tutarsız kodlama stili (tab vs space, single vs double quote)
✗ console.log kalıntıları
✗ Potansiyel hatalar (== yerine ===)
✗ Erişilemez kod (unreachable code)
✗ Boş catch blokları

ESLint Workflow Adımı

jobs:
  lint:
    name: 🔍 Code Quality
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      # ESLint — Kod kalitesi
      - name: Run ESLint
        run: npx eslint . --format=compact
        # --format=compact → daha okunabilir CI çıktısı

      # Prettier — Kod formatlama
      - name: Check formatting
        run: npx prettier --check .
        # --check = sadece kontrol (düzeltme yapmaz)
        # --write = düzeltir (CI'da kullanma, PR'da kullan)

      # TypeScript — Tip kontrolü
      - name: Type check
        run: npx tsc --noEmit
        # --noEmit = dosya üretme, sadece tipleri kontrol et

Lint Sonuçlarını PR'a Yorum Olarak Ekle

  lint:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci

      - name: Run ESLint
        id: eslint
        run: npx eslint . --format json --output-file eslint-report.json || true

      - name: Annotate ESLint results
        uses: ataylorme/eslint-annotate-action@v3
        with:
          report-json: eslint-report.json

Sonuç: ESLint hataları PR'daki ilgili satırlarda annotation olarak görünür:

src/auth.js
────────────────────────────────────────────────
Line 12: 'password' is defined but never used.  (no-unused-vars) ⚠️
Line 25: Expected '===' and instead saw '=='.   (eqeqeq) ⚠️

Katman 2: Test — Kodun Doğruluğunu Kontrol Et

Test Türleri

┌─────────────────────────────────────────────────────────────┐
│                    TEST PİRAMİDİ                             │
│                                                             │
│                    /\                                        │
│                   /  \     E2E (End-to-End) Tests           │
│                  /    \    → Yavaş, az sayıda, tam akış     │
│                 /──────\                                     │
│                /        \  Integration Tests                 │
│               /          \ → Orta hız, modüller arası       │
│              /────────────\                                  │
│             /              \ Unit Tests                      │
│            /                \ → Hızlı, çok sayıda, tek birim│
│           /──────────────────\                               │
│                                                             │
│  CI'da çalıştırılacaklar:                                   │
│  ✅ Unit Tests → Her PR'da (hızlı)                          │
│  ✅ Integration Tests → Her PR'da (orta)                    │
│  ⚠️ E2E Tests → Main merge veya nightly (yavaş)            │
└─────────────────────────────────────────────────────────────┘

Jest ile Test Çalıştırma

jobs:
  test:
    name: 🧪 Tests
    runs-on: ubuntu-latest
    needs: lint

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      # Unit testleri çalıştır
      - name: Run unit tests
        run: npm test -- --coverage --ci
        env:
          CI: true
        # --coverage → kapsam raporu üret
        # --ci → CI modunda çalış (watch mode kapalı, snapshot güncellemesi yok)

Test Coverage (Kapsam)

Test coverage, kodun ne kadarının testlerle kapsandığını gösterir:

# Terminal çıktısı:
$ npm test -- --coverage

----------|---------|----------|---------|---------|
File      | % Stmts | % Branch | % Funcs | % Lines |
----------|---------|----------|---------|---------|
All files |   85.71 |    75.00 |   90.00 |   85.71 |
 auth.js  |  100.00 |   100.00 |  100.00 |  100.00 |
 user.js  |   71.43 |    50.00 |   80.00 |   71.43 |
----------|---------|----------|---------|---------|
      # Coverage eşik kontrolü
      - name: Check coverage threshold
        run: |
          npx jest --coverage --coverageReporters=json-summary
          node -e "
            const coverage = require('./coverage/coverage-summary.json');
            const total = coverage.total;
            const lines = total.lines.pct;
            console.log('Line coverage: ' + lines + '%');
            if (lines < 80) {
              console.error('Coverage is below 80%!');
              process.exit(1);
            }
          "

Veritabanı ile Test (Service Container)

Testlerin veritabanına ihtiyaç duyuyorsa, GitHub Actions service container sağlar:

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7
        ports:
          - 6379:6379

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - name: Run tests with database
        run: npm test
        env:
          DATABASE_URL: postgres://test:test@localhost:5432/testdb
          REDIS_URL: redis://localhost:6379

Python Projelerinde Test

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install pytest pytest-cov

      - name: Run tests
        run: pytest --cov=src --cov-report=xml

      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage-py${{ matrix.python-version }}
          path: coverage.xml

Katman 3: Build — Derlenip Paketlenebiliyor mu?

Neden Build Kontrolü?

Kod lint'ten geçti, testler başarılı — ama bu "production'a deploy edilebilir" anlamına gelmiyor. Build adımı şunları doğrular:

Build kontrolünün yakaladığı sorunlar:
─────────────────────────────────────────
✗ TypeScript derleme hataları
✗ Import edilen ama kurulmamış paketler
✗ Environment variable eksiklikleri
✗ Asset (resim, font) referans hataları
✗ Webpack/Vite yapılandırma sorunları
✗ Tree-shaking sonrası bozulan kodlar

Build Workflow Adımı

jobs:
  build:
    name: 🏗️ Build
    runs-on: ubuntu-latest
    needs: [lint, test]    # Lint ve test başarılıysa çalış

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - name: Build project
        run: npm run build
        env:
          NODE_ENV: production

      # Build çıktısını kontrol et
      - name: Verify build output
        run: |
          ls -la dist/
          if [ ! -f dist/index.html ]; then
            echo "❌ index.html not found in build output!"
            exit 1
          fi
          echo "✅ Build output verified"

      # Build boyutunu göster
      - name: Report build size
        run: |
          echo "Build size:"
          du -sh dist/
          echo ""
          echo "File details:"
          find dist -type f -name "*.js" -exec du -h {} +

Artifact — Build Çıktılarını Sakla

Artifact, bir job'un ürettiği dosyaları saklama mekanizmasıdır. Build çıktısı, test raporları, coverage dosyaları — bunları artifact olarak yükleyebilirsin.

Artifact Yükleme ve İndirme

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run build

      # Artifact yükle
      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: build-output          # Artifact adı
          path: dist/                 # Yüklenecek dosya/dizin
          retention-days: 7           # 7 gün sakla (varsayılan: 90)
          if-no-files-found: error    # Dosya yoksa hata ver

  deploy:
    runs-on: ubuntu-latest
    needs: build
    steps:
      # Artifact indir (başka job'dan)
      - name: Download build artifact
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: dist/

      - name: Deploy
        run: |
          ls -la dist/
          # deploy komutu...

Test Raporu Artifact'ı

      - name: Run tests
        run: npm test -- --ci --coverage

      - name: Upload test results
        if: always()    # Testler başarısız olsa bile yükle!
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: |
            coverage/
            test-results/
            junit-report.xml
GitHub UI'da Artifact'lar:

Actions → Workflow Run → Artifacts bölümü:
┌─────────────────────────────────────────────┐
│ Artifacts                                    │
│                                             │
│ 📦 build-output (2.3 MB)    [Download ⬇️]   │
│ 📦 test-results (156 KB)    [Download ⬇️]   │
│ 📦 coverage-report (89 KB)  [Download ⬇️]   │
│                                             │
│ These artifacts expire in 7 days            │
└─────────────────────────────────────────────┘

💡 İpucu: if: always() eklemeyi unutma! Testler başarısız olduğunda artifact yüklenmezse, hata nedenini araştırmak zorlaşır. Test raporları özellikle başarısız olduğunda en çok işine yarar.


Status Badge — Durumu Görselleştir

README.md'ye CI durumunu gösteren bir badge ekle:

Badge URL Formatı

<!-- README.md -->
# Projem

![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg)
![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg?branch=develop)
Badge görünümü:

  Başarılı:  [CI ✅ passing]  (yeşil)
  Başarısız: [CI ❌ failing]  (kırmızı)
  Çalışıyor: [CI 🔄 running] (sarı)

Badge Ekleme (GitHub UI)

1. Repository → Actions → Sol menüden workflow seç
2. Sağ üstte "..." menüsü → "Create status badge"
3. Branch seç, Markdown'ı kopyala
4. README.md'ye yapıştır

Birden Fazla Badge

# Projem

[![CI](https://github.com/user/repo/actions/workflows/ci.yml/badge.svg)](https://github.com/user/repo/actions/workflows/ci.yml)
[![Deploy](https://github.com/user/repo/actions/workflows/deploy.yml/badge.svg)](https://github.com/user/repo/actions/workflows/deploy.yml)
[![codecov](https://codecov.io/gh/user/repo/branch/main/graph/badge.svg)](https://codecov.io/gh/user/repo)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Branch Protection — Merge'i Koruma Altına Al

CI pipeline'ın var ama birisi pipeline çalışmadan veya başarısız olmasına rağmen merge edebilir. Branch protection rules bunu engeller.

Branch Protection Ayarlama

GitHub → Repository → Settings → Branches
→ "Add branch protection rule"

Branch name pattern: main

☑ Require a pull request before merging
  ☑ Require approvals: 1 (minimum review sayısı)
  ☑ Dismiss stale pull request approvals when new commits are pushed
    → Yeni commit gelince eski approval'ları iptal et

☑ Require status checks to pass before merging  ← EN ÖNEMLİ!
  ☑ Require branches to be up to date before merging
  Status checks:
    → lint ✓
    → test ✓
    → build ✓

☑ Require conversation resolution before merging
  → Tüm review yorumları çözülmeli

☑ Do not allow bypassing the above settings
  → Admin bile kuralları atlayamaz

Nasıl Çalışır?

PR açıldı → CI pipeline başladı:

  ┌──────┐     ┌──────┐     ┌───────┐
  │ lint │────►│ test │────►│ build │
  │  ✅  │     │  ✅  │     │  ✅   │
  └──────┘     └──────┘     └───────┘

Branch protection kontrolleri:
  ✅ lint — passed
  ✅ test — passed
  ✅ build — passed
  ✅ 1 approval received
  ✅ No unresolved conversations

  ┌─────────────────────────┐
  │  ✅ Merge pull request   │  ← Aktif (tıklanabilir)
  └─────────────────────────┘
PR açıldı → CI pipeline başladı:

  ┌──────┐     ┌──────┐
  │ lint │────►│ test │
  │  ✅  │     │  ❌  │  ← Test başarısız!
  └──────┘     └──────┘

Branch protection kontrolleri:
  ✅ lint — passed
  ❌ test — failed           ← Bu yüzden merge engellenmiş
  ⏭️ build — skipped
  ✅ 1 approval received

  ┌─────────────────────────┐
  │  🚫 Merge pull request  │  ← Devre dışı (tıklanamaz)
  │  "Required checks failed"│
  └─────────────────────────┘

Required Status Checks Ayarlama

# ci.yml'deki job isimleri ile branch protection'daki
# status check isimleri eşleşmeli:

jobs:
  lint:                    # ← Branch protection'da "lint" olarak görünür
    name: 🔍 Lint
    runs-on: ubuntu-latest
    ...

  test:                    # ← Branch protection'da "test" olarak görünür
    name: 🧪 Test
    runs-on: ubuntu-latest
    ...

⚠️ Dikkat: Matrix strategy kullanıyorsan, her matrix kombinasyonu ayrı bir status check olarak görünür. test (18), test (20), test (22) gibi. Hepsini required olarak ekle veya tek bir "summary" job oluştur.

Matrix ile Çalışan Required Check Pattern

jobs:
  test:
    strategy:
      matrix:
        node-version: [18, 20, 22]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci && npm test

  # Tüm test job'larını toplayan "gate" job:
  test-gate:
    name: ✅ All Tests Passed
    runs-on: ubuntu-latest
    needs: test           # Tüm matrix job'ları tamamlanınca
    if: always()
    steps:
      - name: Check test results
        run: |
          if [ "${{ needs.test.result }}" != "success" ]; then
            echo "❌ Some tests failed!"
            exit 1
          fi
          echo "✅ All tests passed!"

# Branch protection'da sadece "✅ All Tests Passed" check'ini ekle
# Tek bir check ile tüm matrisi kapsa

Tam CI Pipeline: Gerçek Dünya Örneği

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
    paths-ignore: ['**.md', 'docs/**']
  pull_request:
    branches: [main]

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

permissions:
  contents: read
  pull-requests: write

env:
  NODE_VERSION: '20'

jobs:
  # ═══════════════════════════════════
  # Katman 1: Kod Kalitesi
  # ═══════════════════════════════════
  lint:
    name: 🔍 Lint & Format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - name: ESLint
        run: npx eslint . --max-warnings=0
      - name: Prettier
        run: npx prettier --check .
      - name: TypeScript
        run: npx tsc --noEmit

  # ═══════════════════════════════════
  # Katman 2: Testler
  # ═══════════════════════════════════
  test:
    name: 🧪 Test (Node ${{ matrix.node }})
    runs-on: ubuntu-latest
    needs: lint
    strategy:
      fail-fast: false
      matrix:
        node: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: 'npm'
      - run: npm ci
      - name: Unit & Integration Tests
        run: npm test -- --ci --coverage
      - name: Upload coverage (Node 20 only)
        if: matrix.node == 20 && always()
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage/

  # ═══════════════════════════════════
  # Katman 3: Build
  # ═══════════════════════════════════
  build:
    name: 🏗️ Build
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - name: Upload build
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
          retention-days: 7

  # ═══════════════════════════════════
  # Gate: Tüm Kontroller Başarılı mı?
  # ═══════════════════════════════════
  ci-gate:
    name: ✅ CI Passed
    runs-on: ubuntu-latest
    needs: [lint, test, build]
    if: always()
    steps:
      - name: Verify all checks
        run: |
          echo "Lint: ${{ needs.lint.result }}"
          echo "Test: ${{ needs.test.result }}"
          echo "Build: ${{ needs.build.result }}"
          
          if [ "${{ needs.lint.result }}" != "success" ] || \
             [ "${{ needs.test.result }}" != "success" ] || \
             [ "${{ needs.build.result }}" != "success" ]; then
            echo "❌ CI failed!"
            exit 1
          fi
          echo "✅ All CI checks passed!"
Pipeline Akış Diyagramı:

                    ┌─────────────┐
                    │   PR / Push │
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │  🔍 Lint    │
                    │  (ESLint,   │
                    │  Prettier,  │
                    │  TypeScript)│
                    └──┬─────┬───┘
                       │     │
              ┌────────▼─┐ ┌─▼────────┐
              │ 🧪 Test  │ │ 🏗️ Build │
              │ Node 18  │ │          │
              │ Node 20  │ │          │
              │ Node 22  │ │          │
              └────────┬─┘ └─┬────────┘
                       │     │
                    ┌──▼─────▼───┐
                    │ ✅ CI Gate  │
                    │ (required  │
                    │  check)    │
                    └────────────┘

Yaygın Hatalar

1. needs ile Lint ve Test'i Sıralı Yapmak

# ❌ Gereksiz bağımlılık — build lint'i bekliyor
jobs:
  lint:
    ...
  test:
    needs: lint    # OK: test lint'e bağımlı
    ...
  build:
    needs: test    # Yavaş: build da sıralı bekliyor
    ...

# ✅ Lint sonrası test ve build PARALEL:
jobs:
  lint:
    ...
  test:
    needs: lint    # Lint'e bağımlı
    ...
  build:
    needs: lint    # Lint'e bağımlı (test'e değil!)
    ...
❌ Sıralı (yavaş):
  lint (2dk) → test (3dk) → build (1dk) = 6 dk

✅ Paralel (hızlı):
  lint (2dk) → test (3dk)  } = 5 dk
             → build (1dk) }   (paralel)

2. if: always() Kullanmamak

# ❌ Test başarısız olunca coverage yüklenmez
- run: npm test -- --coverage
- uses: actions/upload-artifact@v4   # Test fail → bu step atlanır!
  with:
    name: coverage
    path: coverage/

# ✅ always() ile her zaman yükle
- run: npm test -- --coverage
- uses: actions/upload-artifact@v4
  if: always()                       # Test fail olsa bile yükle
  with:
    name: coverage
    path: coverage/

3. Branch Protection Status Check Uyumsuzluğu

# ❌ Workflow dosyasındaki job adını değiştirdin ama branch protection'ı güncellemedin
# Eski: lint → Yeni: code-quality
# Branch protection hâlâ "lint" arıyor → sürekli "pending" kalır

# ✅ Job adını değiştirirsen, branch protection settings'i de güncelle!

CI Pipeline En İyi Pratikleri

🏆 EN İYİ PRATİKLER:
────────────────────────────

1. HER ZAMAN cache kullan
   → npm ci 2 dakikadan 15 saniyeye düşer

2. Lint'i ilk çalıştır
   → En hızlı check; hata varsa test/build'a bile girme

3. fail-fast: false kullan
   → Hangi ortamlarda sorun olduğunu tam gör

4. paths-ignore ile gereksiz çalıştırmaları önle
   → README değişikliği CI tetiklemesin

5. concurrency ile eski workflow'ları iptal et
   → Kaynak israfını önle

6. Minimum permissions tanımla
   → Güvenlik için gerekli olmayan izinleri verme

7. CI gate job oluştur
   → Branch protection'da tek check yönetmek kolay

8. Artifact'ları retention-days ile sınırla
   → 90 gün yerine 7 gün yeterli, storage tasarrufu

9. npm ci kullan (npm install değil)
   → Deterministik build, package-lock.json'a sadık

10. Test çıktılarını always() ile yükle
    → Hata analizi için en kritik veri, başarısızlıkta gerekli

Özet

  • CI pipeline her PR ve push'ta otomatik kalite kontrolü sağlar — lint, test ve build katmanlarıyla kodun güvenilirliğini garanti eder

  • Lint (ESLint, Prettier) kod stilini kontrol eder — en hızlı check olduğu için pipeline'ın ilk adımı olmalıdır

  • Test (Jest, pytest) kodun doğruluğunu doğrular — coverage raporları ile test kapsamını ölç, matrix strategy ile farklı ortamlarda test et

  • Artifact'lar build çıktılarını ve test raporlarını saklar — if: always() ile başarısız olsa bile yükle, retention-days ile storage yönetimini kontrol et

  • Status badge'ler CI durumunu README'de görselleştirir — projenin sağlığını tek bakışta gösterir

  • Branch protection rules CI başarısız olduğunda merge'i engeller — Require status checks to pass ile kalite kapısı oluştur, CI gate job ile tüm check'leri tek noktada topla


*Bir sonraki derste CI'ın devamı olan CD (Continuous Deployment) pipeline'larını öğreneceğiz: Otomatik deploy, environment'lar, approval gate ve rollback!*