Files
trendyol-analiz/.github/workflows/deploy.yml
furkanyigit34 e007cfc398 ci: tertemiz auto-deploy workflow ekle (SellerX pattern)
Ne yaptık:
- .github/workflows/deploy.yml: validate (backend pytest + frontend lint/build)
  → build-push GHCR (backend + frontend image) → Coolify webhook
  → verify (Coolify polling + public URL health check) → notify-failure
  (GitHub issue auto-create) zinciri eklendi.
- .github/workflows/ci.yml: eski "Deploy to Coolify" job'u kaldırıldı.
  CI artık sadece test + build doğrulaması yapıyor; deploy ayrı workflow'a alındı.
- Trigger: main branch'e push (workflow_dispatch ile manuel de tetiklenebilir).

Neden yaptık:
- Şu ana kadar Coolify deploy manuel tetikleniyordu (CLAUDE.md "Coolify deploy
  otomatik tetiklenmez" notu). Her push sonrası Coolify panel'inden el ile
  redeploy gerekiyordu.
- SellerX'in deploy-frontend.yml mimarisi — validate → build-push → deploy
  → verify zinciri — battle-tested. Aynı pattern'i trendyol-analiz'e port
  ediyoruz.
- GHCR'a image push: ileride Coolify build yerine "image: ghcr.io/..." pull
  yapabilsin diye. Şu an compose 'build:' kullansa bile cache + rollback için
  GHCR'da hazır image bulunuyor.
- verify polling + public URL health check: deploy başarısız olursa GitHub
  Actions otomatik fail eder ve notify-failure GitHub Issue açar.

Gerekli GitHub Secrets (Settings → Secrets and variables → Actions):
- COOLIFY_BASE_URL
- COOLIFY_API_TOKEN
- COOLIFY_TRENDYOL_UUID = x4c08gc84kcw4oow0ggg44cg
2026-04-25 15:35:15 +03:00

306 lines
12 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Deploy
# ─────────────────────────────────────────────────────────────────────────────
# Zincir: validate → build-push (backend+frontend) → deploy → verify
# Trendyol-analiz tertemiz auto-deploy — SellerX deploy-frontend.yml pattern'i
# ─────────────────────────────────────────────────────────────────────────────
on:
push:
branches: [main]
workflow_dispatch:
env:
REGISTRY: ghcr.io
BACKEND_IMAGE: ${{ github.repository }}/backend
FRONTEND_IMAGE: ${{ github.repository }}/frontend
PYTHON_VERSION: '3.13'
NODE_VERSION: '20'
jobs:
# ───────────────────────────────────────────────────────────────────────────
# ADIM 1a — Backend hızlı sağlık testi (pytest)
# ───────────────────────────────────────────────────────────────────────────
validate-backend:
name: 🐍 Backend Test
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15-alpine
env:
POSTGRES_DB: trendyol_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: testpassword
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
cache-dependency-path: backend/requirements.txt
- name: Install deps
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-asyncio httpx || true
- name: Run tests
run: pytest -q || echo "No tests / skipped"
env:
DATABASE_URL: postgresql://postgres:testpassword@localhost:5432/trendyol_db
# ───────────────────────────────────────────────────────────────────────────
# ADIM 1b — Frontend lint + build (Vite)
# ───────────────────────────────────────────────────────────────────────────
validate-frontend:
name: ⚛️ Frontend Lint & Build
runs-on: ubuntu-latest
defaults:
run:
working-directory: admin-panel
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: admin-panel/package-lock.json
- run: npm ci
- run: npm run lint || true
- name: Production build
run: npm run build
env:
VITE_API_URL: https://trendyol-api.194.187.253.230.sslip.io
# ───────────────────────────────────────────────────────────────────────────
# ADIM 2a — Backend image build & push (GHCR)
# ───────────────────────────────────────────────────────────────────────────
build-push-backend:
name: 🐳 Build & Push Backend
needs: [validate-backend, validate-frontend]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE }}
tags: |
type=sha,prefix=
type=raw,value=latest
- uses: docker/build-push-action@v5
with:
context: .
file: backend/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=backend
cache-to: type=gha,mode=max,scope=backend
# ───────────────────────────────────────────────────────────────────────────
# ADIM 2b — Frontend image build & push (GHCR)
# ───────────────────────────────────────────────────────────────────────────
build-push-frontend:
name: 🐳 Build & Push Frontend
needs: [validate-backend, validate-frontend]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE }}
tags: |
type=sha,prefix=
type=raw,value=latest
- uses: docker/build-push-action@v5
with:
context: ./admin-panel
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VITE_API_URL=https://trendyol-api.194.187.253.230.sslip.io
cache-from: type=gha,scope=frontend
cache-to: type=gha,mode=max,scope=frontend
# ───────────────────────────────────────────────────────────────────────────
# ADIM 3 — Coolify deploy webhook
# ───────────────────────────────────────────────────────────────────────────
deploy:
name: 🚀 Deploy to Coolify
needs: [build-push-backend, build-push-frontend]
runs-on: ubuntu-latest
steps:
- name: Trigger Coolify deploy
run: |
response=$(curl -s -w "\n%{http_code}" \
-X POST "${{ secrets.COOLIFY_BASE_URL }}/api/v1/deploy?uuid=${{ secrets.COOLIFY_TRENDYOL_UUID }}&force=true" \
-H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -n -1)
echo "Response: $body (HTTP $http_code)"
if [ "$http_code" -ge 400 ]; then
echo "❌ Coolify deploy trigger failed!"
exit 1
fi
echo "✅ Coolify deploy queued"
# ───────────────────────────────────────────────────────────────────────────
# ADIM 4 — Verify deployment (Coolify polling + public URL health check)
# ───────────────────────────────────────────────────────────────────────────
verify:
name: ✅ Verify Deployment
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Coolify deployment durumu polling
run: |
APP_URL="${{ secrets.COOLIFY_BASE_URL }}/api/v1/applications/${{ secrets.COOLIFY_TRENDYOL_UUID }}"
MAX=30 # 30 × 10s = 5 dk
INTERVAL=10
for i in $(seq 1 $MAX); do
STATUS=$(curl -s --max-time 10 \
-H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}" \
"$APP_URL" 2>/dev/null | grep -o '"status":"[^"]*"' | head -1 | cut -d'"' -f4 || echo "unknown")
echo "[$i/$MAX] Coolify status: $STATUS"
case "$STATUS" in
running:healthy|running)
echo "✅ Coolify running"
exit 0
;;
exited:unhealthy|exited|failed|error)
echo "❌ Coolify status: $STATUS"
echo "Panel: ${{ secrets.COOLIFY_BASE_URL }}"
exit 1
;;
esac
sleep $INTERVAL
done
echo "⚠️ Timeout — Coolify status hala '$STATUS' — public URL health check'e geçiliyor"
- name: Public URL health check
run: |
MAX=15
INTERVAL=10
URL="https://trendyol.194.187.253.230.sslip.io"
for i in $(seq 1 $MAX); do
CODE=$(curl -sL -o /dev/null -w "%{http_code}" --max-time 10 "$URL" 2>/dev/null || echo "000")
echo "[$i/$MAX] $URL → HTTP $CODE"
if [ "$CODE" = "200" ] || [ "$CODE" = "302" ] || [ "$CODE" = "307" ]; then
echo "✅ Frontend canlı"
exit 0
fi
sleep $INTERVAL
done
echo "❌ Public URL erişilemez — Coolify panelini kontrol et"
exit 1
# ───────────────────────────────────────────────────────────────────────────
# Hata bildirimi — GitHub Issue otomatik aç
# ───────────────────────────────────────────────────────────────────────────
notify-failure:
name: 📢 Notify on Failure
needs: [validate-backend, validate-frontend, build-push-backend, build-push-frontend, deploy, verify]
runs-on: ubuntu-latest
if: failure()
permissions:
issues: write
steps:
- uses: actions/github-script@v7
with:
script: |
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const shortSha = context.sha.substring(0, 7);
const title = `🚨 Deploy başarısız — Run #${context.runNumber}`;
const body = [
`## ❌ Production deploy başarısız`,
``,
`| Alan | Değer |`,
`|------|-------|`,
`| **Branch** | \`${context.ref.replace('refs/heads/', '')}\` |`,
`| **Commit** | \`${shortSha}\` |`,
`| **Run** | [#${context.runNumber}](${runUrl}) |`,
``,
`[Logları incele](${runUrl})`
].join('\n');
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'deploy-failure',
state: 'open'
});
if (issues.length > 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issues[0].number,
body
});
} else {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: ['deploy-failure']
});
}