Merge pull request #14 from avalon-vanguard/develop

🌾 ci: only deploy Pages when docs/ actually changed
This commit is contained in:
Senrokai
2026-08-20 16:49:00 +02:00
committed by GitHub
+82 -5
View File
@@ -6,9 +6,11 @@ name: Deploy Pages
#
# Triggered by CI completing on main rather than by the push itself, so a deploy
# implies the full suite passed — type-check, lint, tests, build, entry points, docs.
# A push that breaks a test turns main red and never reaches Pages; the previous
# wiring deployed on any docs push, green CI or not. workflow_dispatch stays as the
# manual escape hatch, and the deploy job refuses any ref that is not main.
# A push that breaks a test turns main red and never reaches Pages. workflow_dispatch
# stays as the manual escape hatch, and the deploy job refuses any ref that is not main.
#
# workflow_run cannot carry a `paths:` filter the way `push:` can, so the docs-changed
# question is asked in a job instead — see the `changes` job below.
#
# REQUIRES A ONE-TIME SETTING. Settings → Pages → Build and deployment → Source must
# be "GitHub Actions", not "Deploy from a branch". Until it is, the first run fails —
@@ -33,17 +35,92 @@ concurrency:
cancel-in-progress: false
jobs:
build:
name: Build and check
changes:
name: Did docs change?
runs-on: ubuntu-latest
# workflow_run fires on failure too — deploying is the one thing that must not.
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
permissions:
contents: read
deployments: read
outputs:
docs: ${{ steps.check.outputs.docs }}
steps:
- uses: actions/checkout@v4
with:
# For workflow_run the default checkout is the branch tip, which is not
# necessarily the commit CI just validated — two pushes in quick succession
# would deploy the newer one under the older one's green tick. Empty on
# workflow_dispatch, where the dispatched ref is what we want.
ref: ${{ github.event.workflow_run.head_sha }}
# Deep enough to reach whatever commit is currently live.
fetch-depth: 0
- id: check
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "Manual dispatch — deploying whatever the state of docs/ is."
echo "docs=true" >> "$GITHUB_OUTPUT"
exit 0
fi
api() { curl -fsS -H "Authorization: Bearer $GH_TOKEN" -H "Accept: application/vnd.github+json" "$@"; }
BASE="$GITHUB_API_URL/repos/$GITHUB_REPOSITORY"
# What is actually live: the commit behind the newest *successful* Pages
# deployment. Comparing against that, rather than against HEAD^, is what keeps
# this correct when a push carries several commits (the change may be in any of
# them) and when the last deploy failed (the site is then a version further
# behind than the previous commit suggests).
DEPLOYMENTS=$(api "$BASE/deployments?environment=github-pages&per_page=10")
LIVE=""
for id in $(echo "$DEPLOYMENTS" | jq -r '.[].id'); do
state=$(api "$BASE/deployments/$id/statuses?per_page=1" | jq -r '.[0].state // empty')
if [ "$state" = "success" ]; then
LIVE=$(echo "$DEPLOYMENTS" | jq -r --argjson id "$id" '.[] | select(.id == $id) | .sha')
break
fi
done
if [ -z "$LIVE" ]; then
echo "No successful github-pages deployment to compare against — deploying."
echo "docs=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if ! git cat-file -e "${LIVE}^{commit}" 2>/dev/null; then
echo "Live commit $LIVE is not in this history (force push, or rebuilt branch) — deploying."
echo "docs=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Live on Pages: $LIVE"
echo "This commit: $GITHUB_SHA"
if git diff --quiet "$LIVE" HEAD -- docs/; then
echo "docs/ is byte-identical to what is already published — nothing to deploy."
echo "docs=false" >> "$GITHUB_OUTPUT"
else
echo "docs/ changed:"
git diff --name-only "$LIVE" HEAD -- docs/ | sed 's/^/ /'
echo "docs=true" >> "$GITHUB_OUTPUT"
fi
build:
name: Build and check
needs: changes
if: needs.changes.outputs.docs == 'true'
runs-on: ubuntu-latest
# This job runs third-party code (npm postinstall scripts, the build toolchain),
# so it gets read-only. The Pages/OIDC grants live on the deploy job alone.
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
- uses: actions/setup-node@v4
with:
node-version: 22.x