GitHub Actions ile Slack Bildirim Entegrasyonu Nasıl Yapılır

Bir CI/CD pipeline’ı kurdunuzda, deploy işlemlerinin sonucunu her seferinde GitHub arayüzünü açıp kontrol etmek zamanla can sıkıcı bir hal alıyor. Ekip büyüdükçe bu durum daha da kritik bir hale geliyor: kim ne zaman ne deploy etti, hangi branch’ten, başarılı mı oldu? Bu soruların cevabını anlık olarak almanın en pratik yolu, GitHub Actions’ı Slack ile entegre etmek. Bu yazıda sıfırdan gerçek dünya senaryolarına kadar her şeyi ele alacağız.

Neden Slack Bildirimi?

Ekip içinde asenkron çalışma kültürü yaygınlaştıkça, bildirimlerin doğru kanala, doğru formatta gelmesi kritik önem kazanıyor. E-posta bildirimleri gömülüp gidiyor, GitHub’ın kendi bildirim sistemi ise çoğu zaman gürültüye karışıyor.

Slack entegrasyonu sayesinde:

  • Anlık görünürlük: Deploy tamamlandığında tüm ekip aynı anda haberdar oluyor
  • Hata tespiti: Başarısız bir build’i saatler sonra değil, anında görüyorsunuz
  • Audit trail: Hangi kullanıcı hangi branch’i ne zaman deploy etti, Slack geçmişinde kalıyor
  • Aksiyon alma: Kritik bir hata olduğunda nöbetçi mühendis direkt mesajla ping’lenebiliyor

Slack App Kurulumu ve Webhook Alma

Her şeyden önce Slack tarafında bir yapılandırma yapmamız gerekiyor. İki farklı yöntem var: Incoming Webhooks ve Slack Bot API. Başlangıç için Incoming Webhooks çok daha pratik.

Incoming Webhook Oluşturma

  1. [api.slack.com/apps](https://api.slack.com/apps) adresine gidin
  2. “Create New App” butonuna tıklayın
  3. “From scratch” seçeneğini seçin
  4. App adını girin (örneğin “GitHub Actions Bot”) ve workspace’inizi seçin
  5. Sol menüden “Incoming Webhooks” bölümüne gidin
  6. “Activate Incoming Webhooks” toggle’ını aktif edin
  7. “Add New Webhook to Workspace” butonuna tıklayın
  8. Bildirimlerin gideceği kanalı seçin (örneğin #deployments)
  9. Oluşturulan webhook URL’ini kopyalayın

Webhook URL’i şu formatta görünür:

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Bu URL’i asla doğrudan workflow dosyasına yazmayın. GitHub Secrets kullanarak saklayacağız.

GitHub Secret Ekleme

Repository’nize gidin, Settings > Secrets and variables > Actions yolunu izleyin ve “New repository secret” butonuna tıklayın.

  • Secret Name: SLACK_WEBHOOK_URL
  • Secret Value: Kopyaladığınız webhook URL’i

Eğer organization seviyesinde kullanmak istiyorsanız, aynı işlemi Organization Settings üzerinden yapabilirsiniz. Bu sayede tek bir secret’ı birden fazla repository’de kullanabilirsiniz.

Temel Slack Bildirimi Workflow’u

En basit haliyle bir Slack bildirimi göndermek için curl kullanabiliriz. Bu yaklaşım hiçbir üçüncü taraf action’a bağımlı olmadığı için en güvenilir yöntemlerden biri.

name: Deploy with Slack Notification

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kodu al
        uses: actions/checkout@v4

      - name: Uygulama deploy et
        run: |
          echo "Deploy işlemi burada gerçekleşiyor"
          # Gerçek deploy komutlarınız

      - name: Slack bildirimi gönder
        if: always()
        run: |
          STATUS="${{ job.status }}"
          if [ "$STATUS" = "success" ]; then
            COLOR="good"
            EMOJI=":white_check_mark:"
            MESSAGE="Deploy başarıyla tamamlandı!"
          else
            COLOR="danger"
            EMOJI=":x:"
            MESSAGE="Deploy başarısız oldu!"
          fi

          curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" 
            -H 'Content-type: application/json' 
            --data "{
              "attachments": [{
                "color": "$COLOR",
                "title": "$EMOJI $MESSAGE",
                "fields": [
                  {"title": "Repository", "value": "${{ github.repository }}", "short": true},
                  {"title": "Branch", "value": "${{ github.ref_name }}", "short": true},
                  {"title": "Commit", "value": "${{ github.sha }}", "short": false},
                  {"title": "Tetikleyen", "value": "${{ github.actor }}", "short": true}
                ]
              }]
            }"

if: always() koşulunu kullandık. Bu önemli bir detay, çünkü önceki adım başarısız olsa bile bildirim adımının çalışmasını sağlıyor. Aksi takdirde deploy başarısız olduğunda bildirim hiç gitmez, tam da haberi en çok istediğiniz durumda.

Hazır Action Kullanımı: slackapi/slack-github-action

Daha gelişmiş ve bakımı kolay bir yapı için Slack’in resmi GitHub action’ını kullanabilirsiniz.

name: Production Deploy Pipeline

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Node.js kurulumu
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Bağımlılıkları yükle
        run: npm ci

      - name: Testleri çalıştır
        run: npm test

      - name: Production build al
        run: npm run build

      - name: Sunucuya deploy et
        run: |
          rsync -avz ./dist/ user@production-server:/var/www/html/

      - name: Başarı bildirimi gönder
        if: success()
        uses: slackapi/[email protected]
        with:
          payload: |
            {
              "text": ":rocket: *Production deploy tamamlandı!*",
              "attachments": [
                {
                  "color": "#36a64f",
                  "fields": [
                    {
                      "title": "Proje",
                      "value": "${{ github.repository }}",
                      "short": true
                    },
                    {
                      "title": "Deploy Eden",
                      "value": "${{ github.actor }}",
                      "short": true
                    },
                    {
                      "title": "Commit Mesajı",
                      "value": "${{ github.event.head_commit.message }}",
                      "short": false
                    },
                    {
                      "title": "Actions Link",
                      "value": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
                      "short": false
                    }
                  ]
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

      - name: Hata bildirimi gönder
        if: failure()
        uses: slackapi/[email protected]
        with:
          payload: |
            {
              "text": ":fire: *Deploy BAŞARISIZ oldu! Acil kontrol gerekli!*",
              "attachments": [
                {
                  "color": "#FF0000",
                  "fields": [
                    {
                      "title": "Proje",
                      "value": "${{ github.repository }}",
                      "short": true
                    },
                    {
                      "title": "Tetikleyen",
                      "value": "${{ github.actor }}",
                      "short": true
                    },
                    {
                      "title": "Hata Detayı",
                      "value": "Actions sayfasını kontrol edin",
                      "short": false
                    },
                    {
                      "title": "Actions Link",
                      "value": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
                      "short": false
                    }
                  ]
                }
              ]
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK

Çok Aşamalı Pipeline’da Bildirimler

Gerçek dünya senaryolarında genellikle birden fazla job’ı olan pipeline’larla çalışırsınız. Her aşamanın durumunu ayrı ayrı bildirmek, hangi adımda problem olduğunu anında anlamanızı sağlar.

name: Multi-Stage Pipeline

on:
  push:
    branches: [main, staging]

jobs:
  test:
    runs-on: ubuntu-latest
    outputs:
      test_status: ${{ steps.set_status.outputs.status }}
    steps:
      - uses: actions/checkout@v4

      - name: Python kurulumu
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Bağımlılıkları yükle
        run: pip install -r requirements.txt

      - name: Unit testleri çalıştır
        id: run_tests
        run: pytest tests/ --tb=short

      - name: Test durumunu ayarla
        id: set_status
        if: always()
        run: |
          if [ "${{ steps.run_tests.outcome }}" = "success" ]; then
            echo "status=passed" >> $GITHUB_OUTPUT
          else
            echo "status=failed" >> $GITHUB_OUTPUT
          fi

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4

      - name: Deploy işlemi
        run: |
          echo "Deployment komutu burada"

  notify:
    needs: [test, deploy]
    runs-on: ubuntu-latest
    if: always()
    steps:
      - name: Pipeline sonuç bildirimi
        run: |
          TEST_RESULT="${{ needs.test.result }}"
          DEPLOY_RESULT="${{ needs.deploy.result }}"

          # Sonuç emoji'lerini belirle
          get_emoji() {
            case "$1" in
              "success") echo ":white_check_mark:" ;;
              "failure") echo ":x:" ;;
              "skipped") echo ":fast_forward:" ;;
              *) echo ":question:" ;;
            esac
          }

          TEST_EMOJI=$(get_emoji "$TEST_RESULT")
          DEPLOY_EMOJI=$(get_emoji "$DEPLOY_RESULT")

          # Genel durum rengini belirle
          if [ "$TEST_RESULT" = "success" ] && [ "$DEPLOY_RESULT" = "success" ]; then
            COLOR="good"
            HEADER=":rocket: Pipeline başarıyla tamamlandı"
          elif [ "$DEPLOY_RESULT" = "skipped" ] && [ "$TEST_RESULT" = "success" ]; then
            COLOR="#FFA500"
            HEADER=":test_tube: Testler geçti, deploy yapılmadı"
          else
            COLOR="danger"
            HEADER=":fire: Pipeline başarısız!"
          fi

          curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" 
            -H 'Content-type: application/json' 
            --data "{
              "attachments": [{
                "color": "$COLOR",
                "title": "$HEADER",
                "fields": [
                  {"title": "Test", "value": "$TEST_EMOJI $TEST_RESULT", "short": true},
                  {"title": "Deploy", "value": "$DEPLOY_EMOJI $DEPLOY_RESULT", "short": true},
                  {"title": "Branch", "value": "${{ github.ref_name }}", "short": true},
                  {"title": "Actor", "value": "${{ github.actor }}", "short": true},
                  {"title": "Run Link", "value": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "short": false}
                ]
              }]
            }"

Ortam Bazlı Bildirimler

Staging ve production için farklı Slack kanallarına bildirim göndermek, gürültüyü azaltmanın en etkili yollarından biri. Production kanalını sadece kritik değişiklikler için ayırt etmek, ekibin dikkatini doğru noktaya çekiyor.

name: Environment-Based Notifications

on:
  push:
    branches:
      - main
      - staging

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Ortamı belirle
        id: env_check
        run: |
          if [ "${{ github.ref_name }}" = "main" ]; then
            echo "environment=production" >> $GITHUB_OUTPUT
            echo "webhook_secret=SLACK_PROD_WEBHOOK" >> $GITHUB_OUTPUT
          else
            echo "environment=staging" >> $GITHUB_OUTPUT
            echo "webhook_secret=SLACK_STAGING_WEBHOOK" >> $GITHUB_OUTPUT
          fi

      - name: Deploy işlemi
        run: |
          ENV="${{ steps.env_check.outputs.environment }}"
          echo "$ENV ortamına deploy ediliyor..."

      - name: Ortama göre bildirim gönder
        if: always()
        run: |
          ENVIRONMENT="${{ steps.env_check.outputs.environment }}"
          JOB_STATUS="${{ job.status }}"

          # Ortama göre webhook URL'ini seç
          if [ "$ENVIRONMENT" = "production" ]; then
            WEBHOOK_URL="${{ secrets.SLACK_PROD_WEBHOOK }}"
            ENV_COLOR="#FF4500"
            ENV_LABEL=":warning: *PRODUCTION*"
          else
            WEBHOOK_URL="${{ secrets.SLACK_STAGING_WEBHOOK }}"
            ENV_COLOR="#4169E1"
            ENV_LABEL=":test_tube: *STAGING*"
          fi

          if [ "$JOB_STATUS" = "success" ]; then
            STATUS_TEXT="Deploy başarılı :white_check_mark:"
          else
            STATUS_TEXT="Deploy başarısız :x: - Acil kontrol gerekli!"
          fi

          curl -X POST "$WEBHOOK_URL" 
            -H 'Content-type: application/json' 
            --data "{
              "text": "$ENV_LABEL - $STATUS_TEXT",
              "attachments": [{
                "color": "$ENV_COLOR",
                "fields": [
                  {"title": "Ortam", "value": "$ENVIRONMENT", "short": true},
                  {"title": "Versiyon", "value": "${{ github.sha }}", "short": true},
                  {"title": "Deploy Eden", "value": "${{ github.actor }}", "short": true},
                  {"title": "Zaman", "value": "$(date '+%Y-%m-%d %H:%M:%S UTC')", "short": true}
                ]
              }]
            }"

Bu senaryo için GitHub Secrets’a hem SLACK_PROD_WEBHOOK hem de SLACK_STAGING_WEBHOOK eklenmiş olması gerekiyor.

Reusable Workflow ile Merkezi Bildirim Yönetimi

Birden fazla repository’de aynı bildirim mantığını kullanıyorsanız, reusable workflow yaklaşımı kod tekrarını ortadan kaldırır.

# .github/workflows/slack-notify.yml (merkezi repository'de)

name: Slack Bildirimi (Reusable)

on:
  workflow_call:
    inputs:
      status:
        required: true
        type: string
      environment:
        required: false
        type: string
        default: 'unknown'
      custom_message:
        required: false
        type: string
        default: ''
    secrets:
      SLACK_WEBHOOK_URL:
        required: true

jobs:
  send-notification:
    runs-on: ubuntu-latest
    steps:
      - name: Bildirim payload'ını hazırla ve gönder
        run: |
          STATUS="${{ inputs.status }}"
          ENVIRONMENT="${{ inputs.environment }}"
          CUSTOM_MSG="${{ inputs.custom_message }}"

          case "$STATUS" in
            "success")
              COLOR="good"
              STATUS_ICON=":white_check_mark:"
              STATUS_TEXT="Başarılı"
              ;;
            "failure")
              COLOR="danger"
              STATUS_ICON=":x:"
              STATUS_TEXT="Başarısız"
              ;;
            "cancelled")
              COLOR="#808080"
              STATUS_ICON=":no_entry_sign:"
              STATUS_TEXT="İptal Edildi"
              ;;
            *)
              COLOR="#FFA500"
              STATUS_ICON=":question:"
              STATUS_TEXT="Bilinmeyen"
              ;;
          esac

          FOOTER_MSG="Triggered by ${{ github.actor }} on $(date '+%d.%m.%Y %H:%M') UTC"

          curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" 
            -H 'Content-type: application/json' 
            --data "{
              "attachments": [{
                "color": "$COLOR",
                "title": "$STATUS_ICON ${{ github.repository }} - $ENVIRONMENT Deploy: $STATUS_TEXT",
                "text": "$CUSTOM_MSG",
                "footer": "$FOOTER_MSG",
                "fields": [
                  {"title": "Branch", "value": "${{ github.ref_name }}", "short": true},
                  {"title": "Run ID", "value": "${{ github.run_id }}", "short": true},
                  {"title": "Workflow", "value": "${{ github.workflow }}", "short": false},
                  {"title": "Actions", "value": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}", "short": false}
                ]
              }]
            }"

Bu reusable workflow’u başka bir repository’den çağırmak için:

# Herhangi bir repository'deki workflow dosyası

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy komutu
        run: echo "Deploy burada"

  bildirim-gonder:
    needs: deploy
    if: always()
    uses: sirket-org/central-workflows/.github/workflows/slack-notify.yml@main
    with:
      status: ${{ needs.deploy.result }}
      environment: production
      custom_message: "Frontend v2.5.1 production'a deploy edildi."
    secrets:
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

Gelişmiş Senaryo: PR Merge Bildirimi

Pull Request merge edildiğinde takımı bilgilendirmek, özellikle büyük değişiklikler için çok faydalı.

name: PR Merge Slack Bildirimi

on:
  pull_request:
    types: [closed]
    branches:
      - main

jobs:
  pr-merge-notify:
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest
    steps:
      - name: PR merge bildirimi gönder
        run: |
          PR_TITLE="${{ github.event.pull_request.title }}"
          PR_NUMBER="${{ github.event.pull_request.number }}"
          PR_AUTHOR="${{ github.event.pull_request.user.login }}"
          PR_URL="${{ github.event.pull_request.html_url }}"
          PR_BODY="${{ github.event.pull_request.body }}"
          MERGE_COMMIT="${{ github.event.pull_request.merge_commit_sha }}"
          LABELS=$(echo '${{ toJson(github.event.pull_request.labels.*.name) }}' | tr -d '[]"' | tr ',' ', ')

          # PR açıklama uzunsa kırp
          if [ ${#PR_BODY} -gt 200 ]; then
            PR_BODY="${PR_BODY:0:200}..."
          fi

          curl -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" 
            -H 'Content-type: application/json' 
            --data "{
              "text": ":merged: *PR #$PR_NUMBER merge edildi!*",
              "attachments": [{
                "color": "#6f42c1",
                "title": "$PR_TITLE",
                "title_link": "$PR_URL",
                "text": "$PR_BODY",
                "fields": [
                  {"title": "Yazar", "value": "$PR_AUTHOR", "short": true},
                  {"title": "Hedef Branch", "value": "main", "short": true},
                  {"title": "Etiketler", "value": "$LABELS", "short": true},
                  {"title": "Merge Commit", "value": "${MERGE_COMMIT:0:8}", "short": true}
                ]
              }]
            }"

Dikkat Edilmesi Gereken Noktalar

Bildirimleri kurarken karşılaşabileceğiniz yaygın sorunlar ve çözümleri:

Webhook URL güvenliği

  • Webhook URL’ini kesinlikle kod içine yazmayın
  • SLACK_WEBHOOK_URL secret’ını repository seviyesinde değil, mümkünse environment seviyesinde tanımlayın
  • Sızdığını düşündüğünüz bir webhook’u Slack app ayarlarından hemen yenileyin

if: always() ve if: failure() farkı

  • if: always(): Job cancelled olsa bile çalışır
  • if: failure(): Sadece önceki adım başarısız olduğunda çalışır
  • if: success(): Sadece önceki adım başarılı olduğunda çalışır

Bildirimlerde always() kullanmak genellikle daha güvenlidir, çünkü cancel durumlarında da haberdar olursunuz.

JSON escape sorunları

Commit mesajlarında veya PR başlıklarında özel karakter olduğunda curl ile gönderilen JSON bozulabilir. Bunu önlemek için:

  • jq kullanarak JSON oluşturun
  • Mesajı bir dosyaya yazıp @filename ile referans verin
  • GitHub’ın toJson() fonksiyonundan yararlanın

Rate limiting

Slack Incoming Webhooks için saniyede 1 mesaj sınırı var. Paralel çok sayıda job bildirimi gönderiyorsanız bu sınıra takılabilirsiniz. notify job’ını tüm job’ların bitmesini bekleyecek şekilde tasarlamak bu sorunu çözer.

Gürültü yönetimi

Her push’ta bildirim göndermek bir süre sonra rahatsız edici olabiliyor. Aşağıdaki stratejiler gürültüyü azaltır:

  • Sadece main ve release branch’leri için bildirim gönderin
  • Sadece başarısız build’ler için alert açın, başarılılar için summary kanalı kullanın
  • workflow_dispatch ile tetiklenen manual deploy’lar için ayrı kanal kullanın
  • Gece saatlerindeki otomatik scheduled job’lar için sabah özeti formatını tercih edin

Sonuç

GitHub Actions ile Slack entegrasyonu, ilk bakışta küçük bir iyileştirme gibi görünse de ekip dinamiklerine katkısı oldukça büyük. Deploy süreçlerinde tam görünürlük sağlamak, hataları erken tespit etmek ve ekip içi iletişimi otomatikleştirmek; DevOps olgunluğunun önemli göstergelerinden biri.

Başlangıç için curl ile basit bir bildirim göndermekle başlayın. Sonrasında reusable workflow’lar ve ortam bazlı kanallarla yapıyı büyütün. Kritik olan, bildirimlerin anlamlı ve aksiyon alınabilir olması. Sadece “deploy başarılı” yazan bir bildirim değil, kim yaptı, ne değişti, nereye bakmalı sorularını cevaplayan zengin bir içerik hazırlamak, bu entegrasyondan gerçek değer almanızı sağlar.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir