Document the environment with env.default, and tell agents not to rea… #15
Workflow file for this run
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
| # Runs the full validation suite against every environment daily, then builds | |
| # and deploys the dashboard website to GitHub Pages. | |
| name: Test dashboard | |
| on: | |
| schedule: | |
| - cron: '30 6 * * *' | |
| workflow_dispatch: | |
| # Temporary, remove before merge: workflow_dispatch only works once this file | |
| # is on the default branch, so pre-merge runs of the redesign trigger on push. | |
| # Development moved here from #118, which carried the same trigger on its own | |
| # branch; only one branch should have it at a time, since each run takes | |
| # 20-35 minutes and force-pushes gh-pages. | |
| push: | |
| branches: [redesign-dashboard] | |
| permissions: | |
| contents: write # the deploy action pushes to the gh-pages branch | |
| issues: read # the GitHub issue tests read this repo's issues | |
| concurrency: | |
| group: dashboard-deploy | |
| # Only a manual dispatch supersedes what is already running: you press Run | |
| # workflow because you want fresh output now, and the run it cancels would have | |
| # produced the same two files, so nothing is lost by killing it. A scheduled run | |
| # never cancels anything — a cron run must not be able to kill a slower one that | |
| # is mid-flight, because that is the run that appends the day's history line — | |
| # and neither does a push, which queues behind whatever is deploying rather than | |
| # racing it. | |
| cancel-in-progress: ${{ github.event_name == 'workflow_dispatch' }} | |
| jobs: | |
| test-and-deploy: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 350 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v6 | |
| - name: Run the test suite against every target | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| # The Google Sheet IDs are secrets: they must never be checked in or | |
| # appear in anything this workflow publishes. | |
| BABEL_VALIDATION_SHEET_ID: ${{ secrets.BABEL_VALIDATION_SHEET_ID }} | |
| BABEL_VALIDATION_BLOCKLIST_SHEET_ID: ${{ secrets.BABEL_VALIDATION_BLOCKLIST_SHEET_ID }} | |
| # A nonzero pytest exit (failing tests) is normal here: the report is | |
| # the artifact. `timeout 45m` caps the damage from a hung or down | |
| # environment, whose per-test timeouts would otherwise add up. | |
| # ponytail: sequential loop; split into a matrix job with artifact | |
| # merging if total runtime ever approaches the 6h job limit. | |
| # The explicit `tests` path is required: without a path argument, | |
| # pytest-xdist workers do not load tests/conftest.py early enough to | |
| # know --target/--report-jsonl, and every worker dies at argparse. | |
| run: | | |
| mkdir -p raw | |
| # Ask the report generator which targets exist rather than keeping a | |
| # second list here. The two silently disagreed once already: adding | |
| # [test-redis] to targets.ini put it in every table on the site — as a | |
| # permanently unreachable environment, sorted after prod, and as an | |
| # always-empty column in every ?sig= signature — because read_targets | |
| # takes every section but localhost while this loop did not run it. | |
| targets=$(uv run python -c "from src.babel_validation.tools.generate_report import read_targets; print(' '.join(read_targets('tests/targets.ini')[0]))") | |
| echo "Running against: $targets" | |
| for t in $targets; do | |
| timeout 45m uv run pytest tests --target "$t" -n 8 -m "not unit" \ | |
| --report-jsonl "raw/$t.jsonl" || echo "target $t exited $?" | |
| done | |
| - name: Fetch the previous run history | |
| # The published file is the source of truth: the deploy action | |
| # force-pushes gh-pages as a single commit, so the branch is not an | |
| # append log. The Pages CDN caches for ~10 minutes, so a manual | |
| # dispatch right after a deploy could drop one history line — fine at | |
| # a daily cadence. | |
| run: | | |
| curl -fsSL -o old_history.jsonl \ | |
| https://translatorsri.github.io/babel-validation/data/history.jsonl \ | |
| || : > old_history.jsonl | |
| - name: Generate the report | |
| run: | | |
| uv run python -m src.babel_validation.tools.generate_report \ | |
| --raw-dir raw --targets-ini tests/targets.ini \ | |
| --history-in old_history.jsonl --out-dir website/public/data | |
| # Node 24 for npm 11 — see the note in tests.yaml. Without this the job | |
| # gets the runner's default Node and fails at npm ci, four hours into the | |
| # run, after every test has already been paid for. | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| cache: npm | |
| cache-dependency-path: website/package-lock.json | |
| - name: Build the website | |
| working-directory: website | |
| run: | | |
| npm ci | |
| npm run build | |
| touch dist/.nojekyll | |
| - name: Deploy to GitHub Pages | |
| uses: JamesIves/github-pages-deploy-action@v4 | |
| with: | |
| folder: website/dist | |
| - name: Upload raw outcomes for debugging | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: raw-jsonl | |
| path: raw/ | |
| retention-days: 14 |