diff --git a/.forgejo/workflows/deploy-tradein.yml b/.forgejo/workflows/deploy-tradein.yml index 1c10cf23..eafe2980 100644 --- a/.forgejo/workflows/deploy-tradein.yml +++ b/.forgejo/workflows/deploy-tradein.yml @@ -24,16 +24,82 @@ jobs: changes: runs-on: ubuntu-latest outputs: - backend: ${{ steps.filter.outputs.backend }} - frontend: ${{ steps.filter.outputs.frontend }} - browser: ${{ steps.filter.outputs.browser }} - infra: ${{ steps.filter.outputs.infra }} - scraper: ${{ steps.filter.outputs.scraper }} + backend: ${{ steps.set-all.outputs.backend || steps.filter.outputs.backend }} + frontend: ${{ steps.set-all.outputs.frontend || steps.filter.outputs.frontend }} + browser: ${{ steps.set-all.outputs.browser || steps.filter.outputs.browser }} + infra: ${{ steps.set-all.outputs.infra || steps.filter.outputs.infra }} + scraper: ${{ steps.set-all.outputs.scraper || steps.filter.outputs.scraper }} steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Resolve base SHA: read last-successfully-deployed SHA from the VPS host file. + # The file is written by the deploy job on every successful deploy. + # Fail-safe: if we cannot read the file, or the SHA is not an ancestor of HEAD, + # we leave DEPLOYED_SHA empty — the next step will then build everything. + - name: Resolve deployed base SHA + id: resolve-base + env: + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + run: | + # Write SSH key to a temp file + SSH_KEY_FILE=$(mktemp) + echo "$DEPLOY_SSH_KEY" > "$SSH_KEY_FILE" + chmod 600 "$SSH_KEY_FILE" + + # Try to read the marker file from the VPS. Suppress errors — if host is + # unreachable or file missing, RAW_SHA will be empty. + RAW_SHA=$(ssh -i "$SSH_KEY_FILE" \ + -o StrictHostKeyChecking=no \ + -o ConnectTimeout=10 \ + -p "${DEPLOY_PORT:-22}" \ + "${DEPLOY_USER}@${DEPLOY_HOST}" \ + "cat /opt/gendesign/.tradein-deployed-sha 2>/dev/null || true" \ + 2>/dev/null || true) + RAW_SHA=$(echo "$RAW_SHA" | tr -d '[:space:]') + + rm -f "$SSH_KEY_FILE" + + # Validate: non-empty, looks like a git SHA, and is an ancestor of HEAD. + DEPLOYED_SHA="" + if [ -n "$RAW_SHA" ] && echo "$RAW_SHA" | grep -qE '^[0-9a-f]{40}$'; then + if git merge-base --is-ancestor "$RAW_SHA" HEAD 2>/dev/null; then + DEPLOYED_SHA="$RAW_SHA" + echo "Resolved deployed base: $DEPLOYED_SHA" + else + echo "WARNING: stored SHA $RAW_SHA is not an ancestor of HEAD — falling back to build-all" + fi + else + echo "No valid deployed SHA found — falling back to build-all" + fi + + echo "deployed_sha=$DEPLOYED_SHA" >> "$GITHUB_OUTPUT" + + # FAIL-SAFE: if no valid base SHA, emit all=true and skip paths-filter. + # This covers: first run, post-force-push, VPS unreachable, corrupt marker. + # A spurious full build is always safer than a missed build. + - name: Build-all fallback (no base SHA) + id: set-all + if: steps.resolve-base.outputs.deployed_sha == '' + run: | + echo "No base SHA — enabling build-all" + echo "backend=true" >> "$GITHUB_OUTPUT" + echo "frontend=true" >> "$GITHUB_OUTPUT" + echo "browser=true" >> "$GITHUB_OUTPUT" + echo "infra=true" >> "$GITHUB_OUTPUT" + echo "scraper=true" >> "$GITHUB_OUTPUT" + + # Cumulative diff: compare deployed SHA → HEAD so that a fast chain of merges + # (e.g. backend #1829 then frontend #1830) doesn't lose earlier changes. - uses: dorny/paths-filter@v3 id: filter + if: steps.resolve-base.outputs.deployed_sha != '' with: + base: ${{ steps.resolve-base.outputs.deployed_sha }} filters: | backend: - 'tradein-mvp/backend/**' @@ -211,12 +277,13 @@ jobs: IMAGE_TAG: latest GHCR_PAT: ${{ secrets.GHCR_PAT }} SCRAPER_CHANGED: ${{ needs.changes.outputs.scraper == 'true' || needs.changes.outputs.infra == 'true' || github.event_name == 'workflow_dispatch' }} + GITHUB_SHA: ${{ github.sha }} with: host: ${{ secrets.DEPLOY_HOST }} username: ${{ secrets.DEPLOY_USER }} key: ${{ secrets.DEPLOY_SSH_KEY }} port: ${{ secrets.DEPLOY_PORT }} - envs: IMAGE_TAG,GHCR_PAT,SCRAPER_CHANGED + envs: IMAGE_TAG,GHCR_PAT,SCRAPER_CHANGED,GITHUB_SHA script: | set -euo pipefail cd /opt/gendesign @@ -371,3 +438,9 @@ jobs: | xargs -r docker rmi 2>/dev/null || true done docker image prune -af || true + + # Mark this SHA as successfully deployed. + # Written LAST — only after all of the above completed without error. + # The changes job reads this file on the next run to compute cumulative diff. + echo "$GITHUB_SHA" > /opt/gendesign/.tradein-deployed-sha + echo "→ Deployed SHA marker updated: $GITHUB_SHA"