Status Check #24
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: Status Check | |
| # This workflow enforces that all relevant CI checks pass based on which files changed. | |
| # It's the only required status check in branch protection settings. | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| workflow_run: | |
| workflows: ["Python CI", "Go CI", "TypeScript CI"] | |
| types: [completed] | |
| permissions: | |
| contents: read | |
| statuses: write | |
| checks: write | |
| pull-requests: read | |
| jobs: | |
| verify-required-checks: | |
| name: Verify Required Checks | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' || github.event.workflow_run.conclusion != 'cancelled' | |
| steps: | |
| - name: Check out code | |
| uses: actions/checkout@v4 | |
| - name: Get PR number | |
| id: pr | |
| run: | | |
| if [ "${{ github.event_name }}" == "workflow_run" ]; then | |
| PR_NUMBER=$(gh pr list --head "${{ github.event.workflow_run.head_branch }}" --json number --jq '.[0].number') | |
| echo "number=$PR_NUMBER" >> $GITHUB_OUTPUT | |
| else | |
| echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Get changed files | |
| id: changed-files | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| filters: | | |
| python: | |
| - 'python/**' | |
| - '.github/workflows/python.yml' | |
| go: | |
| - 'go/**' | |
| - '.github/workflows/go.yml' | |
| typescript: | |
| - 'typescript/**' | |
| - '.github/workflows/typescript.yml' | |
| - name: Check required statuses | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| const ref = context.payload.pull_request?.head.sha || context.payload.workflow_run?.head_sha; | |
| // Define required checks per language | |
| const requiredChecks = { | |
| python: [ | |
| 'Python CI / Linting', | |
| 'Python CI / Unit Tests (3.10)', | |
| 'Python CI / Unit Tests (3.11)', | |
| 'Python CI / Unit Tests (3.12)' | |
| ], | |
| go: [ | |
| 'Go CI / Linting', | |
| 'Go CI / Unit Tests (1.23)', | |
| 'Go CI / Unit Tests (1.24)', | |
| 'Go CI / Unit Tests (1.25)', | |
| 'Go CI / Race Detection' | |
| ], | |
| typescript: [ | |
| 'TypeScript CI / Linting', | |
| 'TypeScript CI / Unit Tests (20)', | |
| 'TypeScript CI / Unit Tests (22)' | |
| ] | |
| }; | |
| // Get changed files from previous step | |
| const changedFiles = { | |
| python: ${{ steps.changed-files.outputs.python }} === 'true', | |
| go: ${{ steps.changed-files.outputs.go }} === 'true', | |
| typescript: ${{ steps.changed-files.outputs.typescript }} === 'true' | |
| }; | |
| // Collect all required checks based on changes | |
| let allRequiredChecks = []; | |
| for (const [lang, changed] of Object.entries(changedFiles)) { | |
| if (changed) { | |
| allRequiredChecks = allRequiredChecks.concat(requiredChecks[lang]); | |
| } | |
| } | |
| if (allRequiredChecks.length === 0) { | |
| console.log('No language files changed, no checks required'); | |
| return; | |
| } | |
| // Get all check runs for this commit | |
| const { data: checkRuns } = await github.rest.checks.listForRef({ | |
| owner, | |
| repo, | |
| ref | |
| }); | |
| // Verify all required checks have passed | |
| const checkStatuses = {}; | |
| for (const check of checkRuns.check_runs) { | |
| checkStatuses[check.name] = check.conclusion; | |
| } | |
| let allPassed = true; | |
| let failureMessage = ''; | |
| for (const requiredCheck of allRequiredChecks) { | |
| const status = checkStatuses[requiredCheck]; | |
| if (!status) { | |
| allPassed = false; | |
| failureMessage += `❌ ${requiredCheck}: Not started\\n`; | |
| } else if (status !== 'success') { | |
| allPassed = false; | |
| failureMessage += `❌ ${requiredCheck}: ${status}\\n`; | |
| } else { | |
| failureMessage += `✅ ${requiredCheck}: ${status}\\n`; | |
| } | |
| } | |
| if (!allPassed) { | |
| core.setFailed(`Required checks have not passed:\\n${failureMessage}`); | |
| } else { | |
| console.log(`All required checks passed:\\n${failureMessage}`); | |
| } |