Repository navigation
docs: clarify reload password CLI/HTTP threat model (#2477) (#2516) #263
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy static sites | |
| on: | |
| push: | |
| branches: [develop] | |
| paths: | |
| - 'web/**' | |
| - '.github/workflows/web-deploy.yml' | |
| pull_request: | |
| branches: [develop] | |
| paths: | |
| - 'web/**' | |
| - '.github/workflows/web-deploy.yml' | |
| repository_dispatch: | |
| types: [registry-updated] | |
| jobs: | |
| deploy: | |
| name: Deploy ${{ matrix.site }} | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: web-deploy-${{ matrix.site }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| deployments: write | |
| pull-requests: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| site: ${{ github.event_name == 'repository_dispatch' && fromJSON('["packages"]') || fromJSON('["landing", "blog", "guides", "api", "packages"]') }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Set up pnpm | |
| uses: pnpm/action-setup@v5 | |
| with: | |
| version: 10.23.0 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: web/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: web | |
| run: pnpm install --frozen-lockfile | |
| - name: Build ${{ matrix.site }} | |
| working-directory: web | |
| run: pnpm --filter @wheels-dev/site-${{ matrix.site }} build | |
| - name: Deploy to Cloudflare Pages | |
| working-directory: web | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| # Routed via env to keep untrusted branch names out of the command string. | |
| DEPLOY_BRANCH: ${{ github.head_ref || github.ref_name }} | |
| SITE: ${{ matrix.site }} | |
| run: | | |
| pnpm dlx wrangler@4.78.0 pages deploy "sites/${SITE}/dist" \ | |
| --project-name="wheels-${SITE}" \ | |
| --branch="${DEPLOY_BRANCH}" \ | |
| --commit-hash="${GITHUB_SHA}" | |
| visual-regression: | |
| name: Visual regression | |
| # Hard gate for non-content changes (layout/styling/structure). For | |
| # content-only pushes (markdown under web/content/blog/posts/), the | |
| # job auto-regenerates the affected baseline, commits it back to | |
| # develop with [skip ci], and exits success — so adding a new blog | |
| # article doesn't trip a stale-baseline failure. | |
| # | |
| # If this job fails on a non-content PR and the change is intentional, | |
| # download the `visual-regression-diffs` artifact and copy each | |
| # *.actual.png over the matching web/tests/visual-baselines/*.png, | |
| # commit, and push. | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up pnpm | |
| uses: pnpm/action-setup@v5 | |
| with: | |
| version: 10.23.0 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| cache: pnpm | |
| cache-dependency-path: web/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: web | |
| run: pnpm install --frozen-lockfile | |
| - name: Cache Playwright browsers | |
| uses: actions/cache@v5 | |
| id: playwright-cache | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: playwright-${{ runner.os }}-${{ hashFiles('web/pnpm-lock.yaml') }} | |
| - name: Install Playwright Chromium | |
| if: steps.playwright-cache.outputs.cache-hit != 'true' | |
| working-directory: web | |
| run: pnpm exec playwright install --with-deps chromium | |
| - name: Build all sites | |
| working-directory: web | |
| run: pnpm build | |
| - name: Run visual regression | |
| id: regress | |
| continue-on-error: true | |
| working-directory: web | |
| run: pnpm visual:test | |
| - name: Detect content-only push | |
| id: scope | |
| if: steps.regress.outcome == 'failure' && github.event_name == 'push' | |
| run: | | |
| set -euo pipefail | |
| # `changed` comes from git itself (file paths under version | |
| # control), not from user-controlled event metadata, so it's | |
| # safe to grep over without further sanitization. | |
| changed=$(git diff --name-only HEAD~1..HEAD) | |
| non_content=$(echo "$changed" | grep -v -E '^web/content/blog/posts/' || true) | |
| if [ -z "$non_content" ]; then | |
| echo "content_only=true" >> "$GITHUB_OUTPUT" | |
| echo "All changes under web/content/blog/posts/ — will auto-refresh baseline." | |
| else | |
| echo "content_only=false" >> "$GITHUB_OUTPUT" | |
| echo "Non-content files changed; treating regression failure as real." | |
| echo "$non_content" | |
| fi | |
| - name: Auto-refresh blog baseline | |
| if: steps.regress.outcome == 'failure' && steps.scope.outputs.content_only == 'true' | |
| working-directory: web | |
| run: node scripts/visual-regression.mjs --update --site blog | |
| - name: Commit and push refreshed baseline | |
| if: steps.regress.outcome == 'failure' && steps.scope.outputs.content_only == 'true' | |
| run: | | |
| set -euo pipefail | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add web/tests/visual-baselines/blog.png | |
| if git diff --cached --quiet; then | |
| echo "Baseline did not actually change after refresh — exiting clean." | |
| exit 0 | |
| fi | |
| # [skip ci] keeps this push from re-triggering the deploy | |
| # workflow and creating a publish loop. | |
| git commit -m "chore(docs): auto-refresh blog visual baseline after content change [skip ci]" | |
| git push origin HEAD:develop | |
| - name: Fail job on real regression | |
| if: steps.regress.outcome == 'failure' && steps.scope.outputs.content_only != 'true' | |
| run: | | |
| echo "Visual regression failed on changes that include non-content files." | |
| echo "Download the visual-regression-diffs artifact and update baselines as needed." | |
| exit 1 | |
| - name: Upload diffs on failure | |
| if: steps.regress.outcome == 'failure' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: visual-regression-diffs | |
| path: | | |
| web/tests/visual-diffs/*.png | |
| web/tests/visual-baselines/*.png | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| # Note: the packages-index baseline auto-refresh that fires on | |
| # repository_dispatch: registry-updated lives in its own workflow file | |
| # at .github/workflows/refresh-packages-baseline.yml so it doesn't | |
| # appear as a "skipped" check on regular PRs. |