pr-merge-queue 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +125 -2
- package/dist/claim-pr/claim-pr.d.mts +45 -0
- package/dist/claim-pr/claim-pr.d.mts.map +1 -0
- package/dist/claim-pr/claim-pr.mjs +217 -0
- package/dist/claim-pr/claim-pr.mjs.map +1 -0
- package/dist/claim-pr/index.d.mts +2 -0
- package/dist/claim-pr/index.d.mts.map +1 -0
- package/dist/claim-pr/index.mjs +2 -0
- package/dist/claim-pr/index.mjs.map +1 -0
- package/dist/cmd/claim-pr.d.mts +3 -0
- package/dist/cmd/claim-pr.d.mts.map +1 -0
- package/dist/cmd/claim-pr.mjs +20 -0
- package/dist/cmd/claim-pr.mjs.map +1 -0
- package/dist/cmd/open-pr.d.mts +3 -0
- package/dist/cmd/open-pr.d.mts.map +1 -0
- package/dist/cmd/open-pr.mjs +20 -0
- package/dist/cmd/open-pr.mjs.map +1 -0
- package/dist/cmd/pr-report.d.mts +3 -0
- package/dist/cmd/pr-report.d.mts.map +1 -0
- package/dist/cmd/pr-report.mjs +20 -0
- package/dist/cmd/pr-report.mjs.map +1 -0
- package/dist/cmd/push-fixed-pr.d.mts +3 -0
- package/dist/cmd/push-fixed-pr.d.mts.map +1 -0
- package/dist/cmd/push-fixed-pr.mjs +20 -0
- package/dist/cmd/push-fixed-pr.mjs.map +1 -0
- package/dist/cmd/report-unowned-prs.d.mts +3 -0
- package/dist/cmd/report-unowned-prs.d.mts.map +1 -0
- package/dist/cmd/report-unowned-prs.mjs +20 -0
- package/dist/cmd/report-unowned-prs.mjs.map +1 -0
- package/dist/cmd/unblock-prs.d.mts +3 -0
- package/dist/cmd/unblock-prs.d.mts.map +1 -0
- package/dist/cmd/unblock-prs.mjs +19 -0
- package/dist/cmd/unblock-prs.mjs.map +1 -0
- package/dist/entry-point.d.mts +3 -0
- package/dist/entry-point.d.mts.map +1 -0
- package/dist/entry-point.mjs +3 -0
- package/dist/entry-point.mjs.map +1 -0
- package/dist/lib/cli-args.d.mts +27 -0
- package/dist/lib/cli-args.d.mts.map +1 -0
- package/dist/lib/cli-args.mjs +55 -0
- package/dist/lib/cli-args.mjs.map +1 -0
- package/dist/lib/github-api.d.mts +153 -0
- package/dist/lib/github-api.d.mts.map +1 -0
- package/dist/lib/github-api.mjs +291 -0
- package/dist/lib/github-api.mjs.map +1 -0
- package/dist/lib/index.d.mts +7 -0
- package/dist/lib/index.d.mts.map +1 -0
- package/dist/lib/index.mjs +7 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/json.d.mts +12 -0
- package/dist/lib/json.d.mts.map +1 -0
- package/dist/lib/json.mjs +28 -0
- package/dist/lib/json.mjs.map +1 -0
- package/dist/lib/log.d.mts +10 -0
- package/dist/lib/log.d.mts.map +1 -0
- package/dist/lib/log.mjs +13 -0
- package/dist/lib/log.mjs.map +1 -0
- package/dist/lib/shell.d.mts +18 -0
- package/dist/lib/shell.d.mts.map +1 -0
- package/dist/lib/shell.mjs +42 -0
- package/dist/lib/shell.mjs.map +1 -0
- package/dist/lib/time.d.mts +17 -0
- package/dist/lib/time.d.mts.map +1 -0
- package/dist/lib/time.mjs +35 -0
- package/dist/lib/time.mjs.map +1 -0
- package/dist/open-pr/github.d.mts +72 -0
- package/dist/open-pr/github.d.mts.map +1 -0
- package/dist/open-pr/github.mjs +249 -0
- package/dist/open-pr/github.mjs.map +1 -0
- package/dist/open-pr/index.d.mts +6 -0
- package/dist/open-pr/index.d.mts.map +1 -0
- package/dist/open-pr/index.mjs +6 -0
- package/dist/open-pr/index.mjs.map +1 -0
- package/dist/open-pr/main.d.mts +36 -0
- package/dist/open-pr/main.d.mts.map +1 -0
- package/dist/open-pr/main.mjs +204 -0
- package/dist/open-pr/main.mjs.map +1 -0
- package/dist/open-pr/options.d.mts +20 -0
- package/dist/open-pr/options.d.mts.map +1 -0
- package/dist/open-pr/options.mjs +66 -0
- package/dist/open-pr/options.mjs.map +1 -0
- package/dist/open-pr/steps.d.mts +23 -0
- package/dist/open-pr/steps.d.mts.map +1 -0
- package/dist/open-pr/steps.mjs +38 -0
- package/dist/open-pr/steps.mjs.map +1 -0
- package/dist/open-pr/types.d.mts +179 -0
- package/dist/open-pr/types.d.mts.map +1 -0
- package/dist/open-pr/types.mjs +20 -0
- package/dist/open-pr/types.mjs.map +1 -0
- package/dist/pr-report/github.d.mts +59 -0
- package/dist/pr-report/github.d.mts.map +1 -0
- package/dist/pr-report/github.mjs +561 -0
- package/dist/pr-report/github.mjs.map +1 -0
- package/dist/pr-report/index.d.mts +8 -0
- package/dist/pr-report/index.d.mts.map +1 -0
- package/dist/pr-report/index.mjs +8 -0
- package/dist/pr-report/index.mjs.map +1 -0
- package/dist/pr-report/linked-issues.d.mts +15 -0
- package/dist/pr-report/linked-issues.d.mts.map +1 -0
- package/dist/pr-report/linked-issues.mjs +39 -0
- package/dist/pr-report/linked-issues.mjs.map +1 -0
- package/dist/pr-report/main.d.mts +42 -0
- package/dist/pr-report/main.d.mts.map +1 -0
- package/dist/pr-report/main.mjs +163 -0
- package/dist/pr-report/main.mjs.map +1 -0
- package/dist/pr-report/options.d.mts +36 -0
- package/dist/pr-report/options.d.mts.map +1 -0
- package/dist/pr-report/options.mjs +90 -0
- package/dist/pr-report/options.mjs.map +1 -0
- package/dist/pr-report/queue.d.mts +28 -0
- package/dist/pr-report/queue.d.mts.map +1 -0
- package/dist/pr-report/queue.mjs +74 -0
- package/dist/pr-report/queue.mjs.map +1 -0
- package/dist/pr-report/render.d.mts +14 -0
- package/dist/pr-report/render.d.mts.map +1 -0
- package/dist/pr-report/render.mjs +318 -0
- package/dist/pr-report/render.mjs.map +1 -0
- package/dist/pr-report/repo-settings.d.mts +12 -0
- package/dist/pr-report/repo-settings.d.mts.map +1 -0
- package/dist/pr-report/repo-settings.mjs +22 -0
- package/dist/pr-report/repo-settings.mjs.map +1 -0
- package/dist/push-fixed-pr/index.d.mts +2 -0
- package/dist/push-fixed-pr/index.d.mts.map +1 -0
- package/dist/push-fixed-pr/index.mjs +2 -0
- package/dist/push-fixed-pr/index.mjs.map +1 -0
- package/dist/push-fixed-pr/push-fixed-pr.d.mts +54 -0
- package/dist/push-fixed-pr/push-fixed-pr.d.mts.map +1 -0
- package/dist/push-fixed-pr/push-fixed-pr.mjs +172 -0
- package/dist/push-fixed-pr/push-fixed-pr.mjs.map +1 -0
- package/dist/report-unowned-prs/index.d.mts +2 -0
- package/dist/report-unowned-prs/index.d.mts.map +1 -0
- package/dist/report-unowned-prs/index.mjs +2 -0
- package/dist/report-unowned-prs/index.mjs.map +1 -0
- package/dist/report-unowned-prs/report-unowned-prs.d.mts +49 -0
- package/dist/report-unowned-prs/report-unowned-prs.d.mts.map +1 -0
- package/dist/report-unowned-prs/report-unowned-prs.mjs +127 -0
- package/dist/report-unowned-prs/report-unowned-prs.mjs.map +1 -0
- package/dist/tsconfig.json +1 -0
- package/dist/unblock-prs/auto-fix.d.mts +45 -0
- package/dist/unblock-prs/auto-fix.d.mts.map +1 -0
- package/dist/unblock-prs/auto-fix.mjs +207 -0
- package/dist/unblock-prs/auto-fix.mjs.map +1 -0
- package/dist/unblock-prs/checks.d.mts +307 -0
- package/dist/unblock-prs/checks.d.mts.map +1 -0
- package/dist/unblock-prs/checks.mjs +372 -0
- package/dist/unblock-prs/checks.mjs.map +1 -0
- package/dist/unblock-prs/claims.d.mts +21 -0
- package/dist/unblock-prs/claims.d.mts.map +1 -0
- package/dist/unblock-prs/claims.mjs +23 -0
- package/dist/unblock-prs/claims.mjs.map +1 -0
- package/dist/unblock-prs/config.d.mts +487 -0
- package/dist/unblock-prs/config.d.mts.map +1 -0
- package/dist/unblock-prs/config.mjs +119 -0
- package/dist/unblock-prs/config.mjs.map +1 -0
- package/dist/unblock-prs/constants.d.mts +28 -0
- package/dist/unblock-prs/constants.d.mts.map +1 -0
- package/dist/unblock-prs/constants.mjs +28 -0
- package/dist/unblock-prs/constants.mjs.map +1 -0
- package/dist/unblock-prs/demotions.d.mts +42 -0
- package/dist/unblock-prs/demotions.d.mts.map +1 -0
- package/dist/unblock-prs/demotions.mjs +50 -0
- package/dist/unblock-prs/demotions.mjs.map +1 -0
- package/dist/unblock-prs/github.d.mts +739 -0
- package/dist/unblock-prs/github.d.mts.map +1 -0
- package/dist/unblock-prs/github.mjs +626 -0
- package/dist/unblock-prs/github.mjs.map +1 -0
- package/dist/unblock-prs/index.d.mts +25 -0
- package/dist/unblock-prs/index.d.mts.map +1 -0
- package/dist/unblock-prs/index.mjs +25 -0
- package/dist/unblock-prs/index.mjs.map +1 -0
- package/dist/unblock-prs/labels.d.mts +49 -0
- package/dist/unblock-prs/labels.d.mts.map +1 -0
- package/dist/unblock-prs/labels.mjs +49 -0
- package/dist/unblock-prs/labels.mjs.map +1 -0
- package/dist/unblock-prs/main.d.mts +179 -0
- package/dist/unblock-prs/main.d.mts.map +1 -0
- package/dist/unblock-prs/main.mjs +640 -0
- package/dist/unblock-prs/main.mjs.map +1 -0
- package/dist/unblock-prs/merge-after.d.mts +46 -0
- package/dist/unblock-prs/merge-after.d.mts.map +1 -0
- package/dist/unblock-prs/merge-after.mjs +65 -0
- package/dist/unblock-prs/merge-after.mjs.map +1 -0
- package/dist/unblock-prs/options.d.mts +35 -0
- package/dist/unblock-prs/options.d.mts.map +1 -0
- package/dist/unblock-prs/options.mjs +88 -0
- package/dist/unblock-prs/options.mjs.map +1 -0
- package/dist/unblock-prs/owner.d.mts +32 -0
- package/dist/unblock-prs/owner.d.mts.map +1 -0
- package/dist/unblock-prs/owner.mjs +63 -0
- package/dist/unblock-prs/owner.mjs.map +1 -0
- package/dist/unblock-prs/quiet.d.mts +21 -0
- package/dist/unblock-prs/quiet.d.mts.map +1 -0
- package/dist/unblock-prs/quiet.mjs +42 -0
- package/dist/unblock-prs/quiet.mjs.map +1 -0
- package/dist/unblock-prs/rebase.d.mts +120 -0
- package/dist/unblock-prs/rebase.d.mts.map +1 -0
- package/dist/unblock-prs/rebase.mjs +576 -0
- package/dist/unblock-prs/rebase.mjs.map +1 -0
- package/dist/unblock-prs/release.d.mts +62 -0
- package/dist/unblock-prs/release.d.mts.map +1 -0
- package/dist/unblock-prs/release.mjs +94 -0
- package/dist/unblock-prs/release.mjs.map +1 -0
- package/dist/unblock-prs/set-aside-comment.d.mts +20 -0
- package/dist/unblock-prs/set-aside-comment.d.mts.map +1 -0
- package/dist/unblock-prs/set-aside-comment.mjs +93 -0
- package/dist/unblock-prs/set-aside-comment.mjs.map +1 -0
- package/dist/unblock-prs/set-aside-detail.d.mts +41 -0
- package/dist/unblock-prs/set-aside-detail.d.mts.map +1 -0
- package/dist/unblock-prs/set-aside-detail.mjs +56 -0
- package/dist/unblock-prs/set-aside-detail.mjs.map +1 -0
- package/dist/unblock-prs/skips.d.mts +85 -0
- package/dist/unblock-prs/skips.d.mts.map +1 -0
- package/dist/unblock-prs/skips.mjs +141 -0
- package/dist/unblock-prs/skips.mjs.map +1 -0
- package/dist/unblock-prs/stack.d.mts +98 -0
- package/dist/unblock-prs/stack.d.mts.map +1 -0
- package/dist/unblock-prs/stack.mjs +141 -0
- package/dist/unblock-prs/stack.mjs.map +1 -0
- package/dist/unblock-prs/triage.d.mts +28 -0
- package/dist/unblock-prs/triage.d.mts.map +1 -0
- package/dist/unblock-prs/triage.mjs +396 -0
- package/dist/unblock-prs/triage.mjs.map +1 -0
- package/dist/unblock-prs/types.d.mts +793 -0
- package/dist/unblock-prs/types.d.mts.map +1 -0
- package/dist/unblock-prs/types.mjs +26 -0
- package/dist/unblock-prs/types.mjs.map +1 -0
- package/dist/unblock-prs/util.d.mts +23 -0
- package/dist/unblock-prs/util.d.mts.map +1 -0
- package/dist/unblock-prs/util.mjs +60 -0
- package/dist/unblock-prs/util.mjs.map +1 -0
- package/dist/unblock-prs/version-pr.d.mts +57 -0
- package/dist/unblock-prs/version-pr.d.mts.map +1 -0
- package/dist/unblock-prs/version-pr.mjs +79 -0
- package/dist/unblock-prs/version-pr.mjs.map +1 -0
- package/dist/unblock-prs/watch.d.mts +17 -0
- package/dist/unblock-prs/watch.d.mts.map +1 -0
- package/dist/unblock-prs/watch.mjs +128 -0
- package/dist/unblock-prs/watch.mjs.map +1 -0
- package/package.json +118 -3
- package/src/claim-pr/claim-pr.mts +380 -0
- package/src/claim-pr/claim-pr.test.mts +176 -0
- package/src/claim-pr/index.mts +1 -0
- package/src/cmd/claim-pr.mts +32 -0
- package/src/cmd/open-pr.mts +28 -0
- package/src/cmd/pr-report.mts +28 -0
- package/src/cmd/push-fixed-pr.mts +36 -0
- package/src/cmd/report-unowned-prs.mts +37 -0
- package/src/cmd/unblock-prs.mts +24 -0
- package/src/entry-point.mts +3 -0
- package/src/lib/cli-args.mts +86 -0
- package/src/lib/cli-args.test.mts +92 -0
- package/src/lib/github-api.mts +463 -0
- package/src/lib/github-api.test.mts +40 -0
- package/src/lib/index.mts +6 -0
- package/src/lib/json.mts +43 -0
- package/src/lib/json.test.mts +34 -0
- package/src/lib/log.mts +19 -0
- package/src/lib/log.test.mts +45 -0
- package/src/lib/shell.mts +52 -0
- package/src/lib/time.mts +49 -0
- package/src/open-pr/README.md +237 -0
- package/src/open-pr/github.mts +444 -0
- package/src/open-pr/index.mts +5 -0
- package/src/open-pr/main.mts +327 -0
- package/src/open-pr/options.mts +101 -0
- package/src/open-pr/options.test.mts +67 -0
- package/src/open-pr/steps.mts +57 -0
- package/src/open-pr/steps.test.mts +59 -0
- package/src/open-pr/types.mts +42 -0
- package/src/pr-report/README.md +244 -0
- package/src/pr-report/github.mts +911 -0
- package/src/pr-report/index.mts +7 -0
- package/src/pr-report/linked-issues.mts +51 -0
- package/src/pr-report/linked-issues.test.mts +65 -0
- package/src/pr-report/main.mts +257 -0
- package/src/pr-report/options.mts +140 -0
- package/src/pr-report/queue.mts +125 -0
- package/src/pr-report/render.mts +428 -0
- package/src/pr-report/render.test.mts +379 -0
- package/src/pr-report/repo-settings.mts +34 -0
- package/src/push-fixed-pr/index.mts +1 -0
- package/src/push-fixed-pr/push-fixed-pr.mts +276 -0
- package/src/push-fixed-pr/push-fixed-pr.test.mts +228 -0
- package/src/report-unowned-prs/index.mts +1 -0
- package/src/report-unowned-prs/report-unowned-prs.mts +190 -0
- package/src/report-unowned-prs/report-unowned-prs.test.mts +87 -0
- package/src/unblock-prs/README.md +1616 -0
- package/src/unblock-prs/auto-fix.mts +334 -0
- package/src/unblock-prs/auto-fix.test.mts +159 -0
- package/src/unblock-prs/checks.mts +538 -0
- package/src/unblock-prs/checks.test.mts +507 -0
- package/src/unblock-prs/claims.mts +33 -0
- package/src/unblock-prs/claims.test.mts +64 -0
- package/src/unblock-prs/config.mts +187 -0
- package/src/unblock-prs/config.schema.json +71 -0
- package/src/unblock-prs/config.test.mts +139 -0
- package/src/unblock-prs/constants.mts +33 -0
- package/src/unblock-prs/demotions.mts +73 -0
- package/src/unblock-prs/demotions.test.mts +100 -0
- package/src/unblock-prs/github.mts +1042 -0
- package/src/unblock-prs/github.test.mts +84 -0
- package/src/unblock-prs/index.mts +24 -0
- package/src/unblock-prs/labels.mts +70 -0
- package/src/unblock-prs/main.mts +1051 -0
- package/src/unblock-prs/merge-after.mts +117 -0
- package/src/unblock-prs/merge-after.test.mts +120 -0
- package/src/unblock-prs/options.mts +157 -0
- package/src/unblock-prs/owner.mts +91 -0
- package/src/unblock-prs/owner.test.mts +114 -0
- package/src/unblock-prs/quiet.mts +62 -0
- package/src/unblock-prs/quiet.test.mts +175 -0
- package/src/unblock-prs/rebase.mts +962 -0
- package/src/unblock-prs/release.mts +149 -0
- package/src/unblock-prs/release.test.mts +209 -0
- package/src/unblock-prs/set-aside-comment.mts +143 -0
- package/src/unblock-prs/set-aside-comment.test.mts +148 -0
- package/src/unblock-prs/set-aside-detail.mts +82 -0
- package/src/unblock-prs/set-aside-detail.test.mts +131 -0
- package/src/unblock-prs/skips.mts +215 -0
- package/src/unblock-prs/skips.test.mts +280 -0
- package/src/unblock-prs/stack.mts +220 -0
- package/src/unblock-prs/stack.test.mts +449 -0
- package/src/unblock-prs/triage.mts +669 -0
- package/src/unblock-prs/triage.test.mts +100 -0
- package/src/unblock-prs/types.mts +358 -0
- package/src/unblock-prs/util.mts +78 -0
- package/src/unblock-prs/util.test.mts +26 -0
- package/src/unblock-prs/version-pr.mts +112 -0
- package/src/unblock-prs/version-pr.test.mts +78 -0
- package/src/unblock-prs/watch.mts +219 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stacked pull requests: one whose base is another open pull request's
|
|
3
|
+
* branch rather than the default branch. Which pull request is on which is
|
|
4
|
+
* `pr-report-core`'s `stack.mts`, because the reports draw the same stacks;
|
|
5
|
+
* what this script does about them is decided here.
|
|
6
|
+
*
|
|
7
|
+
* The life of a layer, and what this script does at each point:
|
|
8
|
+
*
|
|
9
|
+
* 1. **Stacked.** Its base is the layer below, so its diff is its own and its
|
|
10
|
+
* turn has not come: it is reported as waiting, and nothing else. It has
|
|
11
|
+
* no auto-merge, and must not: nothing holds a pull request onto an
|
|
12
|
+
* unprotected branch, so armed it would land in the layer below rather
|
|
13
|
+
* than on the default branch. Nothing arms it — `open-pr` arms nothing,
|
|
14
|
+
* and this script arms a pull request only when it picks it
|
|
15
|
+
* (`armOnPick` in `rebase.mts`), which a stacked one never is.
|
|
16
|
+
* 2. **The layer below moves.** When this script rebases a pull request, it
|
|
17
|
+
* replays every layer stacked on it onto the new head with
|
|
18
|
+
* `git rebase --onto <new head> <old head>`, which carries exactly the
|
|
19
|
+
* layer's own commits. Otherwise each layer would show the old commits of
|
|
20
|
+
* the one below in its diff, and GitHub's own rebase, when that one
|
|
21
|
+
* merges, would start from a head the layer does not contain.
|
|
22
|
+
* 3. **The layer below merges.** GitHub moves this one onto the default
|
|
23
|
+
* branch. From then on it is an ordinary pull request, picked and armed
|
|
24
|
+
* in its turn like any other, save one thing: it still carries the merged
|
|
25
|
+
* layer's commits, so its diff shows that layer's changes as its own. The
|
|
26
|
+
* next survey rebases them off with `--onto`, from the head that layer
|
|
27
|
+
* merged at to its squash commit, and carries the layers above along —
|
|
28
|
+
* without waiting for it to be queued, because that is an undoing of
|
|
29
|
+
* GitHub's move, not a turn: it adds nothing from the base, and needs no
|
|
30
|
+
* review to have finished. The ruleset merges a branch only when it is up
|
|
31
|
+
* to date and only by squash, so that commit's tree is the merged head's,
|
|
32
|
+
* and the rebased layer's tree is the one it had: only its history, and
|
|
33
|
+
* so its diff, changes. A queued layer is left to its own rebase when it
|
|
34
|
+
* is picked, which drops the same commits the same way on its way onto
|
|
35
|
+
* the tip.
|
|
36
|
+
*
|
|
37
|
+
* A stack here is made by the base alone. GitHub's native stacks are not
|
|
38
|
+
* landed: GitHub refuses auto-merge on a pull request in one ("Auto-merge is
|
|
39
|
+
* not supported for stacked pull requests"), and keeps a layer in its stack
|
|
40
|
+
* after the one below has merged and it has been moved onto the default
|
|
41
|
+
* branch — so one is reported rather than picked, and merged by hand.
|
|
42
|
+
*/
|
|
43
|
+
import { type NativeStackEntry, type QueueOwner } from 'pr-report-core';
|
|
44
|
+
import type { BaseChange, BranchOf, Classification, PullRequest, RetargetedLayer, StackedOn, TriageContext } from './types.mjs';
|
|
45
|
+
/**
|
|
46
|
+
* The branch the pull request was stacked on, if the last change of its base
|
|
47
|
+
* moved it off that branch and onto the default one.
|
|
48
|
+
*/
|
|
49
|
+
export declare const retargetedFrom: (changes: readonly BaseChange[], defaultBranch: string) => string | undefined;
|
|
50
|
+
/** What to report for a stacked pull request in place of anything else. */
|
|
51
|
+
export declare const stackedNote: (pr: PullRequest, parent: number, context: TriageContext) => Classification;
|
|
52
|
+
/**
|
|
53
|
+
* What to report instead of picking a pull request in one of GitHub's native
|
|
54
|
+
* stacks, which GitHub will not let this script arm.
|
|
55
|
+
*/
|
|
56
|
+
export declare const nativeStackNote: (pr: PullRequest, entry: NativeStackEntry) => Classification;
|
|
57
|
+
/**
|
|
58
|
+
* Why a layer cannot be carried along when the one below it moves, or
|
|
59
|
+
* `undefined` when it can. A fork's branch is not this repository's to push
|
|
60
|
+
* to, whatever its name.
|
|
61
|
+
*/
|
|
62
|
+
export declare const restackable: (pr: BranchOf) => string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* The pull requests this script rebases onto the default branch ahead of any
|
|
65
|
+
* turn: the bottom layer of a stack, or a lone pull request, that asked for it
|
|
66
|
+
* (`wantsAutoRebase`) and is paused by `skip-ci`, so the push costs no
|
|
67
|
+
* matrix. Whether it is actually behind is for the caller to ask
|
|
68
|
+
* git: `skip-ci` leaves the merge state at `BLOCKED` whatever the branch is.
|
|
69
|
+
* The version pull request is the release workflow's. Only the worker's own
|
|
70
|
+
* are moved (`owner.mts`): one set aside or claimed is a skill's or a
|
|
71
|
+
* person's until its comment is resolved or the claim ends.
|
|
72
|
+
*/
|
|
73
|
+
export declare const autoRebaseTargets: (pullRequests: readonly PullRequest[], defaultBranch: string, { owners, }: Readonly<{
|
|
74
|
+
/** Who moves each queued pull request next (`owner.mts`). */
|
|
75
|
+
owners: ReadonlyMap<number, QueueOwner>;
|
|
76
|
+
}>) => readonly PullRequest[];
|
|
77
|
+
/** Which open pull request each stacked one is on: child → parent. */
|
|
78
|
+
export declare const stackParentsOf: (pullRequests: readonly PullRequest[], defaultBranch: string) => ReadonlyMap<number, number>;
|
|
79
|
+
/**
|
|
80
|
+
* What to remember of this survey's stacks for the next one: every layer, by
|
|
81
|
+
* the branch it is on, and every layer remembered before that is still on
|
|
82
|
+
* that branch. The second is a layer whose parent has merged while GitHub
|
|
83
|
+
* has yet to move it — no open pull request heads its base any longer, so
|
|
84
|
+
* the bases alone no longer say it is a layer, but it has still to come off
|
|
85
|
+
* one.
|
|
86
|
+
*/
|
|
87
|
+
export declare const stackedOnAfter: (before: StackedOn | undefined, pullRequests: readonly PullRequest[], stackParents: ReadonlyMap<number, number>) => StackedOn;
|
|
88
|
+
/**
|
|
89
|
+
* The pull requests the last survey saw stacked and this one sees on the
|
|
90
|
+
* default branch — before the first survey, every pull request on the
|
|
91
|
+
* default branch, whose timeline then says whether it came off a stack.
|
|
92
|
+
*
|
|
93
|
+
* A queued one is not among them: its own rebase, when it is picked, drops
|
|
94
|
+
* the merged layer's commits on its way onto the tip. Nor is anything that
|
|
95
|
+
* cannot be pushed to, or the version pull request, which was never a layer.
|
|
96
|
+
*/
|
|
97
|
+
export declare const retargetedLayers: (before: StackedOn | undefined, pullRequests: readonly PullRequest[], defaultBranch: string) => readonly RetargetedLayer[];
|
|
98
|
+
//# sourceMappingURL=stack.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack.d.mts","sourceRoot":"","sources":["../../src/unblock-prs/stack.mts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EACV,UAAU,EACV,QAAQ,EACR,cAAc,EACd,WAAW,EACX,eAAe,EACf,SAAS,EACT,aAAa,EACd,MAAM,aAAa,CAAC;AAGrB;;;GAGG;AACH,eAAO,MAAM,cAAc,YAChB,SAAS,UAAU,EAAE,iBACf,MAAM,KACpB,MAAM,GAAG,SAMX,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,WAAW,OAClB,WAAW,UACP,MAAM,WACL,aAAa,KACrB,cAQU,CAAC;AAEd;;;GAGG;AACH,eAAO,MAAM,eAAe,OACtB,WAAW,SACR,gBAAgB,KACtB,cAIU,CAAC;AAEd;;;;GAIG;AACH,eAAO,MAAM,WAAW,OAAQ,QAAQ,KAAG,MAAM,GAAG,SAOjC,CAAC;AAEpB;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,iBACd,SAAS,WAAW,EAAE,iBACrB,MAAM,eAGlB,QAAQ,CAAC;IACV,6DAA6D;IAC7D,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACzC,CAAC,KACD,SAAS,WAAW,EAUpB,CAAC;AAEJ,sEAAsE;AACtE,eAAO,MAAM,cAAc,iBACX,SAAS,WAAW,EAAE,iBACrB,MAAM,KACpB,WAAW,CAAC,MAAM,EAAE,MAAM,CAS1B,CAAC;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WACjB,SAAS,GAAG,SAAS,gBACf,SAAS,WAAW,EAAE,gBACtB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KACxC,SASA,CAAC;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,WACnB,SAAS,GAAG,SAAS,gBACf,SAAS,WAAW,EAAE,iBACrB,MAAM,KACpB,SAAS,eAAe,EAiBrB,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
import { findStackParents, isSafeRefName, } from 'pr-report-core';
|
|
45
|
+
import { isMergeQueued, isSkipCiLabelled, wantsAutoRebase } from './labels.mjs';
|
|
46
|
+
import { isVersionPullRequest } from './version-pr.mjs';
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
export const retargetedFrom = (changes, defaultBranch) => {
|
|
52
|
+
const last = changes.at(-1);
|
|
53
|
+
return last?.to === defaultBranch && last.from !== defaultBranch
|
|
54
|
+
? last.from
|
|
55
|
+
: undefined;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const stackedNote = (pr, parent, context) => ({
|
|
59
|
+
kind: 'note',
|
|
60
|
+
note: `#${pr.number}: stacked on #${parent}, which merges first${context.cyclic.has(pr.number)
|
|
61
|
+
? ' — and on a cycle of stacks and Merge-After, so nothing here will move it'
|
|
62
|
+
: ''}`,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
export const nativeStackNote = (pr, entry) => ({
|
|
69
|
+
kind: 'note',
|
|
70
|
+
note: `#${pr.number}: layer ${entry.position} of ${entry.size} of GitHub's native stack #${entry.stack}, on which GitHub refuses auto-merge; merge it by hand (a stack made by the base alone needs no native stack)`,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
export const restackable = (pr) => pr.state !== 'OPEN'
|
|
78
|
+
? `it is ${pr.state}`
|
|
79
|
+
: pr.isCrossRepository
|
|
80
|
+
? 'its branch is in a fork'
|
|
81
|
+
: !isSafeRefName(pr.headRefName)
|
|
82
|
+
? `branch name ${JSON.stringify(pr.headRefName)} will not be passed to a shell`
|
|
83
|
+
: undefined;
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
export const autoRebaseTargets = (pullRequests, defaultBranch, { owners, }) => pullRequests.filter((pr) => pr.baseRefName === defaultBranch &&
|
|
95
|
+
!pr.isDraft &&
|
|
96
|
+
wantsAutoRebase(pr) &&
|
|
97
|
+
isSkipCiLabelled(pr) &&
|
|
98
|
+
!isVersionPullRequest(pr, defaultBranch) &&
|
|
99
|
+
restackable(pr) === undefined &&
|
|
100
|
+
owners.get(pr.number)?.owner === 'worker');
|
|
101
|
+
|
|
102
|
+
export const stackParentsOf = (pullRequests, defaultBranch) => findStackParents(pullRequests.map((pr) => ({
|
|
103
|
+
number: pr.number,
|
|
104
|
+
headRef: pr.headRefName,
|
|
105
|
+
baseRef: pr.baseRefName,
|
|
106
|
+
fromFork: pr.isCrossRepository,
|
|
107
|
+
})), defaultBranch);
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
export const stackedOnAfter = (before, pullRequests, stackParents) => new Map(pullRequests
|
|
117
|
+
.filter((pr) => stackParents.has(pr.number) ||
|
|
118
|
+
before?.get(pr.number) === pr.baseRefName)
|
|
119
|
+
.map((pr) => [pr.number, pr.baseRefName]));
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
export const retargetedLayers = (before, pullRequests, defaultBranch) => pullRequests
|
|
130
|
+
.filter((pr) => pr.baseRefName === defaultBranch &&
|
|
131
|
+
!isMergeQueued(pr) &&
|
|
132
|
+
!isVersionPullRequest(pr, defaultBranch) &&
|
|
133
|
+
restackable(pr) === undefined)
|
|
134
|
+
.flatMap((pr) => {
|
|
135
|
+
if (before === undefined) {
|
|
136
|
+
return [{ pr, from: undefined }];
|
|
137
|
+
}
|
|
138
|
+
const from = before.get(pr.number);
|
|
139
|
+
return from === undefined ? [] : [{ pr, from }];
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=stack.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack.mjs","sourceRoot":"","sources":["../../src/unblock-prs/stack.mts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** What one survey says about each pull request, and why. */
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
3
|
+
import type { StrictPick } from 'ts-type-forge';
|
|
4
|
+
import { type ApiContext } from '../lib/index.mjs';
|
|
5
|
+
import type { Demotions, PullRequest, Survey, Triage, TriageBase } from './types.mjs';
|
|
6
|
+
/**
|
|
7
|
+
* Lists the open pull requests, re-listing a few times while GitHub is still
|
|
8
|
+
* computing a merge state (`UNKNOWN`) for one that matters.
|
|
9
|
+
*/
|
|
10
|
+
export declare const survey: (api: ApiContext, defaultBranch: string) => Promise<Result<Survey, string>>;
|
|
11
|
+
export declare const triage: (api: ApiContext, pullRequests: readonly PullRequest[], base: TriageBase) => Promise<Triage>;
|
|
12
|
+
/**
|
|
13
|
+
* The cycle's order: `pr-report-core`'s `orderCandidates`, which says why,
|
|
14
|
+
* with what this run has demoted (`demotions.mts`).
|
|
15
|
+
*/
|
|
16
|
+
export declare const orderCandidates: (candidates: readonly PullRequest[], context: Readonly<{
|
|
17
|
+
defaultBranch: string;
|
|
18
|
+
demoted: Demotions;
|
|
19
|
+
}>) => readonly PullRequest[];
|
|
20
|
+
export declare const reportTriage: (triaged: Triage, total: number, context: Readonly<{
|
|
21
|
+
defaultBranch: string;
|
|
22
|
+
demoted: Demotions;
|
|
23
|
+
}>) => void;
|
|
24
|
+
/** What this cycle is about to do to a pull request, as a phrase. */
|
|
25
|
+
export declare const describeAction: (pr: PullRequest, defaultBranch: string, triaged: StrictPick<Triage, 'bypass' | 'stackParents' | 'toArm'>) => string;
|
|
26
|
+
/** What is done instead of arming one only a bypass merges, as a phrase. */
|
|
27
|
+
export declare const bypassPhrase: (reason: string | undefined) => string;
|
|
28
|
+
//# sourceMappingURL=triage.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.d.mts","sourceRoot":"","sources":["../../src/unblock-prs/triage.mts"],"names":[],"mappings":"AAAA,6DAA6D;AAsB7D,OAAO,EAAiB,MAAM,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAmBxE,OAAO,KAAK,EAGV,SAAS,EACT,WAAW,EACX,MAAM,EACN,MAAM,EACN,UAAU,EAEX,MAAM,aAAa,CAAC;AASrB;;;GAGG;AACH,eAAO,MAAM,MAAM,QACZ,UAAU,iBACA,MAAM,KACpB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA8ChC,CAAC;AAoCF,eAAO,MAAM,MAAM,QACZ,UAAU,gBACD,SAAS,WAAW,EAAE,QAC9B,UAAU,KACf,OAAO,CAAC,MAAM,CAsIhB,CAAC;AA8QF;;;GAGG;AACH,eAAO,MAAM,eAAe,eACd,SAAS,WAAW,EAAE,WACzB,QAAQ,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,CAAC,KAC/D,SAAS,WAAW,EAInB,CAAC;AAEL,eAAO,MAAM,YAAY,YACd,MAAM,SACR,MAAM,WACJ,QAAQ,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,SAAS,CAAA;CAAE,CAAC,KAC/D,IA4CF,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,cAAc,OACrB,WAAW,iBACA,MAAM,WACZ,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAC,KAC/D,MAmBF,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,YAAY,WAAY,MAAM,GAAG,SAAS,KAAG,MAGuB,CAAC"}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
|
|
2
|
+
import { asksReview, MERGE_QUEUED_LABEL, orderCandidates as orderQueueCandidates, parseCodeOwners, PRIORITY_HIGH_LABEL, PRIORITY_LOW_LABEL, queueGraph, queueStanding, reviewHold, SKIP_CI_LABEL, stackDescendants, withReviewHold, } from 'pr-report-core';
|
|
3
|
+
import { Arr, isRecord, Result } from 'ts-data-forge';
|
|
4
|
+
import { currentEpochMs, log } from '../lib/index.mjs';
|
|
5
|
+
import { listRequiredChecks, listRunningChecks, summarizeChecks, } from './checks.mjs';
|
|
6
|
+
import { UNKNOWN_STATE_RETRIES, UNKNOWN_STATE_RETRY_MS } from './constants.mjs';
|
|
7
|
+
import { isDemoted } from './demotions.mjs';
|
|
8
|
+
import { listPullRequests, readBranchRules, readNativeStack, readReviewStates, remoteSha, } from './github.mjs';
|
|
9
|
+
import { isSkipCiLabelled, priorityOf } from './labels.mjs';
|
|
10
|
+
import { waitingOnNote } from './merge-after.mjs';
|
|
11
|
+
import { ownerNote, ownerOf } from './owner.mjs';
|
|
12
|
+
import { nativeStackNote, stackedNote } from './stack.mjs';
|
|
13
|
+
import { lastLines, pause, stopRequested } from './util.mjs';
|
|
14
|
+
import { isRebuiltOnBaseTip, isVersionPullRequest, releaseBlockedNote, releaseStaleNote, } from './version-pr.mjs';
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export const survey = async (api, defaultBranch) => {
|
|
20
|
+
let mut_attempt = 0;
|
|
21
|
+
let mut_listed = await listPullRequests(api);
|
|
22
|
+
while (Result.isOk(mut_listed) &&
|
|
23
|
+
mut_attempt < UNKNOWN_STATE_RETRIES &&
|
|
24
|
+
mut_listed.value.some((pr) => pr.mergeStateStatus === 'UNKNOWN' && isRecord(pr.autoMergeRequest)) &&
|
|
25
|
+
!stopRequested()) {
|
|
26
|
+
mut_attempt += 1;
|
|
27
|
+
log(`GitHub is still computing a merge state; re-listing (${mut_attempt}/${UNKNOWN_STATE_RETRIES}).`);
|
|
28
|
+
await pause(UNKNOWN_STATE_RETRY_MS);
|
|
29
|
+
mut_listed = await listPullRequests(api);
|
|
30
|
+
}
|
|
31
|
+
if (Result.isErr(mut_listed)) {
|
|
32
|
+
return mut_listed;
|
|
33
|
+
}
|
|
34
|
+
const baseSha = await remoteSha(defaultBranch);
|
|
35
|
+
if (Result.isErr(baseSha)) {
|
|
36
|
+
return baseSha;
|
|
37
|
+
}
|
|
38
|
+
const rules = await readRules(api, defaultBranch);
|
|
39
|
+
return Result.ok({
|
|
40
|
+
pullRequests: mut_listed.value,
|
|
41
|
+
baseSha: baseSha.value,
|
|
42
|
+
requiredContexts: rules.requiredContexts,
|
|
43
|
+
reviewRequirements: {
|
|
44
|
+
requireCodeOwnerReview: rules.requireCodeOwnerReview,
|
|
45
|
+
requireConversationResolution: rules.requireConversationResolution,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
const readRules = async (api, branch) => {
|
|
63
|
+
const rules = await readBranchRules(api, branch);
|
|
64
|
+
if (Result.isErr(rules)) {
|
|
65
|
+
log(`Cannot read the rules for ${branch}; judging by the checks that have reported, and holding nothing for review. (${lastLines(rules.value, 2)})`);
|
|
66
|
+
return {
|
|
67
|
+
requiredContexts: [],
|
|
68
|
+
requireCodeOwnerReview: false,
|
|
69
|
+
requireConversationResolution: false,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return rules.value;
|
|
73
|
+
};
|
|
74
|
+
export const triage = async (api, pullRequests, base) => {
|
|
75
|
+
const sorted = pullRequests.toSorted((a, b) => a.number - b.number);
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
const graph = queueGraph(sorted.map((pr) => ({
|
|
79
|
+
number: pr.number,
|
|
80
|
+
body: pr.body,
|
|
81
|
+
isDraft: pr.isDraft,
|
|
82
|
+
labels: pr.labels.map(({ name }) => name),
|
|
83
|
+
headRef: pr.headRefName,
|
|
84
|
+
baseRef: pr.baseRefName,
|
|
85
|
+
fromFork: pr.isCrossRepository,
|
|
86
|
+
closes: base.issueOrder.closes.get(pr.number) ?? [],
|
|
87
|
+
})), base.defaultBranch, base.issueOrder.startAfter);
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
const nowEpochMs = currentEpochMs();
|
|
91
|
+
const owners = new Map(Arr.generate(function* () {
|
|
92
|
+
for (const pr of sorted) {
|
|
93
|
+
const owner = ownerOf(pr, {
|
|
94
|
+
defaultBranch: base.defaultBranch,
|
|
95
|
+
skipped: base.skipped,
|
|
96
|
+
claimed: base.claimed,
|
|
97
|
+
stackParents: graph.stackParents,
|
|
98
|
+
cyclic: graph.cyclic,
|
|
99
|
+
nowEpochMs,
|
|
100
|
+
});
|
|
101
|
+
if (owner !== undefined) {
|
|
102
|
+
yield [pr.number, owner];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
const context = { ...base, ...graph, owners };
|
|
107
|
+
const beforeReview = await Promise.all(sorted.map(async (pr) => ({ pr, ...(await settle(api, pr, context)) })));
|
|
108
|
+
const holds = await readReviewHolds(api, beforeReview.filter(({ pr, standing }) => asksReview(standing, pr.mergeStateStatus)), context);
|
|
109
|
+
const classified = beforeReview.map(({ pr, standing, unread, summary }) => ({
|
|
110
|
+
pr,
|
|
111
|
+
result: unread ??
|
|
112
|
+
classification(pr, withReviewHold(standing, pr.mergeStateStatus, holds.get(pr.number)), summary, context),
|
|
113
|
+
}));
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
const bypass = new Map(Arr.generate(function* () {
|
|
117
|
+
for (const [prNumber, hold] of Array.from(holds)) {
|
|
118
|
+
if (hold.kind === 'bypass') {
|
|
119
|
+
yield [prNumber, hold.reason];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}));
|
|
123
|
+
return {
|
|
124
|
+
cycles: graph.cycles,
|
|
125
|
+
owners,
|
|
126
|
+
inScope: classified.filter(({ result }) => result.kind !== 'ignore').length,
|
|
127
|
+
candidates: orderCandidates(classified
|
|
128
|
+
.filter(({ result }) => result.kind === 'candidate')
|
|
129
|
+
.map(({ pr }) => pr), base),
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
toArm: new Set(Arr.generate(function* () {
|
|
134
|
+
for (const { pr, result } of classified) {
|
|
135
|
+
if ((result.kind === 'candidate' || result.kind === 'in-flight') &&
|
|
136
|
+
!isRecord(pr.autoMergeRequest) &&
|
|
137
|
+
!bypass.has(pr.number)) {
|
|
138
|
+
yield pr.number;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
})),
|
|
142
|
+
bypass,
|
|
143
|
+
stackParents: graph.stackParents,
|
|
144
|
+
inFlight: classified
|
|
145
|
+
.filter(({ result }) => result.kind === 'in-flight')
|
|
146
|
+
.map(({ pr }) => pr),
|
|
147
|
+
held: Arr.generate(function* () {
|
|
148
|
+
for (const { pr, result } of classified) {
|
|
149
|
+
if (result.kind === 'held') {
|
|
150
|
+
yield `#${pr.number}: held by its review — ${result.reason}; nothing is run until that changes`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}),
|
|
154
|
+
failing: Arr.generate(function* () {
|
|
155
|
+
for (const { pr, result } of classified) {
|
|
156
|
+
if (result.kind === 'failing') {
|
|
157
|
+
yield { pr, summary: result.summary };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}),
|
|
161
|
+
notes: Arr.generate(function* () {
|
|
162
|
+
for (const { result } of classified) {
|
|
163
|
+
if (result.kind === 'note') {
|
|
164
|
+
yield result.note;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}),
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const factsOf = (pr) => ({
|
|
172
|
+
number: pr.number,
|
|
173
|
+
state: pr.state,
|
|
174
|
+
labels: pr.labels.map(({ name }) => name),
|
|
175
|
+
isDraft: pr.isDraft,
|
|
176
|
+
headRef: pr.headRefName,
|
|
177
|
+
baseRef: pr.baseRefName,
|
|
178
|
+
mergeState: pr.mergeStateStatus,
|
|
179
|
+
autoMerge: isRecord(pr.autoMergeRequest),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
const settle = async (api, pr, context, reads = {}, summary) => {
|
|
186
|
+
const standing = queueStanding(factsOf(pr), context, reads);
|
|
187
|
+
if (standing.kind !== 'needs') {
|
|
188
|
+
return { standing, unread: undefined, summary };
|
|
189
|
+
}
|
|
190
|
+
switch (standing.read) {
|
|
191
|
+
case 'nativeStack':
|
|
192
|
+
return settle(api, pr, context, { ...reads, nativeStack: (await inNativeStack(api, pr)) ?? 'none' }, summary);
|
|
193
|
+
case 'rebuiltOnTip': {
|
|
194
|
+
const rebuilt = await isRebuiltOnBaseTip(pr, context);
|
|
195
|
+
return Result.isErr(rebuilt)
|
|
196
|
+
? { standing, unread: rebuilt.value, summary }
|
|
197
|
+
: settle(api, pr, context, { ...reads, rebuiltOnTip: rebuilt.value }, summary);
|
|
198
|
+
}
|
|
199
|
+
case 'checksFailed': {
|
|
200
|
+
const checks = await readChecks(api, pr, context);
|
|
201
|
+
return Result.isErr(checks)
|
|
202
|
+
? { standing, unread: checks.value, summary }
|
|
203
|
+
: settle(api, pr, context, { ...reads, checksFailed: checks.value.verdict === 'failing' }, checks.value);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const classification = (pr, standing, summary, context) => {
|
|
209
|
+
switch (standing.kind) {
|
|
210
|
+
case 'ignore':
|
|
211
|
+
case 'candidate':
|
|
212
|
+
case 'in-flight':
|
|
213
|
+
return { kind: standing.kind };
|
|
214
|
+
case 'held':
|
|
215
|
+
return { kind: 'held', reason: standing.reason };
|
|
216
|
+
case 'unactionable':
|
|
217
|
+
return { kind: 'note', note: `#${pr.number}: ${standing.reason}` };
|
|
218
|
+
case 'owned':
|
|
219
|
+
return (ownerNote(pr, standing.owner, context.skipped) ?? {
|
|
220
|
+
kind: 'note',
|
|
221
|
+
note: `#${pr.number}: ${standing.owner.reason}`,
|
|
222
|
+
});
|
|
223
|
+
case 'stacked':
|
|
224
|
+
return stackedNote(pr, standing.on, context);
|
|
225
|
+
case 'native-stack':
|
|
226
|
+
return nativeStackNote(pr, standing.entry);
|
|
227
|
+
case 'waiting':
|
|
228
|
+
return waitingOnNote(pr, standing.on, standing.cyclic, context.inherited.get(pr.number));
|
|
229
|
+
case 'release-blocked':
|
|
230
|
+
return releaseBlockedNote(pr, standing.by);
|
|
231
|
+
case 'release-stale':
|
|
232
|
+
return releaseStaleNote(pr, context);
|
|
233
|
+
case 'merge-state':
|
|
234
|
+
return {
|
|
235
|
+
kind: 'note',
|
|
236
|
+
note: `#${pr.number}: merge state ${standing.state}`,
|
|
237
|
+
};
|
|
238
|
+
case 'failing':
|
|
239
|
+
return summary === undefined
|
|
240
|
+
? { kind: 'note', note: `#${pr.number}: failing` }
|
|
241
|
+
: { kind: 'failing', summary };
|
|
242
|
+
case 'needs':
|
|
243
|
+
return {
|
|
244
|
+
kind: 'note',
|
|
245
|
+
note: `#${pr.number}: could not read ${standing.read}`,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
const inNativeStack = async (api, pr) => {
|
|
255
|
+
const entry = await readNativeStack(api, pr.number);
|
|
256
|
+
if (Result.isErr(entry)) {
|
|
257
|
+
log(`#${pr.number}: cannot read whether it is in a native stack; treating it as in none. (${lastLines(entry.value, 2)})`);
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
return entry.value;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
const readReviewHolds = async (api, entries, context) => {
|
|
269
|
+
const { requireCodeOwnerReview, requireConversationResolution } = context.reviewRequirements;
|
|
270
|
+
if (!Arr.isNonEmpty(entries) ||
|
|
271
|
+
(!requireCodeOwnerReview && !requireConversationResolution)) {
|
|
272
|
+
return new Map();
|
|
273
|
+
}
|
|
274
|
+
const read = await readReviewStates(api, entries.map(({ pr }) => pr.number), context.defaultBranch);
|
|
275
|
+
if (Result.isErr(read)) {
|
|
276
|
+
log(`Cannot read the reviews; holding nothing for them. (${lastLines(read.value, 2)})`);
|
|
277
|
+
return new Map();
|
|
278
|
+
}
|
|
279
|
+
const rules = {
|
|
280
|
+
requireCodeOwnerReview,
|
|
281
|
+
requireConversationResolution,
|
|
282
|
+
codeOwners: read.value.codeOwners === undefined
|
|
283
|
+
? []
|
|
284
|
+
: parseCodeOwners(read.value.codeOwners),
|
|
285
|
+
};
|
|
286
|
+
return new Map(Arr.generate(function* () {
|
|
287
|
+
for (const [prNumber, state] of Array.from(read.value.states)) {
|
|
288
|
+
const hold = reviewHold(state, rules);
|
|
289
|
+
if (hold !== undefined) {
|
|
290
|
+
yield [prNumber, hold];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}));
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
const readChecks = async (api, pr, context) => {
|
|
301
|
+
const checks = await listRequiredChecks(api, pr.number);
|
|
302
|
+
if (Result.isErr(checks)) {
|
|
303
|
+
return Result.err({
|
|
304
|
+
kind: 'note',
|
|
305
|
+
note: `#${pr.number}: could not read checks: ${checks.value}`,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
const running = await listRunningChecks(api, pr.number);
|
|
312
|
+
if (Result.isErr(running)) {
|
|
313
|
+
return Result.err({
|
|
314
|
+
kind: 'note',
|
|
315
|
+
note: `#${pr.number}: could not read checks: ${running.value}`,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return Result.ok(summarizeChecks(checks.value, context.requiredContexts, running.value));
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
const isConflicting = (pr) => pr.mergeStateStatus === 'DIRTY';
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
export const orderCandidates = (candidates, context) => orderQueueCandidates(candidates, factsOf, {
|
|
331
|
+
defaultBranch: context.defaultBranch,
|
|
332
|
+
demoted: (pr) => isDemoted(context.demoted, pr),
|
|
333
|
+
});
|
|
334
|
+
export const reportTriage = (triaged, total, context) => {
|
|
335
|
+
const { defaultBranch } = context;
|
|
336
|
+
const paused = triaged.candidates.filter(isSkipCiLabelled).length;
|
|
337
|
+
log(`${total} open pull request(s), ${triaged.inScope} labelled ${MERGE_QUEUED_LABEL}: ${triaged.candidates.length} to act on (${paused} paused by ${SKIP_CI_LABEL}), ${triaged.inFlight.length} in flight, ${triaged.failing.length} failing, ${triaged.held.length} held by review.`);
|
|
338
|
+
for (const cycle of triaged.cycles) {
|
|
339
|
+
if (!Arr.isNonEmpty(cycle)) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
log(` Merge-After cycle: ${[...cycle, cycle[0]].map((number) => `#${number}`).join(' → ')}`);
|
|
343
|
+
}
|
|
344
|
+
for (const held of triaged.held) {
|
|
345
|
+
log(` ${held}`);
|
|
346
|
+
}
|
|
347
|
+
for (const [prNumber, reason] of triaged.bypass) {
|
|
348
|
+
log(` #${prNumber}: only a ruleset bypass merges it — ${reason}; its checks are run, and auto-merge is left off`);
|
|
349
|
+
}
|
|
350
|
+
for (const note of triaged.notes) {
|
|
351
|
+
log(` ${note}`);
|
|
352
|
+
}
|
|
353
|
+
for (const { pr, summary } of triaged.failing) {
|
|
354
|
+
log(` #${pr.number}: up to date but failing: ${summary.failed.join(', ')}`);
|
|
355
|
+
}
|
|
356
|
+
for (const [position, pr] of triaged.candidates.entries()) {
|
|
357
|
+
log(` #${pr.number}: ${position === 0 ? 'next' : `${position} ahead of it`} — ${describeAction(pr, defaultBranch, triaged)}${isDemoted(context.demoted, pr) ? ' — last, because it sat green without merging' : ''}${priorityPhrase(pr)} — ${pr.title}`);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
export const describeAction = (pr, defaultBranch, triaged) => {
|
|
362
|
+
if (isVersionPullRequest(pr, defaultBranch)) {
|
|
363
|
+
return `take ${SKIP_CI_LABEL} off it — the release workflow owns the branch`;
|
|
364
|
+
}
|
|
365
|
+
const above = stackDescendants(triaged.stackParents, pr.number);
|
|
366
|
+
return [
|
|
367
|
+
`rebase onto ${defaultBranch}`,
|
|
368
|
+
isConflicting(pr)
|
|
369
|
+
? ', which GitHub says conflicts — a rebase will say'
|
|
370
|
+
: '',
|
|
371
|
+
Arr.isNonEmpty(above)
|
|
372
|
+
? `, carry ${above.map((n) => `#${n}`).join(', ')} stacked on it along`
|
|
373
|
+
: '',
|
|
374
|
+
triaged.toArm.has(pr.number) ? ', arm auto-merge' : '',
|
|
375
|
+
bypassPhrase(triaged.bypass.get(pr.number)),
|
|
376
|
+
isSkipCiLabelled(pr) ? `, then take ${SKIP_CI_LABEL} off it` : '',
|
|
377
|
+
].join('');
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
export const bypassPhrase = (reason) => reason === undefined
|
|
381
|
+
? ''
|
|
382
|
+
: `, leave auto-merge off (${reason}, so it needs a bypass merge)`;
|
|
383
|
+
|
|
384
|
+
const priorityPhrase = (pr) => {
|
|
385
|
+
switch (priorityOf(pr)) {
|
|
386
|
+
case 'high':
|
|
387
|
+
return ` — ahead of the rest, by ${PRIORITY_HIGH_LABEL}`;
|
|
388
|
+
case 'low':
|
|
389
|
+
return ` — behind the rest, by ${PRIORITY_LOW_LABEL}`;
|
|
390
|
+
case 'both':
|
|
391
|
+
return ` — labelled both ${PRIORITY_HIGH_LABEL} and ${PRIORITY_LOW_LABEL}, so neither counts`;
|
|
392
|
+
case 'none':
|
|
393
|
+
return '';
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
//# sourceMappingURL=triage.mjs.map
|