Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ name: ci-gate
# It runs the project's own `check` script (or `typecheck`) for Bun projects and
# passes with a notice for everything else. Production builds stay with Vercel
# previews because they need per-project environment variables.
#
# A repository whose own ruleset already requires a status check on the default
# branch has its own enforced CI. The gate passes for it with a notice and does
# not install or run anything.

on:
pull_request:
Expand All @@ -22,12 +26,34 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
# A required status check from any active ruleset on the default branch
# counts, except `check`, the name of this job. When the API call fails,
# the gate runs as usual.
- name: Detect own CI
id: own
shell: bash
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
BRANCH: ${{ github.event.repository.default_branch }}
run: |
checks=$(gh api --paginate --slurp "/repos/$REPO/rules/branches/$BRANCH" | jq -r \
'[.[][] | select(.type == "required_status_checks") |
.parameters.required_status_checks[].context | select(. != "check")] |
unique | join(", ")' || true)
if [ -n "$checks" ]; then
echo "::notice::The default branch already requires its own checks ($checks); nothing to gate."
echo "enforced=true" >> "$GITHUB_OUTPUT"
fi

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
if: steps.own.outputs.enforced != 'true'
with:
persist-credentials: false

- name: Detect project
id: detect
if: steps.own.outputs.enforced != 'true'
shell: bash
run: |
if [ ! -f package.json ] || { [ ! -f bun.lock ] && [ ! -f bun.lockb ]; }; then
Expand Down Expand Up @@ -56,6 +82,13 @@ jobs:
with:
bun-version: ${{ steps.detect.outputs.bun-version }}

- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
if: steps.detect.outputs.kind == 'bun'
with:
path: ~/.bun/install/cache
key: ci-gate-bun-${{ runner.os }}-${{ hashFiles('bun.lock', 'bun.lockb') }}
restore-keys: ci-gate-bun-${{ runner.os }}-

- name: Install dependencies
if: steps.detect.outputs.kind == 'bun'
run: bun install --frozen-lockfile
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ and runs the `check` script, or `typecheck` when `check` is absent. It warns whe
Other repositories pass with a notice. Production builds stay with Vercel previews,
which carry each project's environment variables.

A repository with its own CI makes that CI a required status check in its own
ruleset for the default branch. The gate then passes with a notice and installs
and runs nothing. A file in the repository does not count: only a required check
does, so a repository cannot leave the gate without enforced CI. The gate still
starts a job, and GitHub bills each job as at least one minute. To save that
minute too, an owner names the repository in the ruleset's exclusions.

Every change to `ci-gate.yml` changes the gate for the whole organization.

## Dependabot merge policy
Expand Down
Loading