Files
trendyol-analiz/.github/workflows/deploy.yml
furkanyigit34 d9a6dda190 fix(ci): verify job spesifik deployment_uuid'yi izlesin
Ne yaptık:
- deploy job: Coolify response'undan deployment_uuid parse edip
  GITHUB_OUTPUT'a yazıyor.
- verify job: artık uygulama UUID'si yerine spesifik deployment UUID'sini
  polluyor (queued → in_progress → finished/failed geçişleri).
- Polling süresi 5 dk → 10 dk (max 60 × 10s).

Neden yaptık:
- Eski verify uygulama UUID'sini polling ediyordu. Yeni deploy başlamadan
  önceki eski "running:healthy" status'u yakalayıp 4 saniyede early-exit
  yapıyordu. Workflow yeşil görünür ama gerçek deploy'u doğrulamamış olur.
- Yeni davranış: workflow gerçekten Coolify deploy'unun bitmesini bekliyor.
  Fail olursa workflow da fail eder, notify-failure job tetiklenir.
2026-04-25 16:02:45 +03:00

319 lines
13 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
# Deployment UUID'yi output'a yaz → verify job bu spesifik deploy'u izleyecek
# ───────────────────────────────────────────────────────────────────────────
deploy:
name: 🚀 Deploy to Coolify
needs: [build-push-backend, build-push-frontend]
runs-on: ubuntu-latest
outputs:
deployment_uuid: ${{ steps.trigger.outputs.deployment_uuid }}
steps:
- name: Trigger Coolify deploy
id: trigger
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
# Deployment UUID'yi parse et
DEPLOY_UUID=$(echo "$body" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['deployments'][0]['deployment_uuid'])")
echo "deployment_uuid=$DEPLOY_UUID" >> "$GITHUB_OUTPUT"
echo "✅ Coolify deploy queued — deployment_uuid: $DEPLOY_UUID"
# ───────────────────────────────────────────────────────────────────────────
# ADIM 4 — Verify deployment
# Spesifik deployment_uuid'yi poll et: queued → in_progress → finished/failed
# ───────────────────────────────────────────────────────────────────────────
verify:
name: ✅ Verify Deployment
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Coolify deployment status polling
run: |
DEPLOY_UUID="${{ needs.deploy.outputs.deployment_uuid }}"
DEPLOY_URL="${{ secrets.COOLIFY_BASE_URL }}/api/v1/deployments/$DEPLOY_UUID"
MAX=60 # 60 × 10s = 10 dk
INTERVAL=10
echo "🔍 Polling deployment $DEPLOY_UUID"
for i in $(seq 1 $MAX); do
STATUS=$(curl -s --max-time 10 \
-H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}" \
"$DEPLOY_URL" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','?'))" 2>/dev/null || echo "unknown")
echo "[$i/$MAX] $STATUS"
case "$STATUS" in
finished|success)
echo "✅ Coolify deployment finished"
exit 0
;;
failed|error|cancelled)
echo "❌ Coolify deployment status: $STATUS"
echo "Panel: ${{ secrets.COOLIFY_BASE_URL }}"
exit 1
;;
esac
sleep $INTERVAL
done
echo "⚠️ Timeout — deployment hala '$STATUS' (10 dk geçti) — 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']
});
}