Eren-Sama
Initial commit β€” full-stack AI portfolio architect
53e1531
name: Shortlist CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
PYTHON_VERSION: "3.12"
NODE_VERSION: "20"
REGISTRY: ghcr.io
IMAGE_PREFIX: ${{ github.repository_owner }}/shortlist
jobs:
# ── Backend Lint + Test ────────────────────────────────────
backend:
name: Backend CI
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./backend
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: pip
cache-dependency-path: backend/requirements.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with flake8
run: |
flake8 app/ --max-line-length=120 --statistics --count
- name: Type check with pylint (errors only)
run: |
pylint app/ --errors-only --disable=E0401
- name: Run tests
env:
SECRET_KEY: ci-test-secret-key-not-for-production
SUPABASE_URL: https://test.supabase.co
SUPABASE_ANON_KEY: eyJhbGciOiJIUzI1NiJ9.test-anon
SUPABASE_SERVICE_KEY: eyJhbGciOiJIUzI1NiJ9.test-service
SUPABASE_JWT_SECRET: ci-jwt-secret
GROQ_API_KEY: gsk_test_ci_key
ENVIRONMENT: testing
ALLOWED_ORIGINS: http://localhost:3000
run: |
pytest -v --cov=app --cov-report=xml --tb=short
- name: Upload coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: backend-coverage
path: backend/coverage.xml
# ── Frontend Lint + Build ──────────────────────────────────
frontend:
name: Frontend CI
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npx tsc --noEmit
- name: Build
env:
NEXT_PUBLIC_API_URL: http://localhost:8000
NEXT_PUBLIC_SUPABASE_URL: https://test.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY: test-anon-key
run: npm run build
# ── Docker Build + Push ────────────────────────────────────
docker:
name: Docker Build & Push
runs-on: ubuntu-latest
needs: [backend, frontend]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push backend image
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-backend:latest
${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-backend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push frontend image
uses: docker/build-push-action@v5
with:
context: ./frontend
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-frontend:latest
${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-frontend:${{ github.sha }}
build-args: |
NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_SUPABASE_URL=${{ vars.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY=${{ vars.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ── Deploy (main branch only) ──────────────────────────────
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [docker]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
environment: production
steps:
- uses: actions/checkout@v4
- name: Deploy notification
run: |
echo "πŸš€ Deploying Shortlist"
echo " Commit: ${{ github.sha }}"
echo " Backend: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-backend:${{ github.sha }}"
echo " Frontend: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-frontend:${{ github.sha }}"
# ── Option A: SSH deploy to VPS ──
# Uncomment and configure for your server:
#
# - name: Deploy via SSH
# uses: appleboy/ssh-action@v1
# with:
# host: ${{ secrets.DEPLOY_HOST }}
# username: ${{ secrets.DEPLOY_USER }}
# key: ${{ secrets.DEPLOY_SSH_KEY }}
# script: |
# cd /opt/shortlist
# docker compose -f docker-compose.prod.yml pull
# docker compose -f docker-compose.prod.yml up -d --remove-orphans
# docker image prune -f
# ── Option B: Railway / Render / Fly.io ──
# Configure platform-specific deployment here
- name: Post-deploy health check
run: |
echo "Deployment pipeline complete."
echo "Verify health: curl https://api.yourdomain.com/health/deep"