name: Build & Deploy on: push: branches: [develop] workflow_dispatch: concurrency: group: build-${{ gitea.ref }} cancel-in-progress: false env: NODE_VERSION: "20" # Gitea built-in container registry (HTTPS on port 443) REGISTRY_HOST: 192.168.3.80 DOCKERFILE_PATH: Dockerfile.production # VPS deployment target DEPLOY_ROOT: /opt/rentaldrivego jobs: build-image: name: Build & Push Docker Image runs-on: ubuntu-latest outputs: image_repository: ${{ steps.image-meta.outputs.repository }} docker_image: ${{ steps.image-meta.outputs.full }} steps: - uses: actions/checkout@v4 env: GIT_SSL_NO_VERIFY: "true" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Docker image metadata id: image-meta run: | # Gitea container registry path: host/owner/repo REPO="${{ gitea.repository }}" TAG="${{ gitea.sha }}" echo "repository=${REPO}" >> "$GITHUB_OUTPUT" echo "full=${REGISTRY_HOST}/${REPO}:${TAG}" >> "$GITHUB_OUTPUT" echo "latest=${REGISTRY_HOST}/${REPO}:latest" >> "$GITHUB_OUTPUT" - name: Check Docker registry credentials id: registry-check run: | if [ -n "${{ secrets.REGISTRY_TOKEN }}" ]; then echo "available=true" >> "$GITHUB_OUTPUT" else echo "available=false" >> "$GITHUB_OUTPUT" fi - name: Install Docker CLI if: steps.registry-check.outputs.available == 'true' run: | apt-get update -qq apt-get install -y -qq docker.io - name: Log in to Gitea Container Registry if: steps.registry-check.outputs.available == 'true' run: | echo "${{ secrets.REGISTRY_TOKEN }}" | \ docker login "$REGISTRY_HOST" \ -u "${{ gitea.actor }}" \ --password-stdin - name: Build and push uses: docker/build-push-action@v6 with: context: . file: ${{ env.DOCKERFILE_PATH }} push: ${{ steps.registry-check.outputs.available == 'true' }} tags: | ${{ steps.image-meta.outputs.full }} ${{ steps.image-meta.outputs.latest }} build-args: | API_INTERNAL_URL=http://api:4000/api/v1 DASHBOARD_INTERNAL_URL=http://dashboard:3001 ADMIN_INTERNAL_URL=http://admin:3002 NEXT_PUBLIC_API_URL=${{ secrets.NEXT_PUBLIC_API_URL }} NEXT_PUBLIC_MARKETPLACE_URL=${{ secrets.NEXT_PUBLIC_MARKETPLACE_URL }} NEXT_PUBLIC_DASHBOARD_URL=${{ secrets.NEXT_PUBLIC_DASHBOARD_URL }} NEXT_PUBLIC_ADMIN_URL=${{ secrets.NEXT_PUBLIC_ADMIN_URL }} deploy: name: Deploy to VPS runs-on: ubuntu-latest needs: [build-image] env: DOCKER_IMAGE: ${{ needs.build-image.outputs.docker_image }} IMAGE_REPOSITORY: ${{ needs.build-image.outputs.image_repository }} steps: - uses: actions/checkout@v4 env: GIT_SSL_NO_VERIFY: "true" - name: Check deploy credentials id: check-creds run: | if [ -z "${{ secrets.VPS_SSH_KEY }}" ] || \ [ -z "${{ secrets.VPS_IP }}" ] || \ [ -z "${{ secrets.VPS_USER }}" ]; then echo "VPS secrets not fully configured — skipping deploy" echo "skip=true" >> "$GITHUB_OUTPUT" else echo "skip=false" >> "$GITHUB_OUTPUT" fi - name: Install SSH client if: steps.check-creds.outputs.skip == 'false' run: | apt-get update -qq && apt-get install -y -qq openssh-client - name: Set up SSH key if: steps.check-creds.outputs.skip == 'false' run: | mkdir -p ~/.ssh && chmod 700 ~/.ssh echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -H "${{ secrets.VPS_IP }}" >> ~/.ssh/known_hosts 2>/dev/null chmod 644 ~/.ssh/known_hosts - name: Sync deployment assets if: steps.check-creds.outputs.skip == 'false' run: | ssh "${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}" \ "mkdir -p '$DEPLOY_ROOT/scripts' '$DEPLOY_ROOT/docker/pgmanage' '$DEPLOY_ROOT/docker/registry/auth' '$DEPLOY_ROOT/dynamic'" scp docker-compose.production.yml \ docker-compose.portainer.production.yml \ docker-compose.registry.production.yml \ docker-compose.registry.local.yml \ traefik.yaml \ "${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}:$DEPLOY_ROOT/" scp scripts/docker-prod-common.sh \ scripts/docker-prod-deploy.sh \ scripts/docker-prod-up-registry.sh \ scripts/docker-registry-local-up.sh \ "${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}:$DEPLOY_ROOT/scripts/" scp docker/pgmanage/override.py \ "${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}:$DEPLOY_ROOT/docker/pgmanage/" - name: Run deploy script on VPS if: steps.check-creds.outputs.skip == 'false' run: | REGISTRY_PASSWORD_B64="$(printf '%s' "${{ secrets.REGISTRY_TOKEN }}" | base64 | tr -d '\n')" ssh "${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}" " set -e cd '$DEPLOY_ROOT' APP_IMAGE='$IMAGE_REPOSITORY' \ APP_VERSION='${{ gitea.sha }}' \ REGISTRY_HOST='$REGISTRY_HOST' \ REGISTRY_USER='${{ gitea.actor }}' \ REGISTRY_PASSWORD=\$(printf '%s' '$REGISTRY_PASSWORD_B64' | base64 -d) \ bash scripts/docker-prod-deploy.sh "