Skip to Content
Best PracticesGit Best PracticesCI Requirements for PRs

CI Requirements for Pull Requests

All repositories in the integritystl GitHub org are required to have a build-test status check pass before any pull request can be merged. This is enforced by the org-level “PR-Review” ruleset and satisfies SOC2 CC8.1 (Change Management).

How it works

The org-level ruleset requires a GitHub Actions job named build-test to pass on every PR targeting a trunk branch (main, develop, dev, development, staging). If no build-test check runs on a PR, the merge button is blocked.

This means every repo needs a GitHub Actions workflow that:

  1. Triggers on pull_request
  2. Contains a job named build-test
  3. Performs meaningful validation (not a no-op pass-through)

Existing repos

All active repos already have this set up. You don’t need to do anything for repos that are already producing a build-test check on PRs.

New repos

When creating a new repository, you must add a workflow file at .github/workflows/pr-check.yml (or any filename) that includes a build-test job triggered on pull requests. The job should run validation appropriate to the project’s stack.

WordPress repos

For WordPress projects, use PHP linting on custom code. This catches syntax errors before they reach production.

name: PR Check on: pull_request: jobs: build-test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up PHP uses: shivammathur/setup-php@v2 with: php-version: "8.2" - name: Lint PHP files in custom code run: | errors=0 total=0 files=() for dir in wp-content/themes wp-content/mu-plugins; do if [ -d "$dir" ]; then while IFS= read -r file; do files+=("$file") done < <(find "$dir" -name '*.php' \ -not -path '*/vendor/*' \ -not -path '*/node_modules/*') fi done total=${#files[@]} if [ "$total" -eq 0 ]; then echo "No PHP files found to lint." exit 0 fi for file in "${files[@]}"; do output=$(php -l "$file" 2>&1) || true if echo "$output" | grep -q "No syntax errors"; then echo " pass $file" else errors=$((errors + 1)) echo " FAIL $file" echo "$output" | grep -v "^Errors parsing" | sed 's/^/ /' fi done echo "" echo "$total files linted" if [ "$errors" -gt 0 ]; then echo "$errors failed, $((total - errors)) passed" exit 1 fi echo "0 failed, $total passed"

Adjust php-version to match your project’s hosting environment. The || true on php -l prevents a non-zero exit code (from either a syntax error or a PHP binary crash) from aborting the entire lint step under GitHub Actions’ default bash -e behavior.

Next.js / Node repos

For Node-based projects, run your existing lint and/or test suite under a build-test job:

name: PR Check on: pull_request: jobs: build-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: yarn - run: yarn install --frozen-lockfile - run: yarn lint - run: yarn build

Replace the steps with whatever validation is appropriate — yarn test, next lint, type checking, etc. The only requirement is the job is named build-test.

Repos with multiple CI jobs

If your workflow has multiple jobs that run conditionally (e.g., based on path filters), don’t rename one of them. Instead, add a build-test gate job that depends on all of them and reports a single pass/fail result.

name: CI on: pull_request: jobs: frontend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo "frontend checks here" backend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo "backend checks here" build-test: needs: [frontend, backend] if: always() runs-on: ubuntu-latest steps: - name: Check results run: | results=("${{ needs.frontend.result }}" "${{ needs.backend.result }}") for r in "${results[@]}"; do if [[ "$r" == "failure" || "$r" == "cancelled" ]]; then echo "One or more checks failed" exit 1 fi done

The if: always() ensures the gate job runs even if an upstream job is skipped. Skipped jobs are treated as passing — only failure or cancelled results cause the gate to fail. Add each upstream job to the needs array and results list.

If all upstream jobs are skipped (e.g., no files matched path filters), the gate job will still pass. This is expected — it means the PR didn’t change code that requires validation by those jobs.

What not to do

  • No rubber-stamp CI. A job that always passes with no real validation defeats the purpose. The check must perform meaningful work.
  • Don’t skip the job name. The org-level ruleset specifically requires a check named build-test. A workflow with a differently-named job won’t satisfy the requirement.
  • Don’t use required_status_checks at the repo level. The org-level ruleset handles this. Adding repo-level rules creates confusion about where the requirement is enforced.
Last updated on