Files
Jarek PotiukandShahar Epstein 2a3ee7ffe2 Auto-approve cheap CI runs of external contributors' PRs (#75455)
* Auto-approve cheap CI runs of external contributors' PRs

GitHub holds the workflow runs of fork PRs until a maintainer approves
them. With self-hosted runners (AIP-118) the approval gate becomes part
of the trust model, so it should cover all external contributors, but
approving every push by hand does not scale and makes contributors wait.

Runs whose change cannot touch the CI definition and whose CI is cheap
are safe to start without a maintainer. Expensive or large changes, and
anything that changes how CI or runners are chosen, still get a human
look first, which also keeps the load on the shared public runners down.
The CI-minutes estimate lets maintainers see what a run will cost before
approving it.

Generated-by: Claude Opus 5

* Add inline script metadata to the CI-minutes calibration script

The script uses only the standard library, so with a PEP 723 block it runs
with plain `uv run dev/calibrate_ci_minutes_estimates.py` instead of syncing
the whole Breeze environment. Document that invocation in the script and in
.github/AGENTS.md.

* Keep one PR's API or git error from aborting the approval tick

Each PR is now processed in its own try block. A requests.RequestException
or subprocess.CalledProcessError for one PR no longer stops the remaining
PRs or skips the job summary. The failed PR is recorded with failed=True and
shown as "failed" in the summary, keeping its CI-time estimate when one was
computed and giving a short, single-line form of the error as the reason.
The workflow also tries to add the 'need workflow approval' label to it, so
it is not lost once its runs leave the query window. Nothing is approved on
failure.

approve_workflow_runs exits 1 after writing the summary when any PR failed,
so a persistent failure turns the scheduled run red instead of passing
silently.

* Approve the runs of fork CI pull requests unless they change CI

A pull request whose CI runs in the contributor's fork (AIP-120) still
gets pull_request runs in apache/airflow, and GitHub holds them until a
maintainer approves them. Those runs only execute the fork CI gate, so
judging them by the cost and size of project CI left cheap gate-only
runs waiting for a maintainer for no benefit, and a gated run that never
ran could not be cleaned up by the reconciler.

What still needs a maintainer is a change to the files that define CI,
since it could remove the gate or add a workflow that does run. Using
the reconciler's own list keeps the two decisions consistent, and the
author is told why their runs wait instead of only seeing a label.

Generated-by: Claude Opus 5

* Keep CI-minutes estimates true to the runs they approve

A run selects its tests from the labels the PR had when it started, so
approving it on the current labels could start a full-tests run whose
label was removed while it waited. Calibrating from self-hosted and
all-versions runs, and leaving out the jobs that need no CI image, made
the estimate describe runs other than those it is used to approve.

Generated-by: Claude Opus 5

---------

Co-authored-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com>
2026-10-25 20:14:06 +00:00

2.2 KiB

Table of Contents generated with DocToc

The .github folder — Agent Instructions

Keep the CI-minutes estimates in sync with the workflows

breeze ci approve-workflow-runs (run by workflows/auto-approve-workflow-runs.yml) decides whether to approve an external contributor's CI runs from an estimate of the job-minutes they take. The numbers live in dev/breeze/src/airflow_breeze/utils/ci_minutes_estimate.py and are medians measured on recent Tests (AMD) PR runs on public runners.

After you change the CI workflows in a way that adds, removes, splits or resizes jobs (new test groups, a changed matrix, new composite workflows, a move between runner types), refresh the estimates once the change has run on enough PRs, and in any case about once a month:

  1. Run uv run dev/calibrate_ci_minutes_estimates.py --since <date> from the repository root with an authenticated gh CLI. Pick a date that covers at least a week of runs after the workflow change.
  2. Copy the medians and fits it prints into the constants of ci_minutes_estimate.py, and update the "Last calibrated" line next to them.
  3. When you add a new job group to the workflows, add a matching group to both ci_minutes_estimate.py (with the selective-check output that turns it on) and the JOB_GROUPS patterns of the calibration script. Unmatched jobs fall into the base group.
  4. Run uv run --project dev/breeze pytest dev/breeze/tests/test_ci_minutes_estimate.py dev/breeze/tests/test_workflow_run_approval.py -xvs.

The estimates cover public runners only. Self-hosted (RunsOn) runners need their own set once there is enough data from them.