↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 10 — Konu 46: CI/CD

4 dk okuma #flutter
Dizi · 46/61 Flutter Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
  3. Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
  4. Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
  5. Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
  6. Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
  7. Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
  8. Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
  9. Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
  10. Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
  11. Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
  12. Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
  13. Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
  14. Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
  15. Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
  16. Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
  17. Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
  18. Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
  19. Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
  20. Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
  21. Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
  22. Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
  23. Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
  24. Bölüm 6 — Konu 24: Provider Paketi
  25. Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
  26. Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
  27. Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
  28. Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
  29. Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
  30. Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
  31. Bölüm 7 — Konu 31: Deep Linking
  32. Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
  33. Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
  34. Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
  35. Bölüm 8 — Konu 35: Implicit Animasyonlar
  36. Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
  37. Bölüm 8 — Konu 37: Hero Animasyonları
  38. Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
  39. Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
  40. Bölüm 9 — Konu 40: Platform Channels
  41. Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
  42. Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
  43. Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
  44. Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
  45. Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
  46. Bölüm 10 — Konu 46: CI/CD
  47. Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
  48. Bölüm 10 — Konu 48: DevTools Profiling
  49. Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
  50. Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
  51. Bölüm 11 — Konu 51: Supabase Alternatifi
  52. Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
  53. Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
  54. Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
  55. Bölüm 12 — Konu 55: Flutter Web / Desktop
  56. Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
  57. Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
  58. Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
  59. Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
  60. Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
  61. Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
Dizinin sayfası →
İçindekiler 11 başlık
  1. CI/CD Nedir? İki Kavramı Ayıralım
  2. Neden Otomatikleştiresin?
  3. GitHub Actions ile Basit Bir CI Pipeline'ı
  4. pull_request Tetikleyicisinin Gücü — "Kapı Bekçisi" Rolü
  5. Matrix Build — Birden Fazla Ortamda Test Etme
  6. Önbellekleme (Caching) — Hızı Artırma
  7. Mobil Build'e Özgü Bir Zorluk — iOS için macOS Gerekir
  8. Codemagic / Fastlane — Mobil-Özel CI/CD Araçları
  9. Basit Bir Zihinsel Model — CI Pipeline'ının Aşamaları
  10. 🎯 Bu Dersten Çıkarılması Gerekenler
  11. 📝 Ödevler

Konu 45'te testler yazmayı öğrendik — ama testler, sadece senin bilgisayarında elle çalıştırdığında faydalıdır, kimse her zaman hatırlayıp çalıştırmaz. Bu ders, testleri (ve build sürecini) otomatikleştirmeyi — yani her kod değişikliğinde kendiliğinden çalışmasını sağlamayı öğretiyor.

CI/CD Nedir? İki Kavramı Ayıralım

CI (Continuous Integration — Sürekli Entegrasyon): Kod her push edildiğinde ya da bir pull request açıldığında, otomatik olarak testlerin çalıştırılması ve kodun derlenebilir olduğunun doğrulanması. Amaç: "bu değişiklik, projeyi bozmuyor" garantisini insan hatırlamadan almak.

CD (Continuous Deployment/Delivery — Sürekli Dağıtım): CI başarılı olduktan sonra, uygulamanın otomatik olarak bir test ortamına, ya da Bölüm 11'de göreceğimiz gibi doğrudan Play Store/App Store'a dağıtılması.

Analoji: CI, Bölüm 10 Konu 45'teki testlerin "her zaman, kendiliğinden çalışan" versiyonu; CD ise Bölüm 9 Konu 44'teki build/imzalama sürecinin "her zaman, kendiliğinden çalışan" versiyonu. CI/CD, yeni bir kavram değil — önceki iki dersin otomatikleştirilmesidir.

Neden Otomatikleştiresin?

  • İnsan unutur, makine unutmaz. "Testleri çalıştırmayı unuttum, push ettim, ana branch bozuldu" — CI, bunu imkansız hale getirir (testler geçmezse, değişiklik birleştirilemez).
  • Takım büyüdükçe kritikleşir. Bölüm 7'de öğrendiğimiz Dependency Inversion gibi — tek başına çalışırken "disiplin" yeterliyken, birden fazla kişi aynı kod tabanına dokunduğunda, otomatik bir kapı bekçisi gerekir.
  • Hızlı geri bildirim. Bir hata, senin bilgisayarında saatler sonra fark edilmek yerine, push ettikten dakikalar sonra raporlanır.

GitHub Actions ile Basit Bir CI Pipeline'ı

yaml
# .github/workflows/flutter-ci.yml
name: Flutter CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4          # kodu indir

      - uses: subosito/flutter-action@v2   # Flutter SDK'yı kur
        with:
          flutter-version: '3.24.0'
          channel: 'stable'

      - run: flutter pub get               # bağımlılıkları indir

      - run: flutter analyze                # statik kod analizi (birazdan detaylandıracağız)

      - run: flutter test                   # Bölüm 10 Konu 45'teki tüm unit/widget testleri

Parça parça inceleyelim:

on: push / pull_request — bu pipeline'ın ne zaman tetikleneceğini belirtir; burada, main branch'ine her push'ta ve her pull request'te çalışacak.

runs-on: ubuntu-latest — GitHub, senin için geçici, temiz bir sanal makine ayağa kaldırır — Bölüm 9'da öğrendiğimiz kendi bilgisayarındaki geliştirme ortamından bağımsız, her seferinde sıfırdan, aynı bir ortam.

steps: — Dart Bölüm 4'te öğrendiğimiz List yapısına benzer, sırayla çalışacak komutların listesi. Her adım başarısız olursa, pipeline durur ve "failed" olarak işaretlenir.

flutter analyze — Bölüm 10'un ileride (Konu 47-48) daha derin işleyeceğimiz statik analiz aracı; kodun çalıştırılmadan, sadece okunarak (potansiyel hatalar, stil sorunları, kullanılmayan değişkenler gibi) taranmasıdır — flutter test'ten önce çalıştırmak, hızlı ve ucuz bir ilk filtre sağlar.

pull_request Tetikleyicisinin Gücü — "Kapı Bekçisi" Rolü

GitHub'da (ve benzer platformlarda), bir repository'nin ayarlarından, CI geçmeden bir PR'ın birleştirilemeyeceğini ("required status check") zorunlu kılabilirsin. Bu, CI'ın asıl gücünü ortaya koyar — artık "testleri çalıştırmayı unuttum" diye bir kod ana branch'e giremez, çünkü GitHub, CI kırmızı (başarısız) olduğu sürece "Merge" butonunu devre dışı bırakır.

Matrix Build — Birden Fazla Ortamda Test Etme

yaml
jobs:
  test:
    strategy:
      matrix:
        flutter-version: ['3.22.0', '3.24.0']
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
        with:
          flutter-version: ${{ matrix.flutter-version }}
      - run: flutter test

strategy: matrix, Dart Bölüm 9'da öğrendiğimiz generic kavramına biraz benzer bir fikir taşır — aynı pipeline'ı, farklı parametrelerle (burada farklı Flutter sürümleriyle) paralel olarak birden fazla kez çalıştırır. Bir kütüphane/paket geliştiriyorsan (Bölüm 12 Konu 58'i hatırla), kullanıcılarının farklı Flutter sürümlerinde de çalıştığından emin olmak için değerlidir.

Önbellekleme (Caching) — Hızı Artırma

yaml
- uses: actions/cache@v4
  with:
    path: |
      ~/.pub-cache
      **/.dart_tool
    key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}

Her pipeline çalıştığında sıfırdan tüm paketleri (Bölüm 1'de öğrendiğimiz pubspec.yaml bağımlılıkları) indirmek zaman kaybıdır. actions/cache, pubspec.lock değişmediği sürece, önceki çalıştırmadan indirilen paketleri yeniden kullanır — bu, büyük projelerde CI süresini dakikalarca kısaltabilir.

Mobil Build'e Özgü Bir Zorluk — iOS için macOS Gerekir

Bölüm 9 Konu 44'te öğrendiğimiz gibi, iOS build'i Xcode gerektirir, ve Xcode sadece macOS'ta çalışır. Bu, CI ortamı için önemli bir kısıtlama getirir:

yaml
jobs:
  build-ios:
    runs-on: macos-latest  # Android'den FARKLI olarak, macOS runner ZORUNLU
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - run: flutter build ios --release --no-codesign

runs-on: macos-latest — GitHub Actions'ın macOS sanal makineleri mevcuttur ama Linux/Windows makinelere göre daha yavaş ve daha pahalıdır (kullanım kotası daha hızlı tükenir). Bu yüzden pratikte, çoğu takım unit/widget testleri ucuz Linux runner'larda, sadece gerçek iOS build/dağıtımını macOS runner'da çalıştırır.

Codemagic / Fastlane — Mobil-Özel CI/CD Araçları

GitHub Actions genel amaçlıdır (herhangi bir dil/proje için) — mobil geliştirmeye özel olarak tasarlanmış araçlar da var:

  • Codemagic: Flutter'a özel, imzalama sertifikalarını/provisioning profillerini yöneten arayüzü olan, sıfır-konfigürasyona yakın bir CI/CD servisi. Bölüm 9 Konu 44'te gördüğümüz "imzalama karmaşıklığını" büyük ölçüde basitleştirir.
  • Fastlane: Ruby tabanlı, Android/iOS build + imzalama + mağazaya otomatik yükleme (Bölüm 11 Konu 53) adımlarını script'leyen bir araç — GitHub Actions'ın içinde bir adım olarak da çağrılabilir.

Pratik tavsiye: Küçük/orta projelerde GitHub Actions (test + analyze için) + Codemagic (mobil build/dağıtım için) kombinasyonu yaygındır; büyük/kurumsal takımlarda Fastlane, tüm süreci tek bir script altında birleştirmek için tercih edilir.

Basit Bir Zihinsel Model — CI Pipeline'ının Aşamaları

metin
push/PR → checkout → Flutter kur → pub get → analyze → test → (opsiyonel) build → (opsiyonel) dağıt

Her aşama, bir öncekinin başarılı olmasına bağlıdır — bu, Dart Bölüm 5'te öğrendiğimiz sıralı await zinciri mantığına (bir işlem bitmeden diğeri başlamaz) kavramsal olarak benzer.


🎯 Bu Dersten Çıkarılması Gerekenler

  • CI, her push/PR'da testlerin otomatik çalışmasıdır; CD, CI başarılı olduktan sonra otomatik dağıtımdır — ikisi de, Konu 45'teki test yazımı ve Konu 44'teki build sürecinin otomatikleştirilmiş halidir.
  • GitHub Actions'ta bir workflow, on: (ne zaman tetiklenir) ve steps: (sırayla çalışacak komutlar) ile tanımlanır.
  • pull_request tetikleyicisi + "required status check" ayarı, CI'ı gerçek bir kapı bekçisine dönüştürür.
  • strategy: matrix, aynı pipeline'ı birden fazla ortamda (örn. farklı Flutter sürümleri) paralel test etmeyi sağlar.
  • Önbellekleme (actions/cache), her çalıştırmada paketlerin sıfırdan indirilmesini önleyerek CI süresini kısaltır.
  • iOS build'i macOS runner gerektirir (daha yavaş/pahalı); Codemagic/Fastlane, mobil-özel imzalama/dağıtım karmaşıklığını basitleştiren araçlardır.

📝 Ödevler

  • [ ] GitHub Actions ile, her push'ta flutter analyze + flutter test çalıştıran basit bir workflow kur (bu dersteki temel örneği kullanabilirsin).
  • [ ] Repository ayarlarından, bu CI check'ini main branch için zorunlu hale getir, testi bilerek bozup bir PR'ın birleştirilemediğini gözlemle.
  • [ ] actions/cache ekleyerek, pipeline süresinin (cache'li ve cache'siz çalıştırma arasında) ne kadar değiştiğini ölç.
  • [ ] Kendi cümlelerinle, "neden iOS build'inin CI'da macOS runner gerektirdiğini", Bölüm 9 Konu 44'teki Xcode bilgisiyle ilişkilendirerek açıkla.

Sıradaki konu: Bölüm 10 — Konu 47: Rebuild Optimizasyonu (const, key Kullanımı)