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,507 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describeWaitingOn,
|
|
3
|
+
reportedChecksOf,
|
|
4
|
+
summarizeChecks,
|
|
5
|
+
type CheckContextNode,
|
|
6
|
+
type ReportedCheck,
|
|
7
|
+
type RunningCheck,
|
|
8
|
+
} from './checks.mjs';
|
|
9
|
+
|
|
10
|
+
describe(summarizeChecks, () => {
|
|
11
|
+
const required = ['code-check-result / result', 'no-skip-ci-label'] as const;
|
|
12
|
+
|
|
13
|
+
test('passes when every required context passed and nothing is running', () => {
|
|
14
|
+
const summary = summarizeChecks(
|
|
15
|
+
[check('code-check-result / result'), check('no-skip-ci-label')],
|
|
16
|
+
required,
|
|
17
|
+
[],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
assert.strictEqual(summary.verdict, 'passed');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('counts a skipped context as met, as GitHub does', () => {
|
|
24
|
+
const summary = summarizeChecks(
|
|
25
|
+
[
|
|
26
|
+
check('code-check-result / result', 'skipping'),
|
|
27
|
+
check('no-skip-ci-label'),
|
|
28
|
+
],
|
|
29
|
+
required,
|
|
30
|
+
[],
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
assert.strictEqual(summary.verdict, 'passed');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// #2069: `skip-ci` came off a head whose previous round had concluded the
|
|
37
|
+
// aggregates `skipped`, and the new round had not created them yet.
|
|
38
|
+
test('stays pending while any check on the head is still running', () => {
|
|
39
|
+
const summary = summarizeChecks(
|
|
40
|
+
[
|
|
41
|
+
check('code-check-result / result', 'skipping'),
|
|
42
|
+
check('no-skip-ci-label'),
|
|
43
|
+
],
|
|
44
|
+
required,
|
|
45
|
+
[running('code-check (ws:fix:lint)')],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
assert.strictEqual(summary.verdict, 'pending');
|
|
49
|
+
|
|
50
|
+
assert.deepStrictEqual(summary.running, ['code-check (ws:fix:lint)']);
|
|
51
|
+
|
|
52
|
+
assert.strictEqual(
|
|
53
|
+
describeWaitingOn(summary),
|
|
54
|
+
'code-check (ws:fix:lint) (running)',
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('does not list a required check as running twice', () => {
|
|
59
|
+
const summary = summarizeChecks(
|
|
60
|
+
[
|
|
61
|
+
check('code-check-result / result', 'pending'),
|
|
62
|
+
check('no-skip-ci-label'),
|
|
63
|
+
],
|
|
64
|
+
required,
|
|
65
|
+
[
|
|
66
|
+
running('code-check-result / result'),
|
|
67
|
+
running('code-check (ws:fix:lint)'),
|
|
68
|
+
],
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
assert.deepStrictEqual(summary.pending, ['code-check-result / result']);
|
|
72
|
+
|
|
73
|
+
assert.deepStrictEqual(summary.running, ['code-check (ws:fix:lint)']);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('fails on a failed required check even while others run', () => {
|
|
77
|
+
const summary = summarizeChecks(
|
|
78
|
+
[check('code-check-result / result', 'fail'), check('no-skip-ci-label')],
|
|
79
|
+
required,
|
|
80
|
+
[running('code-check (ws:fix:lint)')],
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
assert.strictEqual(summary.verdict, 'failing');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('fails on a required check that failed in the round still running', () => {
|
|
87
|
+
const summary = summarizeChecks(
|
|
88
|
+
[
|
|
89
|
+
check('code-check-result / result', 'fail', {
|
|
90
|
+
completedAt: '2026-10-12T15:20:45Z',
|
|
91
|
+
}),
|
|
92
|
+
check('no-skip-ci-label'),
|
|
93
|
+
],
|
|
94
|
+
required,
|
|
95
|
+
[running('code-check (ws:fix:lint)', '2026-10-12T15:20:14Z')],
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
assert.strictEqual(summary.verdict, 'failing');
|
|
99
|
+
|
|
100
|
+
assert.deepStrictEqual(summary.failed, ['code-check-result / result']);
|
|
101
|
+
|
|
102
|
+
assert.deepStrictEqual(summary.failedRuns, [
|
|
103
|
+
{
|
|
104
|
+
name: 'code-check-result / result',
|
|
105
|
+
link: 'https://example.com/code-check-result / result',
|
|
106
|
+
},
|
|
107
|
+
]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// #2246: the round `skip-ci` cancelled when the pull request was opened
|
|
111
|
+
// left the aggregates red, and `skip-ci` came off the same head.
|
|
112
|
+
test('waits on a required check that failed before the round still running began', () => {
|
|
113
|
+
const summary = summarizeChecks(
|
|
114
|
+
[
|
|
115
|
+
check('code-check-result / result', 'cancel', {
|
|
116
|
+
completedAt: '2026-10-12T12:13:37Z',
|
|
117
|
+
}),
|
|
118
|
+
check('no-skip-ci-label'),
|
|
119
|
+
],
|
|
120
|
+
required,
|
|
121
|
+
[running('code-check (ws:fix:lint)', '2026-10-12T15:20:14Z')],
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
assert.strictEqual(summary.verdict, 'pending');
|
|
125
|
+
|
|
126
|
+
assert.deepStrictEqual(summary.failed, []);
|
|
127
|
+
|
|
128
|
+
assert.deepStrictEqual(summary.failedRuns, []);
|
|
129
|
+
|
|
130
|
+
assert.deepStrictEqual(summary.pending, ['code-check-result / result']);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// #2463: `skip-ci` came off while the round it was put on for was still
|
|
134
|
+
// being cancelled, so that round's aggregate went red 22 seconds after the
|
|
135
|
+
// new round's first check started. Its workflow's own new run, queued
|
|
136
|
+
// behind it by the concurrency group, is what says it is the round before.
|
|
137
|
+
test('waits on a required check whose workflow has a newer run still running', () => {
|
|
138
|
+
const summary = summarizeChecks(
|
|
139
|
+
[
|
|
140
|
+
check('synstate-benchmark-result / result', 'fail', {
|
|
141
|
+
completedAt: '2026-10-25T18:12:55Z',
|
|
142
|
+
workflow: 'SynState Benchmark',
|
|
143
|
+
runId: 40220095906,
|
|
144
|
+
}),
|
|
145
|
+
check('no-skip-ci-label'),
|
|
146
|
+
],
|
|
147
|
+
['synstate-benchmark-result / result', 'no-skip-ci-label'],
|
|
148
|
+
[
|
|
149
|
+
running('code-check (ws:fix:lint)', '2026-10-25T18:12:33Z', {
|
|
150
|
+
workflow: 'Code Check',
|
|
151
|
+
runId: 40220140988,
|
|
152
|
+
}),
|
|
153
|
+
running('gates / check', '2026-10-25T18:12:57Z', {
|
|
154
|
+
workflow: 'SynState Benchmark',
|
|
155
|
+
runId: 40220140914,
|
|
156
|
+
}),
|
|
157
|
+
],
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
assert.strictEqual(summary.verdict, 'pending');
|
|
161
|
+
|
|
162
|
+
assert.deepStrictEqual(summary.failed, []);
|
|
163
|
+
|
|
164
|
+
assert.deepStrictEqual(summary.failedRuns, []);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('fails on a required check whose workflow is still running in the same run', () => {
|
|
168
|
+
const summary = summarizeChecks(
|
|
169
|
+
[
|
|
170
|
+
check('code-check-result / result', 'fail', {
|
|
171
|
+
completedAt: '2026-10-25T18:12:55Z',
|
|
172
|
+
workflow: 'Code Check',
|
|
173
|
+
runId: 200,
|
|
174
|
+
}),
|
|
175
|
+
check('no-skip-ci-label'),
|
|
176
|
+
],
|
|
177
|
+
required,
|
|
178
|
+
[
|
|
179
|
+
running('code-check (ws:fix:lint)', '2026-10-25T18:12:33Z', {
|
|
180
|
+
workflow: 'Code Check',
|
|
181
|
+
runId: 200,
|
|
182
|
+
}),
|
|
183
|
+
],
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
assert.strictEqual(summary.verdict, 'failing');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('fails on a required check when only another workflow has a newer run', () => {
|
|
190
|
+
const summary = summarizeChecks(
|
|
191
|
+
[
|
|
192
|
+
check('code-check-result / result', 'fail', {
|
|
193
|
+
completedAt: '2026-10-25T18:12:55Z',
|
|
194
|
+
workflow: 'Code Check',
|
|
195
|
+
runId: 100,
|
|
196
|
+
}),
|
|
197
|
+
check('no-skip-ci-label'),
|
|
198
|
+
],
|
|
199
|
+
required,
|
|
200
|
+
[
|
|
201
|
+
running('gates / check', '2026-10-25T18:12:33Z', {
|
|
202
|
+
workflow: 'SynState Benchmark',
|
|
203
|
+
runId: 200,
|
|
204
|
+
}),
|
|
205
|
+
],
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
assert.strictEqual(summary.verdict, 'failing');
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('fails on a red left by the round before once nothing runs', () => {
|
|
212
|
+
const summary = summarizeChecks(
|
|
213
|
+
[
|
|
214
|
+
check('code-check-result / result', 'fail', {
|
|
215
|
+
completedAt: '2026-10-12T12:13:37Z',
|
|
216
|
+
}),
|
|
217
|
+
check('no-skip-ci-label'),
|
|
218
|
+
],
|
|
219
|
+
required,
|
|
220
|
+
[],
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
assert.strictEqual(summary.verdict, 'failing');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test('stays pending while a required context has not reported', () => {
|
|
227
|
+
const summary = summarizeChecks([check('no-skip-ci-label')], required, []);
|
|
228
|
+
|
|
229
|
+
assert.strictEqual(summary.verdict, 'pending');
|
|
230
|
+
|
|
231
|
+
assert.deepStrictEqual(summary.missing, ['code-check-result / result']);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('counts the contexts the verdict was reached over', () => {
|
|
235
|
+
const summary = summarizeChecks(
|
|
236
|
+
[check('code-check-result / result'), check('no-skip-ci-label')],
|
|
237
|
+
required,
|
|
238
|
+
[],
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
assert.strictEqual(summary.required, 2);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// The rules could not be read: what `--required` reported is all there is.
|
|
245
|
+
test('judges by what has reported when nothing is known to be required', () => {
|
|
246
|
+
assert.strictEqual(
|
|
247
|
+
summarizeChecks([check('no-skip-ci-label')], [], []).verdict,
|
|
248
|
+
'passed',
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
assert.strictEqual(
|
|
252
|
+
summarizeChecks([check('no-skip-ci-label', 'fail')], [], []).verdict,
|
|
253
|
+
'failing',
|
|
254
|
+
);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('stays pending while nothing has reported, even with nothing known to be required', () => {
|
|
258
|
+
assert.strictEqual(summarizeChecks([], [], []).verdict, 'pending');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('fails on a context that failed once and passed once, as GitHub does', () => {
|
|
262
|
+
const summary = summarizeChecks(
|
|
263
|
+
[
|
|
264
|
+
check('code-check-result / result'),
|
|
265
|
+
check('code-check-result / result', 'fail'),
|
|
266
|
+
check('no-skip-ci-label'),
|
|
267
|
+
],
|
|
268
|
+
required,
|
|
269
|
+
[],
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
assert.strictEqual(summary.verdict, 'failing');
|
|
273
|
+
|
|
274
|
+
assert.deepStrictEqual(summary.failed, ['code-check-result / result']);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// The worker arms a pull request it judges green, and an armed pull
|
|
278
|
+
// request stacked on a branch no ruleset covers merges into it at once.
|
|
279
|
+
// So a required context that has not reported is waited for wherever the
|
|
280
|
+
// pull request points, unlike in `pr-report`'s `notRun`.
|
|
281
|
+
test('waits on a required context that has not reported, whatever the base', () => {
|
|
282
|
+
const summary = summarizeChecks([check('no-skip-ci-label')], required, []);
|
|
283
|
+
|
|
284
|
+
assert.deepStrictEqual(summary.notRun, []);
|
|
285
|
+
|
|
286
|
+
assert.deepStrictEqual(summary.missing, ['code-check-result / result']);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("never reads as paused: `skip-ci` is the queue's to read, not the checks'", () => {
|
|
290
|
+
assert.notStrictEqual(
|
|
291
|
+
summarizeChecks([check('no-skip-ci-label', 'pending')], required, [])
|
|
292
|
+
.verdict,
|
|
293
|
+
'paused',
|
|
294
|
+
);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const check = (
|
|
299
|
+
name: string,
|
|
300
|
+
bucket: string = 'pass',
|
|
301
|
+
{
|
|
302
|
+
completedAt = '',
|
|
303
|
+
workflow = '',
|
|
304
|
+
runId,
|
|
305
|
+
}: Readonly<{
|
|
306
|
+
/** When it finished, which is also taken as when it started. */
|
|
307
|
+
completedAt?: string;
|
|
308
|
+
workflow?: string;
|
|
309
|
+
runId?: number;
|
|
310
|
+
}> = {},
|
|
311
|
+
): ReportedCheck =>
|
|
312
|
+
({
|
|
313
|
+
name,
|
|
314
|
+
bucket,
|
|
315
|
+
link: linkOf(name, runId),
|
|
316
|
+
startedAt: completedAt,
|
|
317
|
+
completedAt,
|
|
318
|
+
workflow,
|
|
319
|
+
}) as const;
|
|
320
|
+
|
|
321
|
+
const running = (
|
|
322
|
+
name: string,
|
|
323
|
+
startedAt: string = '',
|
|
324
|
+
{
|
|
325
|
+
workflow = '',
|
|
326
|
+
runId,
|
|
327
|
+
}: Readonly<{ workflow?: string; runId?: number }> = {},
|
|
328
|
+
): RunningCheck =>
|
|
329
|
+
({ name, startedAt, workflow, link: linkOf(name, runId) }) as const;
|
|
330
|
+
|
|
331
|
+
/** What `gh` reports for a job of a workflow run, or a status's own URL. */
|
|
332
|
+
const linkOf = (name: string, runId: number | undefined): string =>
|
|
333
|
+
runId === undefined
|
|
334
|
+
? (`https://example.com/${name}` as const)
|
|
335
|
+
: (`https://github.com/noshiro-pf/mono/actions/runs/${runId}/job/1` as const);
|
|
336
|
+
|
|
337
|
+
describe(reportedChecksOf, () => {
|
|
338
|
+
const ZERO = '0001-01-01T00:00:00Z';
|
|
339
|
+
|
|
340
|
+
test('sorts a check run into the bucket `gh pr checks` would', () => {
|
|
341
|
+
const buckets = reportedChecksOf(
|
|
342
|
+
[
|
|
343
|
+
checkRun('a', 'COMPLETED', 'SUCCESS'),
|
|
344
|
+
checkRun('b', 'COMPLETED', 'SKIPPED'),
|
|
345
|
+
checkRun('c', 'COMPLETED', 'NEUTRAL'),
|
|
346
|
+
checkRun('d', 'COMPLETED', 'FAILURE'),
|
|
347
|
+
checkRun('e', 'COMPLETED', 'TIMED_OUT'),
|
|
348
|
+
checkRun('f', 'COMPLETED', 'ACTION_REQUIRED'),
|
|
349
|
+
checkRun('g', 'COMPLETED', 'CANCELLED'),
|
|
350
|
+
checkRun('h', 'IN_PROGRESS', null),
|
|
351
|
+
checkRun('i', 'QUEUED', null, null),
|
|
352
|
+
checkRun('j', 'COMPLETED', 'STALE'),
|
|
353
|
+
checkRun('k', 'COMPLETED', 'STARTUP_FAILURE'),
|
|
354
|
+
],
|
|
355
|
+
'all',
|
|
356
|
+
).map(({ name, bucket }) => `${name}:${bucket}`);
|
|
357
|
+
|
|
358
|
+
assert.deepStrictEqual(buckets, [
|
|
359
|
+
'a:pass',
|
|
360
|
+
'b:skipping',
|
|
361
|
+
'c:skipping',
|
|
362
|
+
'd:fail',
|
|
363
|
+
'e:fail',
|
|
364
|
+
'f:fail',
|
|
365
|
+
'g:cancel',
|
|
366
|
+
'h:pending',
|
|
367
|
+
'i:pending',
|
|
368
|
+
'j:pending',
|
|
369
|
+
'k:fail',
|
|
370
|
+
]);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test('sorts a commit status by its state, its time being when it was set', () => {
|
|
374
|
+
assert.deepStrictEqual(
|
|
375
|
+
reportedChecksOf(
|
|
376
|
+
[
|
|
377
|
+
statusContext('no-skip-ci-label', 'SUCCESS'),
|
|
378
|
+
statusContext('x', 'FAILURE'),
|
|
379
|
+
statusContext('y', 'ERROR'),
|
|
380
|
+
statusContext('z', 'PENDING'),
|
|
381
|
+
statusContext('w', 'EXPECTED'),
|
|
382
|
+
],
|
|
383
|
+
'all',
|
|
384
|
+
).map(({ name, bucket, link, startedAt, completedAt }) => ({
|
|
385
|
+
name,
|
|
386
|
+
bucket,
|
|
387
|
+
link,
|
|
388
|
+
startedAt,
|
|
389
|
+
completedAt,
|
|
390
|
+
})),
|
|
391
|
+
[
|
|
392
|
+
['no-skip-ci-label', 'pass'],
|
|
393
|
+
['x', 'fail'],
|
|
394
|
+
['y', 'fail'],
|
|
395
|
+
['z', 'pending'],
|
|
396
|
+
['w', 'pending'],
|
|
397
|
+
].map(([name, bucket]) => ({
|
|
398
|
+
name,
|
|
399
|
+
bucket,
|
|
400
|
+
link: '',
|
|
401
|
+
startedAt: '2026-10-25T10:00:00Z',
|
|
402
|
+
completedAt: '2026-10-25T10:00:00Z',
|
|
403
|
+
})),
|
|
404
|
+
);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test("writes GitHub's zero time for a time not reached yet", () => {
|
|
408
|
+
const [queued] = reportedChecksOf(
|
|
409
|
+
[checkRun('i', 'QUEUED', null, null)],
|
|
410
|
+
'all',
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
assert.strictEqual(queued?.startedAt, ZERO);
|
|
414
|
+
|
|
415
|
+
assert.strictEqual(queued?.completedAt, ZERO);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
test('keeps only the latest run of a job in one workflow and event', () => {
|
|
419
|
+
const checks = reportedChecksOf(
|
|
420
|
+
[
|
|
421
|
+
checkRun('a', 'COMPLETED', 'CANCELLED', '2026-10-25T09:00:00Z'),
|
|
422
|
+
checkRun('a', 'IN_PROGRESS', null, '2026-10-25T11:00:00Z'),
|
|
423
|
+
checkRun('a', 'COMPLETED', 'SUCCESS', '2026-10-25T08:00:00Z', {
|
|
424
|
+
event: 'push',
|
|
425
|
+
}),
|
|
426
|
+
],
|
|
427
|
+
'all',
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
assert.deepStrictEqual(
|
|
431
|
+
checks.map(({ bucket }) => bucket),
|
|
432
|
+
['pending', 'pass'],
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
test('reads the workflow of a check run, and none for a commit status', () => {
|
|
437
|
+
assert.deepStrictEqual(
|
|
438
|
+
reportedChecksOf(
|
|
439
|
+
[checkRun('a', 'COMPLETED', 'SUCCESS'), statusContext('b', 'SUCCESS')],
|
|
440
|
+
'all',
|
|
441
|
+
).map(({ workflow }) => workflow),
|
|
442
|
+
['code-check', ''],
|
|
443
|
+
);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
test('keeps a check run and a commit status of the same name apart', () => {
|
|
447
|
+
assert.strictEqual(
|
|
448
|
+
reportedChecksOf(
|
|
449
|
+
[checkRun('x', 'COMPLETED', 'SUCCESS'), statusContext('x', 'FAILURE')],
|
|
450
|
+
'all',
|
|
451
|
+
).length,
|
|
452
|
+
2,
|
|
453
|
+
);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
test('leaves out what the branch does not require when asked to', () => {
|
|
457
|
+
assert.deepStrictEqual(
|
|
458
|
+
reportedChecksOf(
|
|
459
|
+
[
|
|
460
|
+
checkRun('a', 'COMPLETED', 'SUCCESS'),
|
|
461
|
+
checkRun('b', 'COMPLETED', 'SUCCESS', undefined, {
|
|
462
|
+
isRequired: false,
|
|
463
|
+
}),
|
|
464
|
+
],
|
|
465
|
+
'required',
|
|
466
|
+
).map(({ name }) => name),
|
|
467
|
+
['a'],
|
|
468
|
+
);
|
|
469
|
+
});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const checkRun = (
|
|
473
|
+
name: string,
|
|
474
|
+
status: string,
|
|
475
|
+
conclusion: string | null,
|
|
476
|
+
startedAt: string | null = '2026-10-25T10:00:00Z',
|
|
477
|
+
{ isRequired = true, event = 'pull_request' }: CheckRunOptions = {},
|
|
478
|
+
): CheckContextNode =>
|
|
479
|
+
({
|
|
480
|
+
__typename: 'CheckRun',
|
|
481
|
+
name,
|
|
482
|
+
status,
|
|
483
|
+
conclusion,
|
|
484
|
+
startedAt,
|
|
485
|
+
completedAt: conclusion === null ? null : ('2026-10-25T10:05:00Z' as const),
|
|
486
|
+
detailsUrl: `https://example.com/${name}`,
|
|
487
|
+
isRequired,
|
|
488
|
+
checkSuite: {
|
|
489
|
+
workflowRun: { event, workflow: { name: 'code-check' } },
|
|
490
|
+
},
|
|
491
|
+
}) as const;
|
|
492
|
+
|
|
493
|
+
type CheckRunOptions = Readonly<{ isRequired?: boolean; event?: string }>;
|
|
494
|
+
|
|
495
|
+
const statusContext = (
|
|
496
|
+
context: string,
|
|
497
|
+
state: string,
|
|
498
|
+
createdAt = '2026-10-25T10:00:00Z',
|
|
499
|
+
): CheckContextNode =>
|
|
500
|
+
({
|
|
501
|
+
__typename: 'StatusContext',
|
|
502
|
+
context,
|
|
503
|
+
state,
|
|
504
|
+
targetUrl: null,
|
|
505
|
+
createdAt,
|
|
506
|
+
isRequired: true,
|
|
507
|
+
}) as const;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pull requests a session has claimed, which this script leaves alone.
|
|
3
|
+
*
|
|
4
|
+
* A session claims a pull request this script set aside before fixing it
|
|
5
|
+
* (`claim-pr`; `pr-report-core`'s `claim.mts` says what a claim is).
|
|
6
|
+
* Without one, the base moving would have this script try a set-aside
|
|
7
|
+
* rebase again while the session is resolving the same conflict, and a
|
|
8
|
+
* ticked retry box would do the same for any reason. So while a claim holds,
|
|
9
|
+
* the pull request is a skill's (`owner.mts`): not picked and not kept on the
|
|
10
|
+
* tip ("3a"), and its labels are left alone — the session pushes under
|
|
11
|
+
* `skip-ci` itself. The session's push ends the claim and hands the pull
|
|
12
|
+
* request back, as the push alone always did.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { claimApplies, type Claim } from 'pr-report-core';
|
|
16
|
+
import type { PullRequest } from './types.mjs';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The claims, read from this account's comments, that still hold the open
|
|
20
|
+
* pull requests they name.
|
|
21
|
+
*/
|
|
22
|
+
export const standingClaims = (
|
|
23
|
+
claims: ReadonlyMap<number, Claim>,
|
|
24
|
+
pullRequests: readonly PullRequest[],
|
|
25
|
+
nowEpochMs: number,
|
|
26
|
+
): ReadonlyMap<number, Claim> =>
|
|
27
|
+
new Map(
|
|
28
|
+
Array.from(claims).filter(([number, claim]) => {
|
|
29
|
+
const pr = pullRequests.find((p) => p.number === number);
|
|
30
|
+
|
|
31
|
+
return pr !== undefined && claimApplies(claim, pr.headRefOid, nowEpochMs);
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Claim } from 'pr-report-core';
|
|
2
|
+
import { standingClaims } from './claims.mjs';
|
|
3
|
+
import type { PullRequest } from './types.mjs';
|
|
4
|
+
|
|
5
|
+
const HEAD = 'c'.repeat(40);
|
|
6
|
+
|
|
7
|
+
const CLAIM: Claim = {
|
|
8
|
+
headSha: HEAD,
|
|
9
|
+
by: 'https://claude.ai/code/session_01abc',
|
|
10
|
+
at: '2026-10-12T01:00:00Z',
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
const NOW = Date.parse('2026-10-12T01:30:00Z');
|
|
14
|
+
|
|
15
|
+
const pullRequest = (number: number, headRefOid = HEAD): PullRequest =>
|
|
16
|
+
({
|
|
17
|
+
number,
|
|
18
|
+
id: `PR_${number}`,
|
|
19
|
+
title: `#${number}`,
|
|
20
|
+
body: '',
|
|
21
|
+
state: 'OPEN',
|
|
22
|
+
headRefName: `feature/${number}`,
|
|
23
|
+
headRefOid,
|
|
24
|
+
baseRefName: 'main',
|
|
25
|
+
isCrossRepository: false,
|
|
26
|
+
isDraft: false,
|
|
27
|
+
mergeStateStatus: 'BLOCKED',
|
|
28
|
+
autoMergeRequest: null,
|
|
29
|
+
labels: [],
|
|
30
|
+
}) as const;
|
|
31
|
+
|
|
32
|
+
describe(standingClaims, () => {
|
|
33
|
+
test('keeps a claim at the head its pull request is at', () => {
|
|
34
|
+
assert.deepStrictEqual(
|
|
35
|
+
standingClaims(new Map([[1, CLAIM]]), [pullRequest(1)], NOW),
|
|
36
|
+
new Map([[1, CLAIM]]),
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('drops one whose branch has been pushed, which is the claim done', () => {
|
|
41
|
+
assert.deepStrictEqual(
|
|
42
|
+
standingClaims(
|
|
43
|
+
new Map([[1, CLAIM]]),
|
|
44
|
+
[pullRequest(1, 'd'.repeat(40))],
|
|
45
|
+
NOW,
|
|
46
|
+
),
|
|
47
|
+
new Map(),
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('drops one that has run out, and one on a closed pull request', () => {
|
|
52
|
+
assert.deepStrictEqual(
|
|
53
|
+
standingClaims(
|
|
54
|
+
new Map([
|
|
55
|
+
[1, CLAIM],
|
|
56
|
+
[2, CLAIM],
|
|
57
|
+
]),
|
|
58
|
+
[pullRequest(1)],
|
|
59
|
+
NOW + 3 * 60 * 60_000,
|
|
60
|
+
),
|
|
61
|
+
new Map(),
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
});
|