name: Docker Image CI on: push: tags: - '*' jobs: docker-releases: runs-on: ubuntu-latest steps: - name: Get release version run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - name: Determine tag type (prod vs main) id: tag_type run: | if [[ "${{ env.RELEASE_VERSION }}" == *"-prod"* ]]; then echo "is_prod_tag=true" >> $GITHUB_OUTPUT echo "📦 Prod tag detected - will push :latest-prod" else echo "is_prod_tag=false" >> $GITHUB_OUTPUT echo "📦 Main tag detected - will push :latest" fi - name: Checkout uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # Build and push for PROD tags (X.X.X-prod) - name: Build and push Docker images (prod) if: steps.tag_type.outputs.is_prod_tag == 'true' uses: docker/build-push-action@v6.9.0 with: context: ./ push: true tags: | ghcr.io/zeecka/aperisolve:${{ env.RELEASE_VERSION }} ghcr.io/zeecka/aperisolve:prod # Build and push for MAIN tags (X.X.X) - name: Build and push Docker images (main) if: steps.tag_type.outputs.is_prod_tag == 'false' uses: docker/build-push-action@v6.9.0 with: context: ./ push: true tags: | ghcr.io/zeecka/aperisolve:${{ env.RELEASE_VERSION }} ghcr.io/zeecka/aperisolve:latest deploy: runs-on: ubuntu-latest needs: docker-releases environment: prod steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Check if tag is from prod branch id: check run: | TAG_REF="${GITHUB_REF#refs/tags/}" echo "Tag: $TAG_REF" echo "Commit SHA: $GITHUB_SHA" # Get branches containing this commit BRANCHES=$(git branch -r --contains HEAD) echo "Branches containing this commit: $BRANCHES" # Check if commit is on prod branch if echo "$BRANCHES" | grep -q "origin/prod"; then # Additional check: ensure this commit is at the HEAD of prod # This prevents deployment if the same commit exists on multiple branches PROD_HEAD=$(git rev-parse origin/prod) TAG_COMMIT=$(git rev-parse HEAD) echo "Prod HEAD: $PROD_HEAD" echo "Tag commit: $TAG_COMMIT" if [ "$PROD_HEAD" = "$TAG_COMMIT" ]; then echo "is_prod=true" >> $GITHUB_OUTPUT echo "✅ Tag is at prod branch HEAD - will deploy" else echo "is_prod=false" >> $GITHUB_OUTPUT echo "⚠️ Commit is on prod but not at HEAD - skipping deployment" fi else echo "is_prod=false" >> $GITHUB_OUTPUT echo "❌ Tag is not from prod branch - skipping deployment" fi # wait for 120 seconds - name: Wait for image propagation if: steps.check.outputs.is_prod == 'true' run: | echo "Waiting 120 seconds for image to propagate in registry..." sleep 120 - name: Deploy to production server if: steps.check.outputs.is_prod == 'true' uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.PROD_SSH_HOST }} username: ${{ secrets.PROD_SSH_USER }} key: ${{ secrets.PROD_SSH_KEY }} script: | set -e cd /root/AperiSolve # update code git pull # create .env cat < .env MAX_CONTENT_LENGTH=${{ vars.MAX_CONTENT_LENGTH }} MAX_PENDING_TIME=${{ vars.MAX_PENDING_TIME }} MAX_STORE_TIME=${{ vars.MAX_STORE_TIME }} CLEAR_AT_RESTART=${{ vars.CLEAR_AT_RESTART }} SKIP_IHDR_FILL=${{ vars.SKIP_IHDR_FILL }} REMOVAL_MIN_AGE_SECONDS=${{ vars.REMOVAL_MIN_AGE_SECONDS }} FLASK_DEBUG=${{ vars.FLASK_DEBUG }} RQ_DASHBOARD_REDIS_URL=${{ vars.RQ_DASHBOARD_REDIS_URL }} POSTGRES_DB=${{ secrets.POSTGRES_DB }} POSTGRES_USER=${{ secrets.POSTGRES_USER }} POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }} DB_URI=${{ secrets.DATABASE_URL }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} SENTRY_TRACES_SAMPLE_RATE=${{ vars.SENTRY_TRACES_SAMPLE_RATE }} SENTRY_PROFILES_SAMPLE_RATE=${{ vars.SENTRY_PROFILES_SAMPLE_RATE }} SENTRY_RELEASE=${{ vars.SENTRY_RELEASE }} SENTRY_ENVIRONMENT=${{ vars.SENTRY_ENVIRONMENT }} EOF # Pull images and deploy docker compose pull docker compose down -v docker compose up -d docker image prune -f