Files
edh-stats/.github/workflows/publish.yml
2026-04-11 13:01:58 +02:00

237 lines
8.2 KiB
YAML

name: Build and Publish Docker Images
on:
push:
tags:
- "v*"
- "release-*"
branches:
- main
- production
workflow_dispatch:
inputs:
version:
description: "Version tag (e.g., 1.0.0)"
required: true
type: string
env:
REGISTRY: ghcr.io
PROJECT_NAME: edh-stats
jobs:
build:
name: Build and Push Docker Images
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-options: image=moby/buildkit:latest
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GHCR_TOKEN || secrets.GITHUB_TOKEN }}
- name: Extract version
id: version
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
VERSION=${{ github.event.inputs.version }}
elif [[ "${{ github.ref }}" =~ ^refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
elif [[ "${{ github.ref }}" =~ ^refs/tags/release-(.+)$ ]]; then
VERSION=${BASH_REMATCH[1]}
elif [[ "${{ github.ref }}" == "refs/heads/main" || "${{ github.ref }}" == "refs/heads/production" ]]; then
VERSION=${{ github.ref_name }}-${{ github.sha }}
else
VERSION=latest
fi
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
echo "BACKEND_IMAGE=${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.PROJECT_NAME }}-backend:${VERSION}" >> $GITHUB_OUTPUT
echo "FRONTEND_IMAGE=${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.PROJECT_NAME }}-frontend:${VERSION}" >> $GITHUB_OUTPUT
- name: Build and push backend image
uses: docker/build-push-action@v5
with:
context: ./backend
file: ./backend/Dockerfile
target: production
platforms: linux/amd64
push: true
tags: |
${{ steps.version.outputs.BACKEND_IMAGE }}
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.PROJECT_NAME }}-backend:latest
- name: Build and push frontend image
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile.svelte
platforms: linux/amd64
push: true
tags: |
${{ steps.version.outputs.FRONTEND_IMAGE }}
${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.PROJECT_NAME }}-frontend:latest
- name: Generate deployment config
id: config
run: |
cat > docker-compose.prod.deployed.yml << 'EOF'
version: '3.8'
services:
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=${DB_USER:-postgres}
- POSTGRES_PASSWORD=${DB_PASSWORD:-edh_password}
- POSTGRES_DB=${DB_NAME:-edh_stats}
ports:
- '${DB_PORT:-5432}:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test:
- CMD-SHELL
- 'PGPASSWORD=${DB_PASSWORD:-edh_password} pg_isready -U ${DB_USER:-postgres} -h localhost'
interval: 10s
timeout: 5s
retries: 5
networks:
- edh-stats-network
restart: unless-stopped
db-migrate:
image: ${{ steps.version.outputs.BACKEND_IMAGE }}
depends_on:
postgres:
condition: service_healthy
environment:
- NODE_ENV=production
- DB_HOST=${DB_HOST:-postgres}
- DB_PORT=${DB_PORT:-5432}
- DB_NAME=${DB_NAME:-edh_stats}
- DB_USER=${DB_USER:-postgres}
- DB_PASSWORD=${DB_PASSWORD:-edh_password}
- DB_SEED=${DB_SEED:-false}
command: node src/database/migrate.js migrate
networks:
- edh-stats-network
restart: 'no'
backend:
image: ${{ steps.version.outputs.BACKEND_IMAGE }}
depends_on:
db-migrate:
condition: service_completed_successfully
environment:
- NODE_ENV=production
- DB_HOST=${DB_HOST:-postgres}
- DB_PORT=${DB_PORT:-5432}
- DB_NAME=${DB_NAME:-edh_stats}
- DB_USER=${DB_USER:-postgres}
- DB_PASSWORD=${DB_PASSWORD:-edh_password}
- JWT_SECRET=${JWT_SECRET}
- CORS_ORIGIN=${CORS_ORIGIN:-https://yourdomain.com}
- LOG_LEVEL=${LOG_LEVEL:-warn}
- ALLOW_REGISTRATION=${ALLOW_REGISTRATION:-false}
restart: unless-stopped
healthcheck:
test:
- CMD
- wget
- --no-verbose
- --tries=1
- --spider
- http://localhost:3000/api/health
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- edh-stats-network
stop_grace_period: 30s
frontend:
image: ${{ steps.version.outputs.FRONTEND_IMAGE }}
ports:
- '80:80'
- '443:443'
depends_on:
- backend
restart: unless-stopped
networks:
- edh-stats-network
volumes:
postgres_data:
driver: local
networks:
edh-stats-network:
driver: bridge
EOF
- name: Upload deployment config
uses: actions/upload-artifact@v4
with:
name: deployment-config
path: docker-compose.prod.deployed.yml
- name: Create Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: docker-compose.prod.deployed.yml
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Clean up old backend images
uses: actions/delete-package-versions@v5
continue-on-error: true
with:
owner: ${{ github.repository_owner }}
package-name: ${{ env.PROJECT_NAME }}-backend
package-type: container
min-versions-to-keep: 10
delete-only-untagged-versions: true
- name: Clean up old backend images
uses: actions/delete-package-versions@v5
continue-on-error: true
with:
owner: ${{ github.repository_owner }}
package-name: ${{ env.PROJECT_NAME }}-frontend
package-type: container
min-versions-to-keep: 10
delete-only-untagged-versions: true
- name: Post deployment info
run: |
echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Backend Image:** ${{ steps.version.outputs.BACKEND_IMAGE }}" >> $GITHUB_STEP_SUMMARY
echo "**Frontend Image:** ${{ steps.version.outputs.FRONTEND_IMAGE }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Pull Commands:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ steps.version.outputs.BACKEND_IMAGE }}" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ steps.version.outputs.FRONTEND_IMAGE }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Cleanup:** Old images (keeping last 10 versions)" >> $GITHUB_STEP_SUMMARY