PR Checks #16
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: PR Checks | |
| on: | |
| issue_comment: | |
| types: [created] | |
| jobs: | |
| slash-command: | |
| name: Parse /run-checks | |
| if: >- | |
| github.event.issue.pull_request != null && | |
| contains(github.event.comment.body, '/run-checks') | |
| runs-on: ubuntu-latest | |
| outputs: | |
| pr-sha: ${{ steps.get-sha.outputs.sha }} | |
| steps: | |
| - name: Check commenter permission | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| username: context.actor, | |
| }); | |
| if (!['admin', 'write'].includes(data.permission)) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `@${context.actor} Only maintainers can trigger checks.`, | |
| }); | |
| core.setFailed('Unauthorized'); | |
| } | |
| - name: React with rocket | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| await github.rest.reactions.createForIssueComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: ${{ github.event.comment.id }}, | |
| content: 'rocket', | |
| }); | |
| - name: Get PR head SHA | |
| id: get-sha | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const { data: pr } = await github.rest.pulls.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| }); | |
| core.setOutput('sha', pr.head.sha); | |
| - name: Set checks to pending | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const sha = '${{ steps.get-sha.outputs.sha }}'; | |
| const checks = ['Lint', 'Build C++ (ubuntu-22.04)', 'Build C++ (ubuntu-24.04)', 'Build C++ (macos-14)', 'Validate']; | |
| for (const check of checks) { | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha, | |
| state: 'pending', | |
| context: check, | |
| description: 'Waiting...', | |
| }); | |
| } | |
| lint: | |
| name: Lint | |
| needs: slash-command | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.slash-command.outputs.pr-sha }} | |
| - name: C++ format check | |
| run: | | |
| sudo apt-get install -y clang-format | |
| find . -name "*.cpp" -o -name "*.h" | grep -v "build/" | \ | |
| xargs clang-format --dry-run --Werror || true | |
| - name: Python lint (ruff) | |
| uses: chartboost/ruff-action@v1 | |
| with: | |
| args: "check engine/ --ignore E501 --exit-zero" | |
| - name: Report status | |
| if: always() | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: '${{ needs.slash-command.outputs.pr-sha }}', | |
| state: '${{ job.status }}' === 'success' ? 'success' : 'failure', | |
| context: 'Lint', | |
| description: '${{ job.status }}', | |
| }); | |
| build-cpp: | |
| name: Build C++ (${{ matrix.os }}) | |
| needs: slash-command | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-22.04, ubuntu-24.04, macos-14] | |
| include: | |
| - os: ubuntu-22.04 | |
| artifact: quadtrix-linux-x64 | |
| - os: ubuntu-24.04 | |
| artifact: quadtrix-linux-x64-noble | |
| - os: macos-14 | |
| artifact: quadtrix-macos-arm64 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.slash-command.outputs.pr-sha }} | |
| - name: Install GCC (Linux) | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update && sudo apt-get install -y g++ ccache | |
| - name: Cache ccache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.ccache | |
| key: ccache-${{ matrix.os }}-${{ hashFiles('**/*.cpp', '**/*.h') }} | |
| restore-keys: ccache-${{ matrix.os }}- | |
| - name: Compile main.cpp | |
| run: | | |
| g++ -std=c++17 -O3 -march=native \ | |
| -I. -Iinclude \ | |
| -o quadtrix main.cpp | |
| - name: Smoke test | |
| run: ./quadtrix --help || true | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: quadtrix | |
| retention-days: 7 | |
| - name: Report status | |
| if: always() | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: '${{ needs.slash-command.outputs.pr-sha }}', | |
| state: '${{ job.status }}' === 'success' ? 'success' : 'failure', | |
| context: 'Build C++ (${{ matrix.os }})', | |
| description: '${{ job.status }}', | |
| }); | |
| validate: | |
| name: Validate | |
| needs: slash-command | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ needs.slash-command.outputs.pr-sha }} | |
| - name: Check required files exist | |
| run: | | |
| files=( | |
| "main.cpp" | |
| "engine/main.py" | |
| "requirements.txt" | |
| ) | |
| failed=0 | |
| for f in "${files[@]}"; do | |
| if [ -f "$f" ]; then | |
| echo "✅ $f" | |
| else | |
| echo "❌ $f — MISSING" | |
| failed=1 | |
| fi | |
| done | |
| exit $failed | |
| - name: Lint — Dockerfile.cpp | |
| uses: hadolint/hadolint-action@v3.1.0 | |
| with: | |
| dockerfile: .devops/Dockerfile.cpp | |
| failure-threshold: error | |
| - name: Lint — Dockerfile (CPU) | |
| uses: hadolint/hadolint-action@v3.1.0 | |
| with: | |
| dockerfile: .devops/Dockerfile | |
| failure-threshold: error | |
| - name: Lint — Dockerfile.backend (CUDA) | |
| uses: hadolint/hadolint-action@v3.1.0 | |
| with: | |
| dockerfile: .devops/Dockerfile.backend | |
| failure-threshold: error | |
| - name: Report status | |
| if: always() | |
| uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| await github.rest.repos.createCommitStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| sha: '${{ needs.slash-command.outputs.pr-sha }}', | |
| state: '${{ job.status }}' === 'success' ? 'success' : 'failure', | |
| context: 'Validate', | |
| description: '${{ job.status }}', | |
| }); | |
| post-result: | |
| name: Post result | |
| needs: [slash-command, lint, build-cpp, validate] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const jobs = ${{ toJSON(needs) }}; | |
| const failed = Object.values(jobs).some(j => j.result === 'failure'); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: failed | |
| ? '❌ Some checks failed — see Actions for details.' | |
| : '✅ All checks passed!', | |
| }); |