Skip to content

Merge pull request #522 from Yasir-TechGuy/feat/be-release-pipeline #1

Merge pull request #522 from Yasir-TechGuy/feat/be-release-pipeline

Merge pull request #522 from Yasir-TechGuy/feat/be-release-pipeline #1

name: Backend Release
on:
push:
branches: [main]
paths:
- 'app/backend/**'
- '.github/workflows/backend-release.yml'
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
default: 'staging'
type: choice
options: [staging, production]
rollback_sha:
description: 'Git SHA to roll back to (leave empty for normal deploy)'
required: false
concurrency:
group: backend-release-${{ github.event.inputs.environment || 'staging' }}
cancel-in-progress: false
jobs:
# ─── 1. Build & publish Docker image ────────────────────────────────────────
build:
name: Build Image
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.image_tag }}
git_sha: ${{ github.sha }}
steps:
- uses: actions/checkout@v4
- name: Set image metadata
id: meta
run: |
SHORT_SHA="${GITHUB_SHA::8}"
echo "image_tag=ghcr.io/${{ github.repository_owner }}/quickex-backend:${SHORT_SHA}" >> "$GITHUB_OUTPUT"
echo "SHORT_SHA=${SHORT_SHA}" >> "$GITHUB_ENV"
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: app/backend
push: true
tags: |
${{ steps.meta.outputs.image_tag }}
ghcr.io/${{ github.repository_owner }}/quickex-backend:latest
labels: |
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
# ─── 2. Deploy to staging ───────────────────────────────────────────────────
deploy-staging:
name: Deploy → Staging
needs: build
runs-on: ubuntu-latest
environment: staging
env:
DEPLOY_ENV: staging
IMAGE_TAG: ${{ needs.build.outputs.image_tag }}
GIT_SHA: ${{ needs.build.outputs.git_sha }}
steps:
- uses: actions/checkout@v4
- name: Run migrations (staging)
uses: ./.github/actions/run-migrations
with:
supabase_url: ${{ secrets.STAGING_SUPABASE_URL }}
supabase_service_key: ${{ secrets.STAGING_SUPABASE_SERVICE_KEY }}
environment: staging
git_sha: ${{ env.GIT_SHA }}
- name: Deploy app (staging)
uses: ./.github/actions/deploy-app
with:
image_tag: ${{ env.IMAGE_TAG }}
environment: staging
git_sha: ${{ env.GIT_SHA }}
deploy_token: ${{ secrets.STAGING_DEPLOY_TOKEN }}
app_url: ${{ secrets.STAGING_APP_URL }}
# ─── 3. Deploy to production (manual gate) ──────────────────────────────────
deploy-production:
name: Deploy → Production
needs: [build, deploy-staging]
runs-on: ubuntu-latest
environment: production # requires manual approval in GitHub Environments
if: github.event_name == 'push' || github.event.inputs.environment == 'production'
env:
DEPLOY_ENV: production
IMAGE_TAG: ${{ needs.build.outputs.image_tag }}
GIT_SHA: ${{ needs.build.outputs.git_sha }}
steps:
- uses: actions/checkout@v4
- name: Run migrations (production)
uses: ./.github/actions/run-migrations
with:
supabase_url: ${{ secrets.PROD_SUPABASE_URL }}
supabase_service_key: ${{ secrets.PROD_SUPABASE_SERVICE_KEY }}
environment: production
git_sha: ${{ env.GIT_SHA }}
- name: Deploy app (production)
uses: ./.github/actions/deploy-app
with:
image_tag: ${{ env.IMAGE_TAG }}
environment: production
git_sha: ${{ env.GIT_SHA }}
deploy_token: ${{ secrets.PROD_DEPLOY_TOKEN }}
app_url: ${{ secrets.PROD_APP_URL }}
# ─── 4. Rollback (manual trigger only) ──────────────────────────────────────
rollback:
name: Rollback
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && github.event.inputs.rollback_sha != ''
environment: ${{ github.event.inputs.environment }}
env:
TARGET_ENV: ${{ github.event.inputs.environment }}
ROLLBACK_SHA: ${{ github.event.inputs.rollback_sha }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ env.ROLLBACK_SHA }}
- name: Resolve rollback image
id: rollback_image
run: |
SHORT_SHA="${ROLLBACK_SHA::8}"
echo "image_tag=ghcr.io/${{ github.repository_owner }}/quickex-backend:${SHORT_SHA}" >> "$GITHUB_OUTPUT"
- name: Deploy previous image
uses: ./.github/actions/deploy-app
with:
image_tag: ${{ steps.rollback_image.outputs.image_tag }}
environment: ${{ env.TARGET_ENV }}
git_sha: ${{ env.ROLLBACK_SHA }}
deploy_token: ${{ env.TARGET_ENV == 'production' && secrets.PROD_DEPLOY_TOKEN || secrets.STAGING_DEPLOY_TOKEN }}
app_url: ${{ env.TARGET_ENV == 'production' && secrets.PROD_APP_URL || secrets.STAGING_APP_URL }}
- name: Log rollback event
run: |
echo "::notice title=Rollback::Rolled ${{ env.TARGET_ENV }} back to ${{ env.ROLLBACK_SHA }} at $(date -u +%Y-%m-%dT%H:%M:%SZ)"