From d75ac7748f2191187be37f64a075868bdb45c18b Mon Sep 17 00:00:00 2001 From: Stas Shevchenko Date: Fri, 4 Sep 2026 12:49:34 +0200 Subject: [PATCH 1/3] Add shared Mergify config --- .mergify.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .mergify.yml diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 0000000..5ad0d9c --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,34 @@ +shared: + ci_passed: &ci_passed + - check-success~=^test / + - -check-pending~=^test / + - -check-failure~=^test / + - check-success=AI Policy Check + +merge_queue: + max_parallel_checks: 1 + +queue_rules: + - name: default + merge_method: rebase + update_method: rebase + queue_conditions: *ci_passed + merge_conditions: *ci_passed + +pull_request_rules: + - name: queue approved pull requests + conditions: + - base~=^(main|master)$ + - "#approved-reviews-by>=1" + - "#changes-requested-reviews-by=0" + - label!=do-not-merge + actions: + queue: + + - name: queue scala-steward updates + conditions: + - base~=^(main|master)$ + - author=scala-steward + - label!=do-not-merge + actions: + queue: From 037ebe60167252151780c3d20c2fd535a86c330c Mon Sep 17 00:00:00 2001 From: Stas Shevchenko Date: Fri, 4 Sep 2026 15:07:41 +0200 Subject: [PATCH 2/3] Document the shared Mergify config --- README.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/README.md b/README.md index f855e34..90817aa 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,69 @@ jobs: modules_ignore: 'docs_2.13 docs_3 foo-it-tests_2.13 foo-it-tests_3' ``` +## Merge queue (Mergify) + +Queues a pull request once it is approved and CI is green, rebases it on the default branch, waits for the +checks to pass again, then merges. Dependency updates opened by `scala-steward` are queued without an +approval. + +### Setup + +The Mergify app has to be installed on the project and on this repository, then create `.mergify.yml`: + +```yaml +extends: scala-github-actions +``` + +That is the whole file. Unlike the workflows above there is no revision to pin, `extends` takes a +repository name and nothing else, so whatever sits in this repository's `.mergify.yml` applies to every +project extending it as soon as it lands here. Undoing a change means another commit here rather than a +bump downstream. + +### Diverging from the shared config + +`pull_request_rules` and `queue_rules` merge by name and the local file wins, so a project can replace or +switch off a single rule and keep the rest: + +```yaml +extends: scala-github-actions + +pull_request_rules: + - name: queue scala-steward updates + disabled: + reason: dependency updates are reviewed by hand here + conditions: [] + actions: + queue: +``` + +The `shared` key is the exception, it does not merge, so a YAML anchor has to live in the same file that +uses it. + +### Implementation notes + +* the CI gate is three conditions rather than a list of check names: + + ```yaml + - check-success~=^test / + - -check-pending~=^test / + - -check-failure~=^test / + ``` + + `~=` is a regex match, and against a list attribute it holds when **any** element matches, so the first + condition on its own is satisfied by a single green check. The two negatives are what turn it into "all + of them". In exchange, bumping Scala versions or renaming a job in `ci.yml` needs no change here. +* `check-success=AI Policy Check` sits in the same list because the org ruleset makes that workflow + required on the default branch. Without it Mergify would attempt merges that GitHub refuses. +* the rules match `base~=^(main|master)$`. Mergify has no attribute for "the default branch", and of the + projects calling the CI workflow 40 are on `master` against 7 on `main`. A project whose default branch + is named anything else has to override the rules locally. The condition also keeps stacked pull requests + out of the queue, where the base is another pull request's head branch and merging early makes a mess. +* `max_parallel_checks: 1`, with `queue_conditions` and `merge_conditions` identical, is what enables + in-place checks. The queue then rebases the real pull request and reruns its CI instead of opening a + temporary draft one, which keeps Codacy, CodeRabbit and the policy check on the pull request people are + looking at. + ## Scala Release workflow (v3, v4, v5) ### Setup From bad965606dfc7dceea408d70f975906cabe3a10c Mon Sep 17 00:00:00 2001 From: Stas Shevchenko Date: Fri, 4 Sep 2026 15:08:44 +0200 Subject: [PATCH 3/3] Trim the Mergify notes --- README.md | 51 ++++++++++++++------------------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 90817aa..ff0ff7c 100644 --- a/README.md +++ b/README.md @@ -175,27 +175,20 @@ jobs: ## Merge queue (Mergify) -Queues a pull request once it is approved and CI is green, rebases it on the default branch, waits for the -checks to pass again, then merges. Dependency updates opened by `scala-steward` are queued without an -approval. +Rebases an approved pull request on the default branch, reruns its CI, then merges it. `scala-steward` +updates are queued without an approval. ### Setup -The Mergify app has to be installed on the project and on this repository, then create `.mergify.yml`: +Install the Mergify app on the project and on this repository, then create `.mergify.yml`: ```yaml extends: scala-github-actions ``` -That is the whole file. Unlike the workflows above there is no revision to pin, `extends` takes a -repository name and nothing else, so whatever sits in this repository's `.mergify.yml` applies to every -project extending it as soon as it lands here. Undoing a change means another commit here rather than a -bump downstream. +There is no revision to pin, so this file is live for every project extending it as soon as it lands here. -### Diverging from the shared config - -`pull_request_rules` and `queue_rules` merge by name and the local file wins, so a project can replace or -switch off a single rule and keep the rest: +To replace or switch off a single rule, redefine it by name, the local file wins: ```yaml extends: scala-github-actions @@ -209,32 +202,16 @@ pull_request_rules: queue: ``` -The `shared` key is the exception, it does not merge, so a YAML anchor has to live in the same file that -uses it. - -### Implementation notes - -* the CI gate is three conditions rather than a list of check names: - - ```yaml - - check-success~=^test / - - -check-pending~=^test / - - -check-failure~=^test / - ``` +### Notes - `~=` is a regex match, and against a list attribute it holds when **any** element matches, so the first - condition on its own is satisfied by a single green check. The two negatives are what turn it into "all - of them". In exchange, bumping Scala versions or renaming a job in `ci.yml` needs no change here. -* `check-success=AI Policy Check` sits in the same list because the org ruleset makes that workflow - required on the default branch. Without it Mergify would attempt merges that GitHub refuses. -* the rules match `base~=^(main|master)$`. Mergify has no attribute for "the default branch", and of the - projects calling the CI workflow 40 are on `master` against 7 on `main`. A project whose default branch - is named anything else has to override the rules locally. The condition also keeps stacked pull requests - out of the queue, where the base is another pull request's head branch and merging early makes a mess. -* `max_parallel_checks: 1`, with `queue_conditions` and `merge_conditions` identical, is what enables - in-place checks. The queue then rebases the real pull request and reruns its CI instead of opening a - temporary draft one, which keeps Codacy, CodeRabbit and the policy check on the pull request people are - looking at. +* `check-success~=^test /` is true as soon as one matching check is green, hence the + `-check-pending~=^test /` and `-check-failure~=^test /` next to it. Bumping Scala versions or renaming + a job needs no change here. +* `AI Policy Check` is required by the org ruleset, so it belongs in the same list. +* there is no attribute for "the default branch", hence `base~=^(main|master)$`. It also keeps stacked + pull requests out of the queue. +* `max_parallel_checks: 1` with identical queue and merge conditions gives in-place checks instead of + temporary draft pull requests. ## Scala Release workflow (v3, v4, v5)