Skip to content

Bump actions/checkout from 4 to 7 #46

Bump actions/checkout from 4 to 7

Bump actions/checkout from 4 to 7 #46

Workflow file for this run

# The single source of truth for "is master shippable" and the only automated
# path to production. On every push to master and every PR it lints, tests, and
# runs the full build from a clean checkout (so `tsc -b` is never cache-masked,
# the way a stale local .tsbuildinfo once hid a broken vite.config). On a push
# to master, and only after lint + test + build pass, it deploys to gh-pages.
# That keeps the live site equal to a pushed, green commit instead of whatever
# happened to be in someone's working tree. `npm run deploy` stays as a manual
# break-glass fallback. (The daily rankings Action deploys its own data commit
# separately: its push uses GITHUB_TOKEN, which by design does not trigger this
# workflow, so ci.yml never sees that commit.)
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
# Cancel superseded PR runs, but never interrupt a master run mid-deploy.
# Master pushes share the deploy-pages group with the daily rankings workflow
# so the two gh-pages publishes serialize instead of interleaving.
concurrency:
group: ${{ github.event_name == 'push' && 'deploy-pages' || format('ci-{0}', github.ref) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
ci:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: write # the deploy step pushes the build to the gh-pages branch
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # the stale-pool guard diffs against the pre-push tip, which can be many commits back
# Guard against the clobber that bit us once (af2bb49): a human commit that
# carries a stale, locally-built draft pool and silently reverts the bot's
# daily data. The bot and any fresh rebuild only move generatedAt forward;
# an untouched commit leaves it equal. So if this push moves any
# draftPool.<season>.json generatedAt BACKWARD versus the pre-push master
# tip, stop before deploying. Compared against github.event.before, not
# HEAD~1: a multi-commit push can bury the stale pool one commit deep,
# where a parent-only check never sees it. ISO-8601 timestamps compare
# correctly as strings.
# Deliberately rolling data back? Rebuild fresh (npm run update:rankings)
# so it moves forward, or use the npm run deploy break-glass.
- name: Guard against stale draft-pool clobber
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
base="${{ github.event.before }}"
# Force push or missing before-SHA (also the all-zeros SHA): fall
# back to the parent commit rather than skipping the guard entirely.
if [ -z "$base" ] || ! git cat-file -e "$base^{commit}" 2>/dev/null; then
base=$(git rev-parse HEAD~1 2>/dev/null || true)
fi
[ -n "$base" ] || { echo "No base commit to compare against; skipping guard."; exit 0; }
for f in src/data/draftPool.*.json; do
[ -f "$f" ] || continue
cur=$(grep -m1 '"generatedAt"' "$f" | sed -E 's/.*"generatedAt": *"([^"]+)".*/\1/' || true)
prev=$(git show "$base:$f" 2>/dev/null | grep -m1 '"generatedAt"' | sed -E 's/.*"generatedAt": *"([^"]+)".*/\1/' || true)
if [ -n "$prev" ] && [ -n "$cur" ] && [[ "$cur" < "$prev" ]]; then
echo "::error::$f generatedAt moved backward ($prev -> $cur). This looks like a stale local pool clobbering the bot's update. Run 'git checkout origin/master -- src/data' or 'npm run update:rankings', then recommit."
exit 1
fi
done
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- name: Lint
run: npm run lint
- name: Typecheck
run: npm run typecheck
- name: Test
run: npm run test:run
- name: Build
run: npm run build
# Present only on master pushes (PRs from forks can't read secrets), so
# source maps upload to Sentry on real deploys and are skipped otherwise.
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
# The prerender step degrades to an empty SPA on failure (exit 0) so the
# unattended rankings deploy never breaks. That makes a broken prerender
# silent. CI is attended, so surface it as a warning when dist/index.html
# ships an empty #root - visible in the run, without blocking the deploy.
- name: Verify homepage prerender
run: |
if grep -q '<div id="root"></div>' dist/index.html; then
echo "::warning::Homepage prerender did not inject markup; dist/index.html ships an empty #root (SEO/unfurl copy missing)."
else
echo "::notice::Homepage prerender injected static markup into dist/index.html."
fi
# If master moved while this run was building (e.g. the daily rankings
# job rebased our commit in, deployed, and pushed its data commit),
# deploying our older tree now would overwrite that newer deploy and
# drop the fresh data from production until the next run. The newer
# commit's own deploy already includes this commit, so skip ours.
- name: Check this commit is still the master tip
id: tip
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
git fetch origin master
if [ "$(git rev-parse origin/master)" = "${{ github.sha }}" ]; then
echo "deploy=true" >> "$GITHUB_OUTPUT"
else
echo "deploy=false" >> "$GITHUB_OUTPUT"
echo "::notice::master moved past ${{ github.sha }} while this run built; skipping deploy (the newer commit's deploy includes this one)."
fi
- name: Deploy to GitHub Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && steps.tip.outputs.deploy == 'true'
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist