Skip to content
Open
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
43 changes: 43 additions & 0 deletions .github/intentional-ci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Intentional CI development pilot

The `ci:intentional` label opts a PR out of automatic GitHub Actions test jobs,
independently of draft or ready-for-review state. Other PRs retain their current
behavior. Scheduled, branch-push, release, and existing manual runs retain their
current conditions. Skipped workflow entries can still appear in GitHub.

Apply the label before pushing updates. Adding it does not cancel existing runs;
automatic labeling after PR creation can be too late to suppress the first run.
Existing stack branches may need rebasing onto the bootstrap before their
PR workflows contain the opt-out guards. AppVeyor and Read the Docs are separate
services and do not honor this GitHub Actions opt-out.

## Experimental commands

After this bootstrap merges, create `intentional-ci-experiment` in
`pybind/pybind11` from `master`. Implement the worker there, retaining
`.github/workflows/intentional-ci.yml` and its `workflow_dispatch` string input
named `request`. The bootstrap worker only reports that no tests were executed;
it does not implement either test profile or publish a CI result for the PR.

Any PR author is welcome to join the pilot. On their own open PR labeled
`ci:intentional`, they can post:

* `/ci full`
* `/ci quick`
* `/ci help` (usage appears in the listener's Actions job summary)

The listener runs trusted code from `master`, fetches the current PR state, and
sends the PR number, profile, head SHA, base SHA, and requesting comment ID to
the fixed development branch. Each command requests one captured revision.
Draft status and commit messages do not select the profile. A missing worker
branch produces an actionable failure in the listener; no PR tests run.

Keep experimental workflow/check names, concurrency groups, and cache keys
separate from ordinary CI. Test the captured revisions with read-only
permissions and no secrets; keep result publishing in a separate trusted job.
The listener itself never checks out PR code. It accepts requests only from
the PR author; the label is the explicit opt-in to the evolving experiment.

Implementation changes can stay on the development branch while the listener
and ordinary workflows on `master` remain stable. Submit the completed design
and any proposed project-wide rollout together for review.
77 changes: 58 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ jobs:
# versions of default compilers and Python versions in GitHub Actions.
# It is in two parts: one that always runs, and one that runs on non-draft
standard-small:
if: github.event.action != 'ready_for_review'
if: >-
(github.event.action != 'ready_for_review') &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -85,7 +87,9 @@ jobs:
# Build the test suite against the precompiled pybind11 static library; a
# definition missing from the -inl.h split shows up here as a link error.
precompile:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand All @@ -108,7 +112,9 @@ jobs:
cmake-args: -DPYBIND11_TEST_PRECOMPILE=ON

standard-large:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -195,7 +201,9 @@ jobs:

# This checks inplace builds with C++11
inplace:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -271,7 +279,9 @@ jobs:

manylinux:
name: Manylinux on 🐍 ${{ matrix.python-version }} (${{ matrix.container }})
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -305,7 +315,9 @@ jobs:

# Testing on clang using the excellent silkeh clang docker images
clang:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -377,6 +389,7 @@ jobs:

# Testing NVCC; forces sources to behave like .cu files
cuda:
if: (github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
runs-on: ubuntu-latest
name: "🐍 3.10 • CUDA 12.2 • Ubuntu 22.04"
container: nvidia/cuda:12.2.0-devel-ubuntu22.04
Expand Down Expand Up @@ -445,7 +458,9 @@ jobs:

# Testing on Ubuntu + NVHPC (previous PGI) compilers, which seems to require more workarounds
ubuntu-nvhpc:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
runs-on: ubuntu-24.04
name: "🐍 3 • NVHPC 26.5 • C++17 • x64"
timeout-minutes: 90
Expand Down Expand Up @@ -509,7 +524,9 @@ jobs:

# Testing on GCC using the GCC docker images (only recent images supported)
gcc:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -584,7 +601,9 @@ jobs:

# Testing on ICC using the oneAPI apt repo
icc:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
runs-on: ubuntu-22.04
timeout-minutes: 90

Expand Down Expand Up @@ -692,7 +711,9 @@ jobs:

# Testing on CentOS (manylinux uses a centos base).
centos:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand Down Expand Up @@ -759,7 +780,9 @@ jobs:

# This tests an "install" with the CMake tools
install-classic:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
name: "🐍 3.11 • Debian • x86 • Install"
# Ubuntu 26.04's Docker 29.4.2 breaks i386 networking:
# https://github.com/actions/runner-images/issues/14790
Expand Down Expand Up @@ -807,7 +830,9 @@ jobs:
# This verifies that the documentation is not horribly broken, and does a
# basic validation check on the SDist.
doxygen:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
name: "Documentation build test"
runs-on: ubuntu-latest
timeout-minutes: 90
Expand Down Expand Up @@ -843,7 +868,9 @@ jobs:
diff -rq $installed ./pybind11

win32:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -896,7 +923,9 @@ jobs:
run: cmake --build build -t pytest

win32-debug:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -946,7 +975,9 @@ jobs:


windows-2022:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -1011,7 +1042,9 @@ jobs:
run: cmake --build build_partial --target pytest

mingw:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
name: "🐍 3 • windows-latest • ${{ matrix.sys }}"
runs-on: windows-latest
timeout-minutes: 90
Expand Down Expand Up @@ -1123,7 +1156,9 @@ jobs:
run: PYTHONHOME=/${{matrix.sys}} PYTHONPATH=/${{matrix.sys}} cmake --build build3 --target test_cross_module_rtti

windows_clang:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))

strategy:
matrix:
Expand Down Expand Up @@ -1196,7 +1231,9 @@ jobs:

# Clang with MSVC/Windows SDK toolchain + python.org CPython (Windows ARM)
windows_arm_clang_msvc:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))

strategy:
fail-fast: false
Expand Down Expand Up @@ -1264,7 +1301,9 @@ jobs:

# Clang in MSYS2/MinGW-w64 CLANGARM64 toolchain + MSYS2 Python (Windows ARM)
windows_arm_clang_msys2:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))

strategy:
fail-fast: false
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/configure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ jobs:
# This tests various versions of CMake in various combinations, to make sure
# the configure step passes.
cmake:
if: github.event.pull_request.draft == false
if: >-
(github.event.pull_request.draft == false) &&
(github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
strategy:
fail-fast: false
matrix:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ env:

jobs:
pre-commit:
if: (github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
name: Format
runs-on: ubuntu-latest
steps:
Expand All @@ -34,6 +35,7 @@ jobs:
- uses: pre-commit/action@v3.0.1

clang-tidy:
if: (github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
# When making changes here, please also review the "Clang-Tidy" section
# in .github/CONTRIBUTING.md and update as needed.
name: Clang-Tidy
Expand Down
86 changes: 86 additions & 0 deletions .github/workflows/intentional-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Intentional CI experiment

on:
issue_comment:
types: [created]
workflow_dispatch:
inputs:
request:
description: JSON with the PR, profile, head SHA, base SHA, and comment ID
required: true
type: string

permissions: {}

jobs:
dispatch:
if: >-
github.repository == 'pybind/pybind11' &&
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/ci ')
runs-on: ubuntu-latest
permissions:
actions: write
pull-requests: read
steps:
- uses: actions/github-script@v9
with:
script: |
const match = /^\/ci (full|quick|help)$/.exec(context.payload.comment.body.trim());
if (!match) return;

const {data: pr} = await github.rest.pulls.get({
...context.repo,
pull_number: context.issue.number,
});
if (pr.state !== 'open' || pr.user.login !== context.payload.comment.user.login
|| !pr.labels.some(label => label.name === 'ci:intentional')) return;

if (match[1] === 'help') {
await core.summary.addHeading('Intentional CI experiment')
.addRaw('Use `/ci full` or `/ci quick` on a PR labeled `ci:intentional`. '
+ 'PR authors can request runs on their own PRs during this pilot. '
+ 'The development worker must be installed first; see '
+ '`.github/intentional-ci.md`.').write();
return;
}

const request = {
pr: pr.number,
profile: match[1],
head_sha: pr.head.sha,
base_sha: pr.base.sha,
comment_id: context.payload.comment.id,
};
try {
await github.rest.actions.createWorkflowDispatch({
...context.repo,
workflow_id: 'intentional-ci.yml',
ref: 'intentional-ci-experiment',
inputs: {request: JSON.stringify(request)},
});
} catch (error) {
if (error.status !== 404 && error.status !== 422) throw error;
core.setFailed('Cannot dispatch the experimental worker. Create '
+ 'intentional-ci-experiment from master after this bootstrap merges '
+ 'and keep intentional-ci.yml with its workflow_dispatch input. '
+ error.message);
return;
}
await core.summary.addHeading('Experimental CI requested')
.addCodeBlock(JSON.stringify(request, null, 2), 'json').write();

bootstrap:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
env:
REQUEST: ${{ inputs.request }}
with:
script: |
await core.summary.addHeading('Bootstrap only: no tests executed')
.addRaw('Implement the dispatch worker on `intentional-ci-experiment`. '
+ 'This placeholder does not publish a CI result for the PR.')
.addCodeBlock(process.env.REQUEST, 'json').write();
2 changes: 2 additions & 0 deletions .github/workflows/pip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
# This builds the sdists and wheels and makes sure the files are exactly as
# expected.
test-packaging:
if: (github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
name: 🐍 3.9 • 📦 tests • windows-latest
runs-on: windows-latest

Expand All @@ -43,6 +44,7 @@ jobs:
# This runs the packaging tests and also builds and saves the packages as
# artifacts.
packaging:
if: (github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'ci:intentional'))
name: 🐍 3.9 • 📦 & 📦 tests • ubuntu-24.04
runs-on: ubuntu-24.04

Expand Down
Loading
Loading