Deploy Gate #12
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 Gate | |
| # Runs whenever Test, Typecheck, Lint Code, or Security Audit completes on a PR/push. | |
| # Checks whether all required PR smoke gates have passed for the same commit SHA. | |
| # Posts a commit status on the PR's head SHA so branch protection can see it. | |
| on: | |
| workflow_run: | |
| workflows: ["Test", "Typecheck", "Lint Code", "Security Audit"] | |
| types: [completed] | |
| permissions: | |
| statuses: write | |
| jobs: | |
| gate: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check required PR gates passed for this SHA | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| REPO: ${{ github.repository }} | |
| SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: | | |
| required='["changes","docs-stats","unit","sidecar","convex-tests","variant-smoke-full","resilience-validation-smoke","digest-image","typecheck","biome","security-audit"]' | |
| # Poll check-runs for this SHA and find the latest result for each required job. | |
| # Project to just the three fields the gate logic reads. A SHA can | |
| # accumulate dozens of full check-run objects across re-runs; passing | |
| # the un-projected JSON to python3 via the RUNS_JSON env var overflowed | |
| # Linux's 128KB-per-arg/env limit (MAX_ARG_STRLEN) once it crossed | |
| # ~131KB, failing the gate with "Argument list too long" (exit 126). | |
| runs=$(gh api "repos/$REPO/commits/$SHA/check-runs?per_page=100" \ | |
| --jq ".check_runs | map(select(.name as \$name | $required | index(\$name)) | {name, conclusion, completed_at})") | |
| status=$(RUNS_JSON="$runs" REQUIRED_JOBS="$required" python3 -c " | |
| import json | |
| import os | |
| runs = json.loads(os.environ['RUNS_JSON']) | |
| required = json.loads(os.environ['REQUIRED_JOBS']) | |
| latest = {} | |
| for name in required: | |
| matches = [r for r in runs if r.get('name') == name] | |
| if matches: | |
| latest_run = sorted(matches, key=lambda r: r.get('completed_at') or '')[-1] | |
| latest[name] = latest_run.get('conclusion') or 'pending' | |
| else: | |
| latest[name] = 'pending' | |
| print(' '.join(f'{name}={latest[name]}' for name in required)) | |
| print('pending=' + ','.join(name for name in required if latest[name] == 'pending')) | |
| print('failed=' + ','.join(name for name in required if latest[name] not in ('success', 'skipped'))) | |
| ") | |
| echo "$status" | |
| pending=$(echo "$status" | awk -F= '/^pending=/ { print $2 }') | |
| failed=$(echo "$status" | awk -F= '/^failed=/ { print $2 }') | |
| if [ -n "$pending" ]; then | |
| gh api "repos/$REPO/statuses/$SHA" --method POST \ | |
| --field state="pending" \ | |
| --field context="gate" \ | |
| --field description="Waiting for required PR gates: $pending" | |
| exit 0 | |
| fi | |
| # Treat "skipped" as passing (docs-only PRs skip code checks) | |
| if [ -n "$failed" ]; then | |
| gh api "repos/$REPO/statuses/$SHA" --method POST \ | |
| --field state="failure" \ | |
| --field context="gate" \ | |
| --field description="Required PR gates did not pass: $failed" | |
| exit 0 | |
| fi | |
| gh api "repos/$REPO/statuses/$SHA" --method POST \ | |
| --field state="success" \ | |
| --field context="gate" \ | |
| --field description="All required PR gates passed" |