Skip to content

[v3-4-test] Backport fork CI auto-approval (#75616, #75619, #75455, #75654, #75655) - #75680

Merged
vatsrahul1001 merged 6 commits into
v3-4-testfrom
backport-fork-ci-auto-approve-v3-4-test
Oct 26, 2026
Merged

vatsrahul1001 merged 6 commits into
v3-4-testfrom
backport-fork-ci-auto-approve-v3-4-test

Conversation

@potiuk

@potiuk potiuk commented Oct 26, 2026

Copy link
Copy Markdown
Member

Backports #75654 and #75655 to v3-4-test, together with the three fork-CI changes they build on and that were not yet on the branch: #75616, #75619 and #75455. All five are -x cherry-picks that apply cleanly in this order.

One extra commit fixes test_decide_approval_with_real_selective_checks: it built SelectiveChecks with the checkout's default branch while deciding approval for a PR targeting main. On v3-4-test that skips provider tests, so the large provider change was estimated cheap and approved. The test now pins default_branch="main", as build_selective_checks already does in production.

Not backported to airflow-ctl/v0-1-test or chart/v1-2x-test: neither branch has the fork CI gate these changes modify.

Checks run locally: the fork-CI breeze tests (472 passed) and prek --stage pre-commit over the diff (all passed except lychee, which could not start because Docker was not running locally).


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Opus 5

Generated-by: Claude Opus 5 following the guidelines

🤖 Generated with Claude Code

potiuk and others added 6 commits October 26, 2026 18:02
A gated pull request showed one aggregate fork CI status, so a maintainer
or contributor had to open the fork run to see which jobs were running,
which failed and which passed. Reporting every job as its own check, each
linking to the job in the fork, puts that on the pull request itself,
where project CI shows its jobs.

Generated-by: Claude Opus 5
(cherry picked from commit 2f7a7ea)
…75619)

Merging a pull request does not stop its pull_request runs, so they keep
using the project's GitHub-hosted minutes and self-hosted runners for a
result nobody reads once the change is on its target branch. Until now
maintainers cancelled such runs by hand, when they noticed them.

Generated-by: Claude Opus 5
(cherry picked from commit e5f2c87)
* 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>
(cherry picked from commit 2a3ee7f)
)

When a committer adds "use fork ci" right after a PR opens, the PR's first
runs were created without it, and the workflow-run approver left them for a
maintainer. It had to: the fork CI gate fell back to the labels of the run's
event when it could not read the current ones, and those labels could still
send the run to full project CI on code nobody had reviewed. Anyone able to
exhaust the shared token quota could force that fallback.

The gate now fails when it cannot read the labels, so a run only ever acts on
the PR's current labels and a re-run decides again. With that, runs started
before the label changed are as safe to approve as later ones.

Generated-by: Claude Opus 5
(cherry picked from commit 437daf6)
External contributors' runs wait for the next approver pass before they
start, and GitHub regularly drops scheduled runs under load, which turns the
30-minute wait into an hour or more. A pass takes about a minute, so running
it twice as often costs little and halves the wait.

Generated-by: Claude Opus 5
(cherry picked from commit 54f645d)
The test decides approval for a PR targeting main, but built SelectiveChecks
with the checkout's default branch. On a release branch that skips provider
tests, so the large provider change was estimated cheap and approved.

Generated-by: Claude Opus 5
@vatsrahul1001
vatsrahul1001 enabled auto-merge (squash) October 26, 2026 17:36
@vatsrahul1001
vatsrahul1001 merged commit 1a578ef into v3-4-test Oct 26, 2026
158 checks passed
@vatsrahul1001
vatsrahul1001 deleted the backport-fork-ci-auto-approve-v3-4-test branch October 26, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants