workflows/bot: allow maintainer merges after committer approval

This allows committers to approve PRs with additional, optional nits
that the author-maintainer can either address or merge immediately
without these changes.

It also allows committers to approve a PR for merge, while still waiting
for other maintainers to give their feedback - they can then merge the
PR directly instead of passing it back to the committer.
This commit is contained in:
Wolfgang Walther
2025-10-12 16:30:50 +02:00
parent 9a637aa7a4
commit ffdc8205e5
2 changed files with 20 additions and 2 deletions

View File

@@ -45,8 +45,9 @@ To ensure security and a focused utility, the bot adheres to specific limitation
- The PR targets one of the [development branches](#branch-classification). - The PR targets one of the [development branches](#branch-classification).
- The PR only touches packages located under `pkgs/by-name/*`. - The PR only touches packages located under `pkgs/by-name/*`.
- The PR is either: - The PR is either:
- authored by a [committer][@NixOS/nixpkgs-committers], - approved by a [committer][@NixOS/nixpkgs-committers].
- backported via label, or - authored by a [committer][@NixOS/nixpkgs-committers].
- backported via label.
- created by [@r-ryantm](https://nix-community.github.io/nixpkgs-update/r-ryantm/). - created by [@r-ryantm](https://nix-community.github.io/nixpkgs-update/r-ryantm/).
- The user attempting to merge is a member of [@NixOS/nixpkgs-maintainers]. - The user attempting to merge is a member of [@NixOS/nixpkgs-maintainers].
- The user attempting to merge is a maintainer of all packages touched by the PR. - The user attempting to merge is a maintainer of all packages touched by the PR.

View File

@@ -2,6 +2,7 @@ const { classify } = require('../supportedBranches.js')
function runChecklist({ function runChecklist({
committers, committers,
events,
files, files,
pull_request, pull_request,
log, log,
@@ -23,11 +24,25 @@ function runChecklist({
.map((pkg) => new Set(maintainers[pkg])) .map((pkg) => new Set(maintainers[pkg]))
.reduce((acc, cur) => acc?.intersection(cur) ?? cur) .reduce((acc, cur) => acc?.intersection(cur) ?? cur)
const approvals = new Set(
events
.filter(
({ event, state, commit_id }) =>
event === 'reviewed' &&
state === 'approved' &&
// Only approvals for the current head SHA count, otherwise authors could push
// bad code between the approval and the merge.
commit_id === pull_request.head.sha,
)
.map(({ user }) => user.id),
)
const checklist = { const checklist = {
'PR targets a [development branch](https://github.com/NixOS/nixpkgs/blob/-/ci/README.md#branch-classification).': 'PR targets a [development branch](https://github.com/NixOS/nixpkgs/blob/-/ci/README.md#branch-classification).':
classify(pull_request.base.ref).type.includes('development'), classify(pull_request.base.ref).type.includes('development'),
'PR touches only packages in `pkgs/by-name/`.': allByName, 'PR touches only packages in `pkgs/by-name/`.': allByName,
'PR is at least one of:': { 'PR is at least one of:': {
'Approved by a committer.': committers.intersection(approvals).size > 0,
'Authored by a committer.': committers.has(pull_request.user.id), 'Authored by a committer.': committers.has(pull_request.user.id),
'Backported via label.': 'Backported via label.':
pull_request.user.login === 'nixpkgs-ci[bot]' && pull_request.user.login === 'nixpkgs-ci[bot]' &&
@@ -246,6 +261,7 @@ async function handleMerge({
const { result, checklist } = runChecklist({ const { result, checklist } = runChecklist({
committers, committers,
events,
files, files,
pull_request, pull_request,
log, log,
@@ -302,6 +318,7 @@ async function handleMerge({
const { result } = runChecklist({ const { result } = runChecklist({
committers, committers,
events,
files, files,
pull_request, pull_request,
log, log,