name: Auto V2 Deploy on Push on: push: branches: - V2 - deploy-on-v2-commit permissions: contents: read jobs: deploy-v2-on-push: runs-on: ubuntu-latest concurrency: group: deploy-v2-push-V2 cancel-in-progress: true steps: - name: Harden Runner uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 with: egress-policy: audit - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - 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: Check if frontend image exists id: check-frontend run: | if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test: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 - name: Check if backend image exists id: check-backend run: | if docker manifest inspect ${{ secrets.DOCKER_HUB_USERNAME }}/test: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 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_API }} - name: Build and push frontend image if: steps.check-frontend.outputs.exists == 'false' uses: docker/build-push-action@v6 with: context: . file: ./docker/frontend/Dockerfile push: true tags: | ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} ${{ secrets.DOCKER_HUB_USERNAME }}/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@v6 with: context: . file: ./docker/backend/Dockerfile push: true tags: | ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-latest build-args: VERSION_TAG=v2-alpha platforms: linux/amd64 - name: Set up SSH run: | mkdir -p ~/.ssh/ echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key chmod 600 ../private.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: ${{ secrets.DOCKER_HUB_USERNAME }}/test: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-GB 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: "http://${{ secrets.VPS_HOST }}:3000" restart: on-failure:5 frontend: container_name: stirling-v2-frontend image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} ports: - "3000:80" environment: VITE_API_BASE_URL: "http://${{ secrets.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 ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/$UNIQUE_NAME # SSH and rename/move atomically to avoid interference ssh -i ../private.key -o StrictHostKeyChecking=no ${{ secrets.VPS_USERNAME }}@${{ secrets.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 docker image prune -af --filter "until=336h" --filter "label!=keep=true" ENDSSH - name: Cleanup temporary files if: always() run: | rm -f ../private.key