Skip to content
Closed
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
4 changes: 0 additions & 4 deletions .github/workflows/build-grpcio.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ on:
description: 'grpcio version to build (git tag without leading v, e.g. 1.78.0)'
required: true
default: '1.78.0'
pull_request:
paths:
- '.github/workflows/build-grpcio.yml'
- 'patches/grpcio/**'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '1.78.0' }}-${{ github.head_ref || github.run_id }}
Expand Down
71 changes: 62 additions & 9 deletions .github/workflows/pr-trigger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,30 @@ on:
permissions:
contents: read
actions: write
pull-requests: read
checks: write

jobs:
dispatch-triggers:
trigger:
runs-on: ubuntu-latest
if: contains(github.event.pull_request.body, 'Trigger:')
timeout-minutes: 350
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}

- name: Dispatch build/test workflows for Trigger directives
# Every build-*.yml/test-*.yml is workflow_dispatch-only (no pull_request
# trigger of its own), so a Trigger: line is the *only* thing that ever
# starts a build. A dispatched run has no native PR check of its own, so
# each directive gets one posted via the Checks API instead of a relay
# job — a properly named check whose "Details" link goes straight to the
# dispatched run's log.
- name: Dispatch Trigger directives and relay status via the Checks API
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_BODY: ${{ github.event.pull_request.body }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
BASE_REPO: ${{ github.repository }}
run: |
Expand All @@ -43,7 +51,50 @@ jobs:
exit 0
fi
printf '%s\n' "$triggers" | while IFS= read -r line; do
relay() {
local wf="$1" ver="$2" name="$3"
local check_id since run_id url conclusion
check_id=$(gh api "repos/$BASE_REPO/check-runs" -f name="$name" -f head_sha="$HEAD_SHA" \
-f status=queued --jq .id)
since=$(date -u -d '-5 seconds' +%Y-%m-%dT%H:%M:%SZ)
if ! gh workflow run "$wf" --repo "$BASE_REPO" --ref "$HEAD_REF" -f "version=$ver"; then
gh api "repos/$BASE_REPO/check-runs/$check_id" -X PATCH -f status=completed -f conclusion=failure \
-f "output[title]=Dispatch failed" -f "output[summary]=gh workflow run failed for $wf @ $ver" >/dev/null
return
fi
run_id="" url=""
for _ in $(seq 1 30); do
row=$(gh run list --repo "$BASE_REPO" --workflow "$wf" --branch "$HEAD_REF" --limit 5 \
--json databaseId,url,createdAt \
-q "[.[] | select(.createdAt >= \"$since\")] | sort_by(.createdAt) | .[0]")
run_id=$(jq -r '.databaseId // empty' <<< "$row")
url=$(jq -r '.url // empty' <<< "$row")
[ -n "$run_id" ] && break
sleep 5
done
if [ -z "$run_id" ]; then
gh api "repos/$BASE_REPO/check-runs/$check_id" -X PATCH -f status=completed -f conclusion=failure \
-f "output[title]=Run not found" -f "output[summary]=Dispatched $wf @ $ver but couldn't find the run." >/dev/null
return
fi
gh api "repos/$BASE_REPO/check-runs/$check_id" -X PATCH -f status=in_progress -f details_url="$url" >/dev/null
gh run watch "$run_id" --repo "$BASE_REPO" >/dev/null || true
conclusion=$(gh run view "$run_id" --repo "$BASE_REPO" --json conclusion -q .conclusion | tr '[:upper:]' '[:lower:]')
[ -z "$conclusion" ] && conclusion=failure
gh api "repos/$BASE_REPO/check-runs/$check_id" -X PATCH -f status=completed -f conclusion="$conclusion" \
-f details_url="$url" >/dev/null
}
pids=()
while IFS= read -r line; do
[ -z "$line" ] && continue
directive=${line#Trigger:}
directive=${directive# }
package_name=${directive%:*}
Expand All @@ -68,11 +119,13 @@ jobs:
continue
fi
echo "Dispatching build-${package_name}.yml on $HEAD_REF with version=$package_version"
gh workflow run "build-${package_name}.yml" --ref "$HEAD_REF" -f "version=$package_version"
relay "build-${package_name}.yml" "$package_version" "build-${package_name}.yml @ ${package_version}" &
pids+=($!)
if [ -f "$test_wf" ]; then
echo "Dispatching test-${package_name}.yml on $HEAD_REF with version=$package_version"
gh workflow run "test-${package_name}.yml" --ref "$HEAD_REF" -f "version=$package_version"
relay "test-${package_name}.yml" "$package_version" "test-${package_name}.yml @ ${package_version}" &
pids+=($!)
fi
done
done <<< "$triggers"
wait "${pids[@]}"
3 changes: 0 additions & 3 deletions .github/workflows/test-hf-xet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ on:
description: 'hf-xet version to test (git tag without leading v, e.g. 1.6.0)'
required: true
default: '1.6.0'
pull_request:
paths:
- '.github/workflows/test-hf-xet.yml'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '1.6.0' }}-${{ github.head_ref || github.run_id }}
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/test-matplotlib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ on:
description: 'matplotlib version to test (git tag without leading v, e.g. 3.11.1)'
required: true
default: '3.11.1'
pull_request:
paths:
- '.github/workflows/test-matplotlib.yml'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '3.11.1' }}-${{ github.head_ref || github.run_id }}
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/test-pillow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ on:
description: 'pillow version to test (git tag without leading v, e.g. 12.3.0)'
required: true
default: '12.3.0'
pull_request:
paths:
- '.github/workflows/test-pillow.yml'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '12.3.0' }}-${{ github.head_ref || github.run_id }}
Expand Down
29 changes: 18 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,29 @@ name, repo, version, upstream build docs — come from the invoking prompt):
**`.claude/worktrees/<pkg>`** inside this repo (locally ignored via `.git/info/exclude`).
Never put a worktree — or anything else — outside the repository.
2. Add `.github/workflows/build-<pkg>.yml` following the playbook below.
3. Validate locally (gotcha 9), then push to `origin` and open a PR. A build only
starts from a `Trigger: <pkg>:<tag>` line in the **PR description** — one per
version you want built (`Trigger: numpy:v2.5.1`), which `pr-trigger.yml` picks
up. Editing the workflow file alone does not start a build.
3. Validate locally (gotcha 9), then push to `origin` and open a PR with a
`Trigger: <pkg>:<tag>` line in the **PR description** for every version you want
built (`Trigger: numpy:v2.5.1`). `build-<pkg>.yml` is `workflow_dispatch`-only —
it has no `pull_request` trigger of its own, so a `Trigger:` line is the only
thing that ever starts a run; editing the workflow file alone does nothing.
`pr-trigger.yml` parses the directives, dispatches each via `workflow_dispatch`,
and posts one GitHub Check Run per directive through the Checks API — a
properly named, real check on the PR (`build-<pkg>.yml @ <version>`) whose
"Details" link goes straight to the dispatched run, with real
pending/success/failure/cancelled status mirrored via `gh run watch`.
4. Watch CI, triage failures, iterate until every matrix job is green and the
`publish` job dry-runs cleanly.
5. When the wheels build and tests pass, reply to any review threads, then
record reusable, project-agnostic learnings back into this file.

## Anatomy of a build-<pkg>.yml

Standard triggers (copy from an existing workflow):
Standard trigger (copy from an existing workflow) — `workflow_dispatch` only, no
`pull_request` block. A per-package `pull_request: paths` trigger was tried and
dropped: with 40+ package workflows, any PR touching several of their files fired
that many separate (mostly skipped) runs, flooding the Actions list for no benefit
— `pr-trigger.yml`'s Checks-API relay (step 3 above) gives the same visible,
per-directive status without it:

```yaml
on:
Expand All @@ -53,10 +64,6 @@ on:
version: { description: '<pkg> version/tag', required: true, default: '<latest stable>' }
```

`workflow_dispatch` is the only trigger — no `pull_request` trigger. A build only ever starts
via a manual dispatch or a `Trigger: <pkg>:<tag>` line in a PR description, which `pr-trigger.yml`
turns into a `workflow_dispatch` call. Editing/pushing the workflow file itself must not start a build.

UV env vars (`UV_EXTRA_INDEX_URL`, `UV_INDEX_STRATEGY`, `UV_ONLY_BINARY`) are **only** needed
if the workflow has steps that actually invoke `uv` (e.g. an sdist-build job on `ubuntu-latest`
that uses `setup-uv`). For pure cibuildwheel build-from-checkout workflows with no `uv` steps,
Expand Down Expand Up @@ -212,8 +219,8 @@ upload without the docs-PR side effect.

6. **Wire up real testing** — mirror how upstream tests its wheels (gotcha 6).

7. **Validate locally, then push** (gotcha 9). Open a PR, add a `Trigger:
<pkg>:<tag>` line to its description to start CI. Watch, triage, iterate.
7. **Validate locally, then push** (gotcha 9). Open a PR; the `pull_request` path
trigger runs CI. Watch, triage, iterate.

## Gotchas (the "wish I knew from the start" list)

Expand Down
Loading