DevOps & Cloud

CI/CD Pipeline: GitHub Actions ile Otomatik Test ve Deployment

10 dk okuma17 Mart 2026
CI/CD pipelineGitHub ActionsCI/CD rehberiOtomatik deploymentGitHub Actions tutorialDevOpsContinuous integrationContinuous deploymentGitHub Actions DockerCI/CD .NET

CI/CD (Continuous Integration / Continuous Deployment), yazilim gelistirme surecinin en kritik bilesenlerinden biridir. GitHub Actions, kod degisikliklerini otomatik olarak test eden, build eden ve deploy eden guclu bir CI/CD platformudur. Bu yazida GitHub Actions ile .NET ve Flutter projeleri icin kapsamli CI/CD pipeline'lari olusturmayi, otomatik deployment stratejilerini ve production-ready workflow yapilandirmalarini detayli olarak inceleyecegim.

Kendi projelerimde GitHub Actions'a gecis yaptigimdan beri manuel deployment hatalarini sifira indirdim. Her push'ta otomatik test, build ve deployment surecleri sayesinde hem gelistirme hizim artti hem de production ortaminin guvenilirligi yukseldi.

GitHub Actions Temelleri

Workflow Yapisi

GitHub Actions workflow'lari .github/workflows/ dizininde YAML dosyalari olarak tanimlanir. Her workflow bir veya daha fazla job icerir ve her job bir dizi step'ten olusur.

Temel kavramlar:

  • Workflow: Otomatik surec tanimi (YAML dosyasi)
  • Event: Workflow'u tetikleyen olay (push, pull_request, schedule)
  • Job: Paralel veya sirali calisabilen is birimleri
  • Step: Job icindeki tek bir islem adimi
  • Action: Yeniden kullanilabilir is birimi (marketplace veya ozel)

.NET CI/CD Pipeline

Build, Test ve Deployment

yaml
# .github/workflows/dotnet-ci-cd.yml
name: .NET CI/CD Pipeline

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

env:
  DOTNET_VERSION: '8.0.x'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-test:
    runs-on: ubuntu-latest

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

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

    steps:
      - uses: actions/checkout@v4

      - name: .NET SDK kur
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: NuGet paketlerini cache'le
        uses: actions/cache@v4
        with:
          path: ~/.nuget/packages
          key: nuget-${{ hashFiles('**/*.csproj') }}
          restore-keys: nuget-

      - name: Restore
        run: dotnet restore

      - name: Build
        run: dotnet build --no-restore -c Release

      - name: Unit testleri calistir
        run: dotnet test --no-build -c Release --filter "Category!=Integration" --logger "trx;LogFileName=unit-tests.trx" --collect:"XPlat Code Coverage"

      - name: Integration testleri calistir
        run: dotnet test --no-build -c Release --filter "Category=Integration" --logger "trx;LogFileName=integration-tests.trx"
        env:
          ConnectionStrings__DefaultConnection: "Host=localhost;Database=testdb;Username=postgres;Password=postgres"
          Redis__ConnectionString: "localhost:6379"

      - name: Test sonuclarini yukle
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: "**/*.trx"

      - name: Code coverage raporu
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  docker-build:
    needs: build-and-test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Container registry'ye giris
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Docker metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha
            type=raw,value=latest

      - name: Docker imaji build ve push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy:
    needs: docker-build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production

    steps:
      - name: SSH ile sunucuya deploy
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /opt/myapp
            docker compose pull
            docker compose up -d --remove-orphans
            docker image prune -f

Flutter CI/CD Pipeline

Flutter Build ve Test

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

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

jobs:
  analyze-and-test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Flutter SDK kur
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.24.0'
          channel: stable
          cache: true

      - name: Bagimliliklari yukle
        run: flutter pub get

      - name: Kod analizi
        run: flutter analyze --fatal-infos

      - name: Testleri calistir
        run: flutter test --coverage

      - name: Coverage raporu
        uses: codecov/codecov-action@v4
        with:
          file: coverage/lcov.info

  build-android:
    needs: analyze-and-test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: Java kur
        uses: actions/setup-java@v4
        with:
          distribution: 'temurin'
          java-version: '17'

      - name: Flutter SDK kur
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.24.0'
          channel: stable
          cache: true

      - name: Keystore dosyasini decode et
        run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/app/keystore.jks

      - name: Android APK build
        run: flutter build apk --release
        env:
          KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
          STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}

      - name: APK artifact yukle
        uses: actions/upload-artifact@v4
        with:
          name: android-release
          path: build/app/outputs/flutter-apk/app-release.apk

  build-ios:
    needs: analyze-and-test
    runs-on: macos-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: Flutter SDK kur
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.24.0'
          channel: stable
          cache: true

      - name: iOS build
        run: flutter build ios --release --no-codesign

      - name: IPA artifact yukle
        uses: actions/upload-artifact@v4
        with:
          name: ios-release
          path: build/ios/iphoneos/Runner.app

Ileri Seviye Workflow Teknikleri

Secrets Yonetimi ve Guvenlik

GitHub Actions'da hassas verilerin guvenli yonetimi icin cok katmanli bir yaklasim benimsenmalidir:

  • Repository secrets: Tum workflow'larda kullanilabilen genel secretlar (API key'leri, token'lar)
  • Environment secrets: Production, staging gibi ortam bazli secret yonetimi. Environment bazli approval zorunlulugu eklenebilir
  • OIDC: AWS, Azure gibi cloud provider'lara secretsiz baglanmak icin OpenID Connect. Uzun omurlu credential'lar yerine kisa omurlu token'lar kullanir
yaml
# OIDC ile AWS'ye secretsiz erisim ornegi
permissions:
  id-token: write
  contents: read

steps:
  - name: AWS credentials (OIDC)
    uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789:role/github-actions-role
      aws-region: eu-central-1

  - name: ECR'ye giris
    uses: aws-actions/amazon-ecr-login@v2

OIDC kullanarak static access key'leri tamamen ortadan kaldirabilirsiniz. Bu yontem ozellikle AWS ve Azure entegrasyonlarinda guvenlik acisindan en iyi pratik olarak kabul edilir.

Ortam Bazli Deployment

Farkli ortamlar icin farkli yapilandirmalar kullanmak, deployment guvenligini artirir:

yaml
# Staging ve production icin ayri deployment job'lari
  deploy-staging:
    needs: docker-build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/develop'
    environment: staging
    steps:
      - name: Deploy to staging
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.STAGING_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /opt/myapp-staging
            docker compose pull
            docker compose up -d --remove-orphans

  deploy-production:
    needs: docker-build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production  # Manual approval gerektirir
    steps:
      - name: Deploy to production
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.PRODUCTION_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /opt/myapp
            docker compose pull
            docker compose up -d --remove-orphans
            docker image prune -f

Reusable Workflows

Tekrarlayan workflow parcalarini paylasabilir workflow'lara donusturun. Organizasyon genelinde standart CI/CD pratiklerini zorunlu kilmak icin cok etkilidir:

yaml
# .github/workflows/reusable-dotnet-build.yml
name: Reusable .NET Build

on:
  workflow_call:
    inputs:
      dotnet-version:
        required: true
        type: string
      project-path:
        required: true
        type: string
    secrets:
      CODECOV_TOKEN:
        required: false

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ inputs.dotnet-version }}
      - run: dotnet restore ${{ inputs.project-path }}
      - run: dotnet build ${{ inputs.project-path }} --no-restore -c Release
      - run: dotnet test ${{ inputs.project-path }} --no-build -c Release

Matrix Strategy

Birden fazla versiyon veya platform icin paralel test calistirmak icin matrix strategy kullanin:

yaml
# Matrix strategy ile coklu platform testi
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        dotnet-version: ['8.0.x', '9.0.x']
      fail-fast: false

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ matrix.dotnet-version }}
      - run: dotnet test -c Release

Caching Stratejileri

Build surelerini kisaltmak icin etkili cache stratejileri kullanin:

yaml
# Docker layer cache
- name: Docker build with cache
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: ${{ steps.meta.outputs.tags }}
    cache-from: type=gha
    cache-to: type=gha,mode=max

# NuGet package cache
- uses: actions/cache@v4
  with:
    path: ~/.nuget/packages
    key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }}
    restore-keys: |
      nuget-${{ runner.os }}-

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

Cache hit oranini izlemek ve cache key stratejinizi optimize etmek, build surelerini %50'ye kadar kisaltabilir. Ozellikle buyuk dependency'lere sahip projelerde cache kullanimi buyuk fark yaratir.

Pratik Oneriler ve Ozet

GitHub Actions ile CI/CD pipeline olusturulurken su noktalara dikkat edin:

  1. Cache kullanimi: NuGet, npm, Flutter paketlerini cache'leyerek build surelerini kisaltin
  2. Paralel job'lar: Bagimsiz islemleri paralel calistirarak toplam sureyi azaltin
  3. Environment koruma: Production deployment icin manual approval ekleyin
  4. Artifact yonetimi: Build ciktilarini artifact olarak saklayin, rollback icin hazir bulundurun
  5. Bildirimler: Slack veya Teams entegrasyonu ile pipeline durumunu takip edin

Iyi yapilandirilmis bir CI/CD pipeline, yazilim gelistirme surecinin omurgasidir. Otomatik test ve deployment sayesinde hem hata oranini dusurur hem de teslim hizini artirirsiniz.

İlgili Makaleler

Flutter Projeniz mi Var?

iOS, Android ve web için yüksek performanslı Flutter uygulamaları geliştiriyorum.

İletişime Geç