pr-report-core 0.2.0 → 0.2.1
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/dist/checks.d.mts +61 -62
- package/dist/checks.d.mts.map +1 -1
- package/dist/checks.mjs +0 -1
- package/dist/checks.mjs.map +1 -1
- package/dist/claim.d.mts +13 -14
- package/dist/claim.d.mts.map +1 -1
- package/dist/claim.mjs +0 -1
- package/dist/claim.mjs.map +1 -1
- package/dist/closing-issues.d.mts +18 -19
- package/dist/closing-issues.d.mts.map +1 -1
- package/dist/closing-issues.mjs +0 -1
- package/dist/closing-issues.mjs.map +1 -1
- package/dist/code-owners.d.mts +33 -34
- package/dist/code-owners.d.mts.map +1 -1
- package/dist/code-owners.mjs +0 -2
- package/dist/code-owners.mjs.map +1 -1
- package/dist/labels.d.mts +38 -40
- package/dist/labels.d.mts.map +1 -1
- package/dist/labels.mjs +0 -2
- package/dist/labels.mjs.map +1 -1
- package/dist/merge-after.d.mts +22 -16
- package/dist/merge-after.d.mts.map +1 -1
- package/dist/merge-after.mjs +87 -24
- package/dist/merge-after.mjs.map +1 -1
- package/dist/queue-comments.d.mts +2 -2
- package/dist/queue-order.d.mts +32 -32
- package/dist/queue-order.mjs +0 -2
- package/dist/queue-order.mjs.map +1 -1
- package/dist/queue-owner.d.mts +13 -13
- package/dist/queue-owner.mjs.map +1 -1
- package/dist/report.d.mts +4 -4
- package/dist/review-hold.d.mts +14 -14
- package/dist/ruleset.d.mts +10 -11
- package/dist/ruleset.d.mts.map +1 -1
- package/dist/ruleset.mjs +0 -1
- package/dist/ruleset.mjs.map +1 -1
- package/dist/set-aside.d.mts +28 -28
- package/dist/stack.d.mts +14 -15
- package/dist/stack.d.mts.map +1 -1
- package/dist/stack.mjs +0 -1
- package/dist/stack.mjs.map +1 -1
- package/dist/start-after.d.mts +20 -21
- package/dist/start-after.d.mts.map +1 -1
- package/dist/start-after.mjs +0 -1
- package/dist/start-after.mjs.map +1 -1
- package/dist/summarize.d.mts +2 -2
- package/dist/timestamp.d.mts +10 -10
- package/dist/tree.d.mts +5 -5
- package/dist/types.d.mts +32 -33
- package/dist/types.d.mts.map +1 -1
- package/package.json +8 -8
- package/src/checks.mts +64 -65
- package/src/checks.test.mts +30 -31
- package/src/claim.mts +13 -14
- package/src/closing-issues.mts +18 -19
- package/src/closing-issues.test.mts +2 -2
- package/src/code-owners.mts +39 -41
- package/src/labels.mts +38 -40
- package/src/merge-after.mts +142 -49
- package/src/merge-after.test.mts +80 -3
- package/src/queue-comments.mts +2 -2
- package/src/queue-order.mts +60 -62
- package/src/queue-order.test.mts +6 -6
- package/src/queue-owner.mts +25 -25
- package/src/queue-owner.test.mts +2 -2
- package/src/report.mts +9 -9
- package/src/review-hold.mts +14 -14
- package/src/review-hold.test.mts +3 -3
- package/src/ruleset.mts +10 -11
- package/src/set-aside.mts +28 -28
- package/src/stack.mts +14 -15
- package/src/stack.test.mts +4 -4
- package/src/start-after.mts +20 -21
- package/src/summarize.mts +2 -2
- package/src/timestamp.mts +14 -14
- package/src/tree.mts +5 -5
- package/src/types.mts +32 -33
package/dist/types.d.mts
CHANGED
|
@@ -12,22 +12,21 @@ export type RepoRef = Readonly<{
|
|
|
12
12
|
* What one context has reported on a head commit.
|
|
13
13
|
*
|
|
14
14
|
* `skipped` is its own state rather than a kind of `passed`. GitHub counts a
|
|
15
|
-
* skip as met, and so does the verdict — but once the two are one word a
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* skip as met, and so does the verdict — but once the two are one word a reader
|
|
16
|
+
* cannot tell them apart, and the aggregate that skipped may be from a round
|
|
17
|
+
* that was superseded by one about to fail.
|
|
18
18
|
*/
|
|
19
19
|
export type ContextState = 'failed' | 'passed' | 'pending' | 'skipped';
|
|
20
20
|
export type ChecksSummary = Readonly<{
|
|
21
21
|
/**
|
|
22
|
-
* `paused` is `skip-ci`: the gated jobs boot no runner and
|
|
23
|
-
*
|
|
24
|
-
* "failing" describes it.
|
|
22
|
+
* `paused` is `skip-ci`: the gated jobs boot no runner and `no-skip-ci-label`
|
|
23
|
+
* sits `pending` by design, so neither "pending" nor "failing" describes it.
|
|
25
24
|
*/
|
|
26
25
|
verdict: 'failing' | 'passed' | 'paused' | 'pending';
|
|
27
26
|
/**
|
|
28
27
|
* Every required context by what it reported. These four,
|
|
29
|
-
* {@link ChecksSummary.missing} and {@link ChecksSummary.notRun} are
|
|
30
|
-
*
|
|
28
|
+
* {@link ChecksSummary.missing} and {@link ChecksSummary.notRun} are disjoint
|
|
29
|
+
* and cover the required list.
|
|
31
30
|
*/
|
|
32
31
|
passed: readonly string[];
|
|
33
32
|
failed: readonly string[];
|
|
@@ -41,9 +40,9 @@ export type ChecksSummary = Readonly<{
|
|
|
41
40
|
missing: readonly string[];
|
|
42
41
|
/**
|
|
43
42
|
* Required contexts with nothing reported, on a pull request whose base the
|
|
44
|
-
* ruleset does not cover — a stacked one. A workflow may run on pull
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* ruleset does not cover — a stacked one. A workflow may run on pull requests
|
|
44
|
+
* into `main` only, and then its contexts never come here; nothing waits for
|
|
45
|
+
* them, since GitHub requires nothing of this base either.
|
|
47
46
|
*/
|
|
48
47
|
notRun: readonly string[];
|
|
49
48
|
/** How many contexts the verdict was reached over. */
|
|
@@ -82,28 +81,28 @@ export type PullRequestFacts = Readonly<{
|
|
|
82
81
|
labels: readonly Label[];
|
|
83
82
|
/**
|
|
84
83
|
* Whether auto-merge is armed. Separate from `merge-queued`, which is the
|
|
85
|
-
* author saying a pull request is to be landed: the label is the request
|
|
86
|
-
*
|
|
87
|
-
*
|
|
84
|
+
* author saying a pull request is to be landed: the label is the request and
|
|
85
|
+
* this is the mechanism, which `unblock-prs` arms when it picks the pull
|
|
86
|
+
* request.
|
|
88
87
|
*/
|
|
89
88
|
autoMerge: boolean;
|
|
90
89
|
headRef: string;
|
|
91
90
|
headSha: string;
|
|
92
91
|
baseRef: string;
|
|
93
92
|
/**
|
|
94
|
-
* Whether the head branch lives in a fork, which keeps it from being read
|
|
95
|
-
*
|
|
93
|
+
* Whether the head branch lives in a fork, which keeps it from being read as
|
|
94
|
+
* the parent of a stacked pull request. See `stack.mts`.
|
|
96
95
|
*/
|
|
97
96
|
fromFork: boolean;
|
|
98
97
|
url: string;
|
|
99
98
|
/**
|
|
100
|
-
* When anything about the pull request last changed — a label, a comment,
|
|
101
|
-
*
|
|
99
|
+
* When anything about the pull request last changed — a label, a comment, an
|
|
100
|
+
* edit — which is why it is not {@link PullRequestFacts.headCommittedAt}.
|
|
102
101
|
*/
|
|
103
102
|
updatedAt: string;
|
|
104
103
|
/**
|
|
105
|
-
* When the head commit was made, which is when the branch was last pushed
|
|
106
|
-
*
|
|
104
|
+
* When the head commit was made, which is when the branch was last pushed to
|
|
105
|
+
* as nearly as GitHub records it. Undefined when it could not be read.
|
|
107
106
|
*/
|
|
108
107
|
headCommittedAt: string | undefined;
|
|
109
108
|
/** Undefined when the comparison could not be read. */
|
|
@@ -111,8 +110,8 @@ export type PullRequestFacts = Readonly<{
|
|
|
111
110
|
/** What every context reported on the head commit, required or not. */
|
|
112
111
|
reported: ReadonlyMap<string, ContextState>;
|
|
113
112
|
/**
|
|
114
|
-
* Whether any check run on the head commit has not finished, required or
|
|
115
|
-
*
|
|
113
|
+
* Whether any check run on the head commit has not finished, required or not.
|
|
114
|
+
* See `anyRunInProgress` for why the required ones are not enough.
|
|
116
115
|
*/
|
|
117
116
|
checksRunning: boolean;
|
|
118
117
|
linkedIssues: readonly LinkedIssue[];
|
|
@@ -126,8 +125,8 @@ export type ReportEntry = PullRequestFacts & Readonly<{
|
|
|
126
125
|
*/
|
|
127
126
|
stackedOn: number | undefined;
|
|
128
127
|
/**
|
|
129
|
-
* The open pull requests it merges after because an issue it closes
|
|
130
|
-
*
|
|
128
|
+
* The open pull requests it merges after because an issue it closes starts
|
|
129
|
+
* after them (`start-after.mts`'s `inheritStartAfter`), less what
|
|
131
130
|
* `mergeAfter` and `stackedOn` already say.
|
|
132
131
|
*/
|
|
133
132
|
inheritedMergeAfter: readonly number[];
|
|
@@ -146,9 +145,9 @@ export type ReportEntry = PullRequestFacts & Readonly<{
|
|
|
146
145
|
}>;
|
|
147
146
|
/**
|
|
148
147
|
* One pull request in the merge order. `repeated` marks the second and later
|
|
149
|
-
* appearances of a pull request with more than one predecessor — declared,
|
|
150
|
-
*
|
|
151
|
-
*
|
|
148
|
+
* appearances of a pull request with more than one predecessor — declared, or
|
|
149
|
+
* the one it is stacked on: it is drawn under each of them, but expanded under
|
|
150
|
+
* the first only.
|
|
152
151
|
*/
|
|
153
152
|
export type TreeNode = Readonly<{
|
|
154
153
|
number: number;
|
|
@@ -158,8 +157,8 @@ export type TreeNode = Readonly<{
|
|
|
158
157
|
/**
|
|
159
158
|
* One pull request that has already landed, for the section that says what
|
|
160
159
|
* shipped. Nothing that is true of an open pull request — a merge order, a
|
|
161
|
-
* check verdict, a distance from its base — is true of one that has merged,
|
|
162
|
-
*
|
|
160
|
+
* check verdict, a distance from its base — is true of one that has merged, so
|
|
161
|
+
* it is its own shape rather than an entry with the fields blanked.
|
|
163
162
|
*/
|
|
164
163
|
export type MergedPullRequest = Readonly<{
|
|
165
164
|
number: number;
|
|
@@ -193,8 +192,8 @@ export type OpenIssue = Readonly<{
|
|
|
193
192
|
*/
|
|
194
193
|
startAfter: readonly number[];
|
|
195
194
|
/**
|
|
196
|
-
* What a `Merge-After:` in its body names. That line is not read on an
|
|
197
|
-
*
|
|
195
|
+
* What a `Merge-After:` in its body names. That line is not read on an issue,
|
|
196
|
+
* and is shown as a slip to fix: `Start-After:` is the issue's.
|
|
198
197
|
*/
|
|
199
198
|
misplacedMergeAfter: readonly number[];
|
|
200
199
|
}>;
|
|
@@ -215,8 +214,8 @@ export type IssueDeclarations = Readonly<{
|
|
|
215
214
|
/** Each issue's `Start-After:`; an issue not in it declares nothing. */
|
|
216
215
|
startAfter: ReadonlyMap<number, readonly number[]>;
|
|
217
216
|
/**
|
|
218
|
-
* The numbers known to be open issues, beyond the ones an open pull
|
|
219
|
-
*
|
|
217
|
+
* The numbers known to be open issues, beyond the ones an open pull request
|
|
218
|
+
* links as open. Decides only what is said not to be started.
|
|
220
219
|
*/
|
|
221
220
|
open: ReadonlySet<number>;
|
|
222
221
|
}>;
|
package/dist/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.mts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAE1E;;;GAGG;AAEH,wCAAwC;AACxC,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvE,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC
|
|
1
|
+
{"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../src/types.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pr-report-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "What a GitHub merge queue driven by labels and `Merge-After:` trailers decides about the open pull requests — verdicts, merge order, stacks, owners — with no I/O, shared by the GitHub Pull Requests Manager page and the unblock-prs worker",
|
|
6
6
|
"keywords": [
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"LICENSE"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"ts-data-forge": "^14.
|
|
43
|
-
"ts-fortress": "^12.4.
|
|
42
|
+
"ts-data-forge": "^14.11.0",
|
|
43
|
+
"ts-fortress": "^12.4.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@octokit/openapi-types": "^29.0.1",
|
|
@@ -49,16 +49,16 @@
|
|
|
49
49
|
"cspell": "10.4.0",
|
|
50
50
|
"dedent": "1.7.2",
|
|
51
51
|
"eslint": "10.13.0",
|
|
52
|
-
"eslint-config-typed": "7.
|
|
53
|
-
"eslint-plugin-ts-data-forge": "0.10.
|
|
54
|
-
"eslint-plugin-ts-fortress": "1.3.
|
|
55
|
-
"eslint-plugin-ts-type-forge": "0.8.
|
|
52
|
+
"eslint-config-typed": "7.4.0",
|
|
53
|
+
"eslint-plugin-ts-data-forge": "0.10.9",
|
|
54
|
+
"eslint-plugin-ts-fortress": "1.3.13",
|
|
55
|
+
"eslint-plugin-ts-type-forge": "0.8.18",
|
|
56
56
|
"jiti": "2.7.0",
|
|
57
57
|
"npm-run-all2": "9.0.4",
|
|
58
58
|
"prettier": "3.9.10",
|
|
59
59
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
60
60
|
"prettier-plugin-packagejson": "3.0.2",
|
|
61
|
-
"ts-repo-utils": "10.7.
|
|
61
|
+
"ts-repo-utils": "10.7.2",
|
|
62
62
|
"tsx": "4.23.15",
|
|
63
63
|
"typescript": "6.0.3",
|
|
64
64
|
"typescript-native": "npm:typescript@7.0.2",
|
package/src/checks.mts
CHANGED
|
@@ -6,36 +6,36 @@ import type { ChecksSummary, ContextState } from './types.mjs';
|
|
|
6
6
|
/**
|
|
7
7
|
* What every context reported, from a head commit's check runs.
|
|
8
8
|
*
|
|
9
|
-
* A name appears more than once whenever two check suites reported it, and on
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
9
|
+
* A name appears more than once whenever two check suites reported it, and on a
|
|
10
|
+
* queued pull request that is the normal case rather than the odd one: the run
|
|
11
|
+
* the `opened` event starts is cancelled by the `labeled` event's, and both
|
|
12
|
+
* stay on the commit — the cancelled one leaving its `*-result` aggregate
|
|
13
|
+
* concluded `failure`, because an `if: always()` job that asserts on cancelled
|
|
14
|
+
* `needs` fails.
|
|
15
15
|
*
|
|
16
|
-
* **The newest check suite wins, and that is not the same as the newest
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* **The newest check suite wins, and that is not the same as the newest run.**
|
|
17
|
+
* GitHub resolves a required context to the run in the suite with the greatest
|
|
18
|
+
* id, so where the cancelled suite happens to have been created after the one
|
|
19
|
+
* that superseded it, the stale red is what holds the merge — however much
|
|
20
|
+
* later the green one finished. Every suite of one push is created in the same
|
|
21
|
+
* second, so which of them got the higher id is not something the repository
|
|
22
|
+
* decides.
|
|
23
23
|
*
|
|
24
24
|
* This is why the rule is not "the newest `started_at`", which reads more
|
|
25
25
|
* natural and would call such a pull request green while GitHub blocks it.
|
|
26
|
-
* A report that says a blocked pull request will merge is worse than one
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* A report that says a blocked pull request will merge is worse than one that
|
|
27
|
+
* says a green one will not: `CLAUDE.md`'s "Commits and pull requests" says to
|
|
28
|
+
* ignore the red the cancelled run leaves, and this is the case where
|
|
29
29
|
* GitHub does not.
|
|
30
30
|
*
|
|
31
31
|
* **A run whose workflow has a newer round still going is pending.** An
|
|
32
|
-
* aggregate has no run in a round until the jobs it waits on are done, so
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
32
|
+
* aggregate has no run in a round until the jobs it waits on are done, so until
|
|
33
|
+
* then the only run of its name is the previous round's — on a pull request
|
|
34
|
+
* whose label events started two rounds, the red the second left on the first
|
|
35
|
+
* (#2191). That run is what GitHub shows, but not what it will answer with: the
|
|
36
|
+
* newer round is in the suite with the greater id, and its aggregate will be
|
|
37
|
+
* the newest run of the name. Where the newer round has finished without one,
|
|
38
|
+
* the older run stands, as it does on GitHub.
|
|
39
39
|
*/
|
|
40
40
|
export const statesFromCheckRuns = (
|
|
41
41
|
runs: readonly CheckRunReport[],
|
|
@@ -101,9 +101,9 @@ export type CheckRunReport = Readonly<{
|
|
|
101
101
|
/**
|
|
102
102
|
* The workflow run its suite is, where it is one: the workflow, so that a
|
|
103
103
|
* newer round of it can be told from an unrelated suite, and whether the
|
|
104
|
-
* round has finished, which its runs alone do not say — an aggregate's run
|
|
105
|
-
*
|
|
106
|
-
*
|
|
104
|
+
* round has finished, which its runs alone do not say — an aggregate's run is
|
|
105
|
+
* created only once every job before it has completed. `undefined` for a run
|
|
106
|
+
* no workflow made, or where the workflow runs could not be read.
|
|
107
107
|
*/
|
|
108
108
|
round: Readonly<{ workflowId: number; completed: boolean }> | undefined;
|
|
109
109
|
}>;
|
|
@@ -114,12 +114,12 @@ export type CheckRunReport = Readonly<{
|
|
|
114
114
|
* A run that has not completed is pending whatever it concluded last — the
|
|
115
115
|
* conclusion of a re-run is the previous verdict until the new one finishes.
|
|
116
116
|
* A `skipped` conclusion is reported as `skipped` and counted as met by
|
|
117
|
-
* {@link summarizeChecks}, because GitHub counts it as met: the gated jobs
|
|
118
|
-
*
|
|
119
|
-
*
|
|
117
|
+
* {@link summarizeChecks}, because GitHub counts it as met: the gated jobs skip
|
|
118
|
+
* on `skip-ci` and on a diff the workflow does not read, and reading that as a
|
|
119
|
+
* failure would call every gated pull request red.
|
|
120
120
|
* Everything else that finished — `cancelled`, `stale`, `timed_out`,
|
|
121
|
-
* `action_required` — is something a reader has to act on, so it is a
|
|
122
|
-
*
|
|
121
|
+
* `action_required` — is something a reader has to act on, so it is a failure
|
|
122
|
+
* here even where GitHub is vaguer about it.
|
|
123
123
|
*/
|
|
124
124
|
export const classifyCheckRun = (
|
|
125
125
|
status: string,
|
|
@@ -141,12 +141,12 @@ const PASSING_CONCLUSIONS: ReadonlySet<string> = new Set<string>([
|
|
|
141
141
|
/**
|
|
142
142
|
* Whether any run on the head commit has not finished, or any round has not.
|
|
143
143
|
*
|
|
144
|
-
* Every run, not only the required ones: the aggregates are `if: always()`
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
144
|
+
* Every run, not only the required ones: the aggregates are `if: always()` and
|
|
145
|
+
* have no run in the newest round until the jobs they wait on are done, so
|
|
146
|
+
* "every required context has reported" is true of a commit halfway through a
|
|
147
|
+
* round — with the reports coming from the round before. And the round, not
|
|
148
|
+
* only its runs: between the last job finishing and the aggregate being
|
|
149
|
+
* created, every run there is has completed.
|
|
150
150
|
*/
|
|
151
151
|
export const anyRunInProgress = (runs: readonly CheckRunReport[]): boolean =>
|
|
152
152
|
runs.some(
|
|
@@ -154,10 +154,10 @@ export const anyRunInProgress = (runs: readonly CheckRunReport[]): boolean =>
|
|
|
154
154
|
);
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
* What every context has reported on one commit, from both places GitHub
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
157
|
+
* What every context has reported on one commit, from both places GitHub keeps
|
|
158
|
+
* them. The aggregate jobs are check runs; `no-skip-ci-label` is a commit
|
|
159
|
+
* status, so reading only the first would report the context that holds every
|
|
160
|
+
* labelled pull request as missing.
|
|
161
161
|
*
|
|
162
162
|
* `state` is a commit status's as the REST API spells it, in lower case.
|
|
163
163
|
*/
|
|
@@ -165,9 +165,9 @@ export const reportedContexts = (
|
|
|
165
165
|
runs: readonly CheckRunReport[],
|
|
166
166
|
statuses: readonly Readonly<{ context: string; state: string }>[],
|
|
167
167
|
): ReadonlyMap<string, ContextState> => {
|
|
168
|
-
// A commit status and a check run of the same name are two requirements,
|
|
169
|
-
//
|
|
170
|
-
//
|
|
168
|
+
// A commit status and a check run of the same name are two requirements, not
|
|
169
|
+
// one reported twice: GitHub asks both to pass. So the stricter of the two is
|
|
170
|
+
// kept rather than whichever was read second.
|
|
171
171
|
const mut_states = new Map<string, ContextState>(statesFromCheckRuns(runs));
|
|
172
172
|
|
|
173
173
|
for (const { context, state } of statuses) {
|
|
@@ -189,12 +189,11 @@ export const reportedContexts = (
|
|
|
189
189
|
/**
|
|
190
190
|
* What a context reported that is both a check run and a commit status.
|
|
191
191
|
*
|
|
192
|
-
* Not "the status wins", which is what this used to assume. GitHub's own
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
* them ran.
|
|
192
|
+
* Not "the status wins", which is what this used to assume. GitHub's own answer
|
|
193
|
+
* is that neither does: "If a check and a commit status have the same name,
|
|
194
|
+
* both must pass when that name is required." So the stricter of the two is the
|
|
195
|
+
* verdict, and a green status cannot cover a red check run of the same name. A
|
|
196
|
+
* skip beside a pass is a skip: both are met, but only one of them ran.
|
|
198
197
|
*/
|
|
199
198
|
export const combineContextStates = (
|
|
200
199
|
a: ContextState,
|
|
@@ -210,8 +209,8 @@ export const combineContextStates = (
|
|
|
210
209
|
|
|
211
210
|
/**
|
|
212
211
|
* What one commit status has reported. `no-skip-ci-label` is one of these
|
|
213
|
-
* rather than a check run, so a report that read only check runs would call
|
|
214
|
-
*
|
|
212
|
+
* rather than a check run, so a report that read only check runs would call the
|
|
213
|
+
* context that holds every labelled pull request "missing".
|
|
215
214
|
*/
|
|
216
215
|
export const classifyCommitStatus = (state: string): ContextState => {
|
|
217
216
|
switch (state) {
|
|
@@ -231,24 +230,24 @@ export const classifyCommitStatus = (state: string): ContextState => {
|
|
|
231
230
|
* requires and no others: a failing job nothing requires does not block a
|
|
232
231
|
* merge, and listing it would bury the one that does.
|
|
233
232
|
*
|
|
234
|
-
* `paused` outranks the rest. While `skip-ci` is on, the checks a reader
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
233
|
+
* `paused` outranks the rest. While `skip-ci` is on, the checks a reader sees
|
|
234
|
+
* are whatever survived from before the label went on — typically the red left
|
|
235
|
+
* by the `opened` run that the `labeled` run cancelled. Calling that "failing"
|
|
236
|
+
* would make every queued pull request look broken; the failures are still
|
|
237
|
+
* listed, because they are what a reader asks about.
|
|
239
238
|
*
|
|
240
239
|
* `running` is the third thing that makes a verdict provisional, beside a
|
|
241
|
-
* required context that is pending and one that has not reported. Without it
|
|
242
|
-
*
|
|
243
|
-
*
|
|
240
|
+
* required context that is pending and one that has not reported. Without it a
|
|
241
|
+
* commit mid-round reads as settled out of the round before — which is how a
|
|
242
|
+
* failing pull request (#2031) came to show a tick.
|
|
244
243
|
*
|
|
245
244
|
* **Off the covered base, a context that never reported is not awaited.**
|
|
246
245
|
* The contexts are the ones the ruleset asks of `main`, and a workflow that
|
|
247
|
-
* runs only on pull requests into `main` never reports on a stacked one —
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
246
|
+
* runs only on pull requests into `main` never reports on a stacked one — which
|
|
247
|
+
* kept #2103, every check of it green, "running" until it was moved onto
|
|
248
|
+
* `main`. Such a context is {@link ChecksSummary.notRun} instead, but only once
|
|
249
|
+
* some required context has reported: before the first check suite, nothing
|
|
250
|
+
* having come is not a pass over zero contexts.
|
|
252
251
|
*/
|
|
253
252
|
export const summarizeChecks = ({
|
|
254
253
|
required,
|
package/src/checks.test.mts
CHANGED
|
@@ -17,11 +17,11 @@ describe(classifyCheckRun, () => {
|
|
|
17
17
|
assert.strictEqual(classifyCheckRun('in_progress', 'failure'), 'pending');
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
// The gated jobs skip on `skip-ci` and on a diff the workflow does not
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
20
|
+
// The gated jobs skip on `skip-ci` and on a diff the workflow does not read;
|
|
21
|
+
// GitHub counts that as met, so reading it as a failure would call every
|
|
22
|
+
// gated pull request red. `summarizeChecks` still counts it as met — but it
|
|
23
|
+
// is reported as what it was, because folding it into `passed` is what let a
|
|
24
|
+
// failing pull request show a tick.
|
|
25
25
|
test('a skipped job is reported as skipped, not as passed', () => {
|
|
26
26
|
assert.strictEqual(classifyCheckRun('completed', 'skipped'), 'skipped');
|
|
27
27
|
|
|
@@ -114,10 +114,9 @@ describe(summarizeChecks, () => {
|
|
|
114
114
|
|
|
115
115
|
test('`skip-ci` is a pause, and the detail is still reported', () => {
|
|
116
116
|
// While the label is on, the gated jobs boot no runner and
|
|
117
|
-
// `no-skip-ci-label` sits `pending` by design. Calling that "failing"
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
// asks about.
|
|
117
|
+
// `no-skip-ci-label` sits `pending` by design. Calling that "failing" would
|
|
118
|
+
// make every queued pull request look broken; the red left by the cancelled
|
|
119
|
+
// `opened` run is still listed, because it is what a reader asks about.
|
|
121
120
|
const summary = summarizeChecks({
|
|
122
121
|
required,
|
|
123
122
|
reported: new Map<string, ContextState>([
|
|
@@ -207,9 +206,9 @@ describe(summarizeChecks, () => {
|
|
|
207
206
|
});
|
|
208
207
|
|
|
209
208
|
// #2103, stacked on `chore/pnpm-update`: `lint-pull-request.yml` runs on
|
|
210
|
-
// pull requests into `main` only, so its three contexts never came, and
|
|
211
|
-
//
|
|
212
|
-
//
|
|
209
|
+
// pull requests into `main` only, so its three contexts never came, and the
|
|
210
|
+
// page kept calling a pull request whose checks had all passed "checks
|
|
211
|
+
// running".
|
|
213
212
|
describe('on a base the ruleset does not cover', () => {
|
|
214
213
|
const withLint = Arr.toPushed(required, 'Validate PR title');
|
|
215
214
|
|
|
@@ -235,8 +234,8 @@ describe(summarizeChecks, () => {
|
|
|
235
234
|
});
|
|
236
235
|
|
|
237
236
|
test('while nothing required has reported, everything is still coming', () => {
|
|
238
|
-
// Between a push and the first check suite, a head commit has nothing
|
|
239
|
-
//
|
|
237
|
+
// Between a push and the first check suite, a head commit has nothing on
|
|
238
|
+
// it at all; that is not a pass over zero contexts.
|
|
240
239
|
const summary = summarizeChecks({
|
|
241
240
|
required: withLint,
|
|
242
241
|
reported: new Map<string, ContextState>(),
|
|
@@ -331,8 +330,8 @@ describe(statesFromCheckRuns, () => {
|
|
|
331
330
|
// `test-node-versions-result`, the one context of the five that blocked
|
|
332
331
|
// #2021: the cancelled suite happens to have the greater id, so GitHub
|
|
333
332
|
// reports the failure however much later the green one finished. Reading
|
|
334
|
-
// the newest `started_at` instead would call this pull request green
|
|
335
|
-
//
|
|
333
|
+
// the newest `started_at` instead would call this pull request green while
|
|
334
|
+
// GitHub blocks it.
|
|
336
335
|
const states = statesFromCheckRuns([
|
|
337
336
|
run(
|
|
338
337
|
'test-node-versions-result / result',
|
|
@@ -496,11 +495,11 @@ describe(anyRunInProgress, () => {
|
|
|
496
495
|
* The state #2031 was in when the page showed it a tick.
|
|
497
496
|
*
|
|
498
497
|
* `skip-ci` came off, which started a new round. The old round's
|
|
499
|
-
* `code-check-result` had concluded `skipped` and was the only run of that
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* `
|
|
498
|
+
* `code-check-result` had concluded `skipped` and was the only run of that name
|
|
499
|
+
* on the commit — the new round's aggregate does not exist until the jobs it
|
|
500
|
+
* waits on are done. Folding `skipped` into `passed` then made the pull request
|
|
501
|
+
* look settled and green, two minutes before `code-check-result` concluded
|
|
502
|
+
* `failure`.
|
|
504
503
|
*/
|
|
505
504
|
describe('a required context in a superseded round', () => {
|
|
506
505
|
const required = [
|
|
@@ -607,9 +606,9 @@ describe('a required context in a superseded round', () => {
|
|
|
607
606
|
* `skip-ci` came off, which started a round, and `merge-queued` went on a
|
|
608
607
|
* minute later, which started another and cancelled the first — whose
|
|
609
608
|
* `*-result` aggregates, `if: always()` over cancelled `needs`, concluded
|
|
610
|
-
* `failure`. The newer round was still at its matrix, so its aggregates did
|
|
611
|
-
*
|
|
612
|
-
*
|
|
609
|
+
* `failure`. The newer round was still at its matrix, so its aggregates did not
|
|
610
|
+
* exist yet, and the red of the cancelled one was the only run of each name on
|
|
611
|
+
* the commit.
|
|
613
612
|
*/
|
|
614
613
|
describe('a required context whose workflow has a newer round running', () => {
|
|
615
614
|
const codeCheck = 359_266_435;
|
|
@@ -659,8 +658,8 @@ describe('a required context whose workflow has a newer round running', () => {
|
|
|
659
658
|
conclusion: undefined,
|
|
660
659
|
round: { workflowId: codeCheck, completed: false },
|
|
661
660
|
},
|
|
662
|
-
// Style Check has finished every job it has created, but the round is
|
|
663
|
-
//
|
|
661
|
+
// Style Check has finished every job it has created, but the round is not
|
|
662
|
+
// over: its aggregate is created only after that.
|
|
664
663
|
{
|
|
665
664
|
id: 114_375_644_790,
|
|
666
665
|
checkSuiteId: 103_247_840_622,
|
|
@@ -719,8 +718,8 @@ describe('a required context whose workflow has a newer round running', () => {
|
|
|
719
718
|
});
|
|
720
719
|
|
|
721
720
|
// The rule is not "an older round never counts": where the newer round
|
|
722
|
-
// finished without a run of that name, GitHub answers with the older run,
|
|
723
|
-
//
|
|
721
|
+
// finished without a run of that name, GitHub answers with the older run, and
|
|
722
|
+
// so does this.
|
|
724
723
|
test('a finished round that never ran the job does not hide the older run', () => {
|
|
725
724
|
const states = statesFromCheckRuns([
|
|
726
725
|
runs[0],
|
|
@@ -737,9 +736,9 @@ describe('a required context whose workflow has a newer round running', () => {
|
|
|
737
736
|
assert.strictEqual(states.get('code-check-result / result'), 'failed');
|
|
738
737
|
});
|
|
739
738
|
|
|
740
|
-
// Nor "the round still running wins": GitHub resolves a context to the
|
|
741
|
-
//
|
|
742
|
-
//
|
|
739
|
+
// Nor "the round still running wins": GitHub resolves a context to the suite
|
|
740
|
+
// with the greatest id, and where the cancelled one has it, its red holds the
|
|
741
|
+
// merge however the other round goes.
|
|
743
742
|
test('a cancelled round with the greater id still holds the merge', () => {
|
|
744
743
|
const states = statesFromCheckRuns([
|
|
745
744
|
{
|
package/src/claim.mts
CHANGED
|
@@ -4,25 +4,24 @@
|
|
|
4
4
|
*
|
|
5
5
|
* `unblock-prs` leaves a set-aside pull request alone until its head moves —
|
|
6
6
|
* or, for every reason but `checks-failed` and `awaiting-bypass`, until the
|
|
7
|
-
* base does, when it tries the rebase again. A session fixing that pull
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* that pull request to it.
|
|
7
|
+
* base does, when it tries the rebase again. A session fixing that pull request
|
|
8
|
+
* is then racing the script, and a second session, or the one that opened the
|
|
9
|
+
* pull request and is woken by the set-aside comment, may be fixing the same
|
|
10
|
+
* failure. The leases on every push keep any of them from overwriting another's
|
|
11
|
+
* work, but not from doing it twice. So whoever starts on one says so first in
|
|
12
|
+
* a comment whose first line is a hidden record this module writes and reads,
|
|
13
|
+
* and everyone else — the script included — leaves that pull request to it.
|
|
15
14
|
*
|
|
16
15
|
* **It lasts while the head is the one it claimed**, and for at most
|
|
17
16
|
* {@link CLAIM_LIFETIME_MINUTES}. The push that carries the fix moves the head
|
|
18
|
-
* and so ends the claim with nothing left to clean up; that push is what
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
17
|
+
* and so ends the claim with nothing left to clean up; that push is what hands
|
|
18
|
+
* the pull request back to the script, as it always was. The lifetime is for a
|
|
19
|
+
* claimant that stopped without pushing. A claimant that needs longer writes
|
|
20
|
+
* the claim again.
|
|
22
21
|
*
|
|
23
22
|
* **One comment per pull request, edited in place**, like the set-aside one;
|
|
24
|
-
* a claim that has ended is simply written over. Of several, the oldest is
|
|
25
|
-
*
|
|
23
|
+
* a claim that has ended is simply written over. Of several, the oldest is the
|
|
24
|
+
* one, so two claimants writing at once both read back the same answer.
|
|
26
25
|
*
|
|
27
26
|
* **Only the comments the reader's own account wrote count**, as for the
|
|
28
27
|
* set-aside comment (`set-aside.mts`): the repository is public. `by` is what
|
package/src/closing-issues.mts
CHANGED
|
@@ -19,15 +19,14 @@ export type ClosingIssueNode = Readonly<{
|
|
|
19
19
|
/**
|
|
20
20
|
* The closing issues that belong to `repo`, in GitHub's order.
|
|
21
21
|
*
|
|
22
|
-
* **Only this repository's.** A pull request can close an issue anywhere,
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* same line.
|
|
22
|
+
* **Only this repository's.** A pull request can close an issue anywhere, and a
|
|
23
|
+
* report lists each as `#N` — which for another repository's issue names a
|
|
24
|
+
* different issue of this one, and for a private repository's may put a title
|
|
25
|
+
* the report's reader cannot see into a report someone else reads. The body
|
|
26
|
+
* parser `pr-report` falls back on without a token draws the same line.
|
|
28
27
|
*
|
|
29
|
-
* `null` entries are skipped rather than rejected: one issue the token may
|
|
30
|
-
*
|
|
28
|
+
* `null` entries are skipped rather than rejected: one issue the token may not
|
|
29
|
+
* see is no reason to lose the rest.
|
|
31
30
|
*/
|
|
32
31
|
export const closingIssuesIn = (
|
|
33
32
|
repo: RepoRef,
|
|
@@ -55,21 +54,21 @@ export const closingIssuesIn = (
|
|
|
55
54
|
};
|
|
56
55
|
|
|
57
56
|
/**
|
|
58
|
-
* The issues of `repo` a pull request body closes by keyword, as GitHub
|
|
59
|
-
*
|
|
57
|
+
* The issues of `repo` a pull request body closes by keyword, as GitHub itself
|
|
58
|
+
* read the body: first appearance order, each once.
|
|
60
59
|
*
|
|
61
60
|
* **Read from GitHub's rendering, not from the text.** GitHub wraps each
|
|
62
|
-
* closing keyword it recognized in `<span class="issue-keyword">` and puts
|
|
63
|
-
*
|
|
64
|
-
* `closingIssuesReferences` does not: it links a keyword only on a pull
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
61
|
+
* closing keyword it recognized in `<span class="issue-keyword">` and puts the
|
|
62
|
+
* reference right after it, and it does so whatever the base branch.
|
|
63
|
+
* `closingIssuesReferences` does not: it links a keyword only on a pull request
|
|
64
|
+
* into the default branch, so a stacked one lists nothing until the layers
|
|
65
|
+
* below it merge. Which spellings count, whether a reference inside code or
|
|
66
|
+
* after a comma is closed, is GitHub's to decide, and this takes its decision
|
|
67
|
+
* rather than copying the grammar. A body cannot forge the mark:
|
|
69
68
|
* GitHub strips `class` from HTML written in one.
|
|
70
69
|
*
|
|
71
|
-
* A reference to another repository's issue, or to a pull request, is left
|
|
72
|
-
*
|
|
70
|
+
* A reference to another repository's issue, or to a pull request, is left out,
|
|
71
|
+
* for the reasons {@link closingIssuesIn} gives.
|
|
73
72
|
*/
|
|
74
73
|
export const closingKeywordIssuesIn = (
|
|
75
74
|
repo: RepoRef,
|