name: Auto V2 Deploy on Push on: push: branches: - V2 - deploy-on-v2-commit permissions: contents: read jobs: deploy-v2-on-push: environment: pr-preview runs-on: ubuntu-latest permissions: contents: read packages: write concurrency: group: deploy-v2-push-V2 cancel-in-progress: true steps: - name: Harden Runner uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Get commit hashes for frontend and backend id: commit-hashes run: | # Get last commit that touched the frontend folder, docker/frontend, or docker/compose FRONTEND_HASH=$(git log -1 --format="%H" -- frontend/ docker/frontend/ docker/compose/ 2>/dev/null || echo "") if [ -z "$FRONTEND_HASH" ]; then FRONTEND_HASH="no-frontend-changes" fi # Get last commit that touched backend code, docker/backend, or docker/compose BACKEND_HASH=$(git log -1 --format="%H" -- app/ docker/backend/ docker/compose/ 2>/dev/null || echo "") if [ -z "$BACKEND_HASH" ]; then BACKEND_HASH="no-backend-changes" fi echo "Frontend hash: $FRONTEND_HASH" echo "Backend hash: $BACKEND_HASH" echo "frontend_hash=$FRONTEND_HASH" >> $GITHUB_OUTPUT echo "backend_hash=$BACKEND_HASH" >> $GITHUB_OUTPUT # Short hashes for tags if [ "$FRONTEND_HASH" = "no-frontend-changes" ]; then echo "frontend_short=no-frontend" >> $GITHUB_OUTPUT else echo "frontend_short=${FRONTEND_HASH:0:8}" >> $GITHUB_OUTPUT fi if [ "$BACKEND_HASH" = "no-backend-changes" ]; then echo "backend_short=no-backend" >> $GITHUB_OUTPUT else echo "backend_short=${BACKEND_HASH:0:8}" >> $GITHUB_OUTPUT fi - name: Convert repository owner to lowercase id: repoowner run: echo "lowercase=$(echo ${{ github.repository_owner }} | awk '{print tolower($0)}')" >> $GITHUB_OUTPUT - name: Login to GitHub Container Registry uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ github.token }} - name: Check if frontend image exists id: check-frontend run: | if docker manifest inspect ${IMAGE_BASE}:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} >/dev/null 2>&1; then echo "exists=true" >> $GITHUB_OUTPUT echo "Frontend image already exists, skipping build" else echo "exists=false" >> $GITHUB_OUTPUT echo "Frontend image needs to be built" fi env: IMAGE_BASE: ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test - name: Check if backend image exists id: check-backend run: | if docker manifest inspect ${IMAGE_BASE}:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} >/dev/null 2>&1; then echo "exists=true" >> $GITHUB_OUTPUT echo "Backend image already exists, skipping build" else echo "exists=false" >> $GITHUB_OUTPUT echo "Backend image needs to be built" fi env: IMAGE_BASE: ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test - name: Build and push frontend image if: steps.check-frontend.outputs.exists == 'false' uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: ./docker/frontend/Dockerfile push: true cache-from: type=gha,scope=stirling-v2-frontend cache-to: type=gha,mode=max,scope=stirling-v2-frontend tags: | ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test:v2-frontend-latest build-args: VERSION_TAG=v2-alpha platforms: linux/amd64 - name: Build and push backend image if: steps.check-backend.outputs.exists == 'false' uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: ./docker/backend/Dockerfile push: true cache-from: type=gha,scope=stirling-v2-backend cache-to: type=gha,mode=max,scope=stirling-v2-backend tags: | ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test:v2-backend-latest build-args: VERSION_TAG=v2-alpha platforms: linux/amd64 - name: Set up SSH run: | mkdir -p ~/.ssh/ echo "${NEW_VPS_SSH_KEY}" > ../private.key chmod 600 ../private.key env: NEW_VPS_SSH_KEY: ${{ secrets.NEW_VPS_SSH_KEY }} - name: Deploy to VPS on port 3000 run: | export UNIQUE_NAME=docker-compose-v2-$GITHUB_RUN_ID.yml cat > $UNIQUE_NAME << EOF version: '3.3' services: backend: container_name: stirling-v2-backend image: ${IMAGE_BASE}:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} ports: - "13000:8080" volumes: - /stirling/V2/data:/usr/share/tessdata:rw - /stirling/V2/config:/configs:rw - /stirling/V2/logs:/logs:rw environment: DISABLE_ADDITIONAL_FEATURES: "true" SECURITY_ENABLELOGIN: "false" SYSTEM_DEFAULTLOCALE: en-US UI_APPNAME: "Stirling-PDF V2" UI_HOMEDESCRIPTION: "V2 Frontend/Backend Split" UI_APPNAMENAVBAR: "V2 Deployment" SYSTEM_MAXFILESIZE: "100" METRICS_ENABLED: "true" SYSTEM_GOOGLEVISIBILITY: "false" SWAGGER_SERVER_URL: "https://demo.stirlingpdf.cloud" baseUrl: "https://demo.stirlingpdf.cloud" restart: on-failure:5 frontend: container_name: stirling-v2-frontend image: ${IMAGE_BASE}:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} ports: - "3000:80" environment: VITE_API_BASE_URL: "http://${NEW_VPS_HOST}:13000" depends_on: - backend restart: on-failure:5 EOF # Copy to remote with unique name scp -i ../private.key -o StrictHostKeyChecking=no $UNIQUE_NAME ${NEW_VPS_USERNAME}@${NEW_VPS_HOST}:/tmp/$UNIQUE_NAME # SSH and rename/move atomically to avoid interference ssh -i ../private.key -o StrictHostKeyChecking=no ${NEW_VPS_USERNAME}@${NEW_VPS_HOST} << ENDSSH mkdir -p /stirling/V2/{data,config,logs} mv /tmp/$UNIQUE_NAME /stirling/V2/docker-compose.yml cd /stirling/V2 docker-compose down || true docker-compose pull docker-compose up -d docker system prune -af --volumes || true docker image prune -af --filter "until=336h" --filter "label!=keep=true" || true ENDSSH env: IMAGE_BASE: ghcr.io/${{ steps.repoowner.outputs.lowercase }}/stirling-pdf-test NEW_VPS_HOST: ${{ secrets.NEW_VPS_HOST }} NEW_VPS_USERNAME: ${{ secrets.NEW_VPS_USERNAME }} - name: Cleanup temporary files if: always() run: | rm -f ../private.key