pr-report-core 0.2.0 → 0.3.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/README.md +5 -2
- package/dist/branch-rules.d.mts +30 -0
- package/dist/branch-rules.d.mts.map +1 -0
- package/dist/branch-rules.mjs +71 -0
- package/dist/branch-rules.mjs.map +1 -0
- 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 +21 -15
- package/dist/claim.d.mts.map +1 -1
- package/dist/claim.mjs +1 -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/index.d.mts +3 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/dist/issue-claim.d.mts +56 -0
- package/dist/issue-claim.d.mts.map +1 -0
- package/dist/issue-claim.mjs +87 -0
- package/dist/issue-claim.mjs.map +1 -0
- package/dist/issue-priority.d.mts +44 -0
- package/dist/issue-priority.d.mts.map +1 -0
- package/dist/issue-priority.mjs +91 -0
- package/dist/issue-priority.mjs.map +1 -0
- package/dist/labels.d.mts +43 -42
- package/dist/labels.d.mts.map +1 -1
- package/dist/labels.mjs +2 -1
- 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 +14 -14
- package/dist/queue-owner.d.mts.map +1 -1
- package/dist/queue-owner.mjs +18 -0
- 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 +12 -13
- 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 +29 -28
- package/dist/set-aside.d.mts.map +1 -1
- package/dist/set-aside.mjs +2 -0
- package/dist/set-aside.mjs.map +1 -1
- 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 +10 -10
- package/src/branch-rules.mts +105 -0
- package/src/branch-rules.test.mts +221 -0
- package/src/checks.mts +64 -65
- package/src/checks.test.mts +30 -31
- package/src/claim.mts +16 -16
- package/src/closing-issues.mts +18 -19
- package/src/closing-issues.test.mts +2 -2
- package/src/code-owners.mts +39 -41
- package/src/index.mts +3 -0
- package/src/issue-claim.mts +138 -0
- package/src/issue-claim.test.mts +149 -0
- package/src/issue-priority.mts +116 -0
- package/src/issue-priority.test.mts +71 -0
- package/src/labels.mts +43 -42
- 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 +46 -25
- package/src/queue-owner.test.mts +4 -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 +12 -13
- package/src/set-aside.mts +30 -28
- package/src/set-aside.test.mts +22 -0
- 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/src/start-after.mts
CHANGED
|
@@ -82,9 +82,9 @@ export const progressOf = (
|
|
|
82
82
|
: 'none';
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Whether `labels` holds `name`, whatever its case. GitHub's label names
|
|
86
|
-
*
|
|
87
|
-
*
|
|
85
|
+
* Whether `labels` holds `name`, whatever its case. GitHub's label names are:
|
|
86
|
+
* adding `in-progress` to a repository that has `In-Progress` puts that one on,
|
|
87
|
+
* so an exact match would not see the label it just added.
|
|
88
88
|
*/
|
|
89
89
|
export const hasLabel = (
|
|
90
90
|
labels: readonly Readonly<{ name: string }>[],
|
|
@@ -114,9 +114,9 @@ export const issuesInProgress = (
|
|
|
114
114
|
);
|
|
115
115
|
|
|
116
116
|
/**
|
|
117
|
-
* What GitHub says about a numbered item, in the terms both of its APIs
|
|
118
|
-
*
|
|
119
|
-
* `
|
|
117
|
+
* What GitHub says about a numbered item, in the terms both of its APIs share
|
|
118
|
+
* once lower-cased: GraphQL's `CLOSED` / `NOT_PLANNED` are REST's `closed` /
|
|
119
|
+
* `not_planned`.
|
|
120
120
|
*/
|
|
121
121
|
export type ReferencedFacts = Readonly<
|
|
122
122
|
| {
|
|
@@ -129,9 +129,8 @@ export type ReferencedFacts = Readonly<
|
|
|
129
129
|
>;
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
* Where one named item stands. An issue closed with no reason recorded is
|
|
133
|
-
*
|
|
134
|
-
* existed.
|
|
132
|
+
* Where one named item stands. An issue closed with no reason recorded is taken
|
|
133
|
+
* as completed, which was the only way to close one before reasons existed.
|
|
135
134
|
*/
|
|
136
135
|
export const referenceStatusOf = (facts: ReferencedFacts): ReferenceStatus => {
|
|
137
136
|
if (facts.state.toLowerCase() === 'open') {
|
|
@@ -152,9 +151,9 @@ export const referenceStatusOf = (facts: ReferencedFacts): ReferenceStatus => {
|
|
|
152
151
|
*
|
|
153
152
|
* `statusOf` says where each named number stands; the open issues among
|
|
154
153
|
* `issues` are `waiting` whatever it says, so a caller need only know about
|
|
155
|
-
* what is not in the list. Cycles are found among the declarations of
|
|
156
|
-
*
|
|
157
|
-
*
|
|
154
|
+
* what is not in the list. Cycles are found among the declarations of `issues`
|
|
155
|
+
* alone: a pull request declares no `Start-After:`, and the body of an issue
|
|
156
|
+
* that is not listed was not read.
|
|
158
157
|
*
|
|
159
158
|
* Nothing is transitive: an issue that names an open one is blocked whatever
|
|
160
159
|
* that one is waiting for in turn.
|
|
@@ -202,15 +201,15 @@ export const decideStartStates = (
|
|
|
202
201
|
*/
|
|
203
202
|
export type InheritedOrder = Readonly<{
|
|
204
203
|
/**
|
|
205
|
-
* The open pull requests it merges after because of them, as if its body
|
|
206
|
-
*
|
|
207
|
-
*
|
|
204
|
+
* The open pull requests it merges after because of them, as if its body had
|
|
205
|
+
* declared them: one an issue names, or one closing an open issue an issue
|
|
206
|
+
* names. Lowest number first, and never itself.
|
|
208
207
|
*/
|
|
209
208
|
mergeAfter: readonly number[];
|
|
210
209
|
/**
|
|
211
|
-
* The open issues named that no open pull request closes. They hold
|
|
212
|
-
*
|
|
213
|
-
*
|
|
210
|
+
* The open issues named that no open pull request closes. They hold nothing —
|
|
211
|
+
* waiting on work nobody has started could hold the merge for ever — but they
|
|
212
|
+
* are not done, and a reader is told so. Lowest first.
|
|
214
213
|
*/
|
|
215
214
|
notStarted: readonly number[];
|
|
216
215
|
}>;
|
|
@@ -219,9 +218,9 @@ export type InheritedOrder = Readonly<{
|
|
|
219
218
|
* Each open pull request's {@link InheritedOrder}, keyed by its number.
|
|
220
219
|
*
|
|
221
220
|
* `closes` is the open issues each closes, by closing keyword or by GitHub's
|
|
222
|
-
* own link; `startAfterOf` what each issue whose body was read declares, and
|
|
223
|
-
*
|
|
224
|
-
*
|
|
221
|
+
* own link; `startAfterOf` what each issue whose body was read declares, and an
|
|
222
|
+
* issue missing from it declares nothing. `openIssues` is what is known to be
|
|
223
|
+
* an open issue, which only decides what is reported as
|
|
225
224
|
* {@link InheritedOrder.notStarted}: anything named that is neither an open
|
|
226
225
|
* pull request nor an open issue — merged, closed, unknown — constrains
|
|
227
226
|
* nothing, since the issue's own start state is what asks for it to be looked
|
package/src/summarize.mts
CHANGED
|
@@ -8,8 +8,8 @@ import type { ReportEntry, Summary } from './types.mjs';
|
|
|
8
8
|
*
|
|
9
9
|
* Here rather than in whoever displays it. Two of these are questions this
|
|
10
10
|
* repository's conventions answer — `queued` is a label, and `failing` is the
|
|
11
|
-
* verdict reached over the contexts the ruleset requires — and both
|
|
12
|
-
*
|
|
11
|
+
* verdict reached over the contexts the ruleset requires — and both `pr-report`
|
|
12
|
+
* and the Pull Requests Manager page lead with them.
|
|
13
13
|
*/
|
|
14
14
|
export const summarize = (entries: readonly ReportEntry[]): Summary => {
|
|
15
15
|
const count = (predicate: (entry: ReportEntry) => boolean): number =>
|
package/src/timestamp.mts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GitHub's timestamps, as the numbers the page and the claims
|
|
3
|
-
*
|
|
2
|
+
* GitHub's timestamps, as the numbers the page and the claims (`claim.mts`) do
|
|
3
|
+
* arithmetic with.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { Arr, Num, Result } from 'ts-data-forge';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Milliseconds since the epoch, or `undefined` for a string that is not
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Milliseconds since the epoch, or `undefined` for a string that is not the one
|
|
10
|
+
* shape GitHub sends: `2026-09-24T09:39:18Z`, UTC, sometimes with a fraction of
|
|
11
|
+
* a second.
|
|
12
12
|
*
|
|
13
|
-
* Counted out field by field rather than handed to `Date`, whose parse is
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* Counted out field by field rather than handed to `Date`, whose parse is left
|
|
14
|
+
* to the engine for anything but the exact format ECMAScript defines and whose
|
|
15
|
+
* months count from zero, and rather than to `Temporal`, which not every
|
|
16
|
+
* browser the page may be opened in has yet, nor every Node.js version this
|
|
17
|
+
* package is tested on.
|
|
18
18
|
*/
|
|
19
19
|
export const epochMsOf = (timestamp: string): number | undefined => {
|
|
20
20
|
if (!timestamp.endsWith('Z')) {
|
|
@@ -65,10 +65,10 @@ const SECONDS_PER_HOUR = 3600;
|
|
|
65
65
|
const SECONDS_PER_DAY = 86_400;
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* Days from 1970-01-01 to a date of the proleptic Gregorian calendar, with
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
68
|
+
* Days from 1970-01-01 to a date of the proleptic Gregorian calendar, with the
|
|
69
|
+
* month counted from 1. Howard Hinnant's `days_from_civil`: the year is taken
|
|
70
|
+
* to start in March, so the leap day falls at its end and every month before it
|
|
71
|
+
* has a fixed length.
|
|
72
72
|
*/
|
|
73
73
|
const daysFromCivil = (year: number, month: number, day: number): number => {
|
|
74
74
|
const marchYear = month <= 2 ? year - 1 : year;
|
package/src/tree.mts
CHANGED
|
@@ -22,11 +22,11 @@ export type Forest = Readonly<{
|
|
|
22
22
|
* nothing and is dropped — the pull request it named has merged, which is
|
|
23
23
|
* exactly the constraint being satisfied.
|
|
24
24
|
*
|
|
25
|
-
* Two things a forest cannot hold are handled rather than drawn. A pull
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
25
|
+
* Two things a forest cannot hold are handled rather than drawn. A pull request
|
|
26
|
+
* that declared several predecessors appears under each of them, but is
|
|
27
|
+
* expanded under the first only ({@link TreeNode.repeated} marks the rest), so
|
|
28
|
+
* a diamond does not duplicate everything below it. A pull request on a cycle
|
|
29
|
+
* is left out altogether and reported through {@link Forest.cycles}:
|
|
30
30
|
* every member of a cycle waits, in the end, for itself, so there is no
|
|
31
31
|
* position in a merge order to draw it at.
|
|
32
32
|
*/
|
package/src/types.mts
CHANGED
|
@@ -14,23 +14,22 @@ export type RepoRef = Readonly<{ owner: string; name: string }>;
|
|
|
14
14
|
* What one context has reported on a head commit.
|
|
15
15
|
*
|
|
16
16
|
* `skipped` is its own state rather than a kind of `passed`. GitHub counts a
|
|
17
|
-
* skip as met, and so does the verdict — but once the two are one word a
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* skip as met, and so does the verdict — but once the two are one word a reader
|
|
18
|
+
* cannot tell them apart, and the aggregate that skipped may be from a round
|
|
19
|
+
* that was superseded by one about to fail.
|
|
20
20
|
*/
|
|
21
21
|
export type ContextState = 'failed' | 'passed' | 'pending' | 'skipped';
|
|
22
22
|
|
|
23
23
|
export type ChecksSummary = Readonly<{
|
|
24
24
|
/**
|
|
25
|
-
* `paused` is `skip-ci`: the gated jobs boot no runner and
|
|
26
|
-
*
|
|
27
|
-
* "failing" describes it.
|
|
25
|
+
* `paused` is `skip-ci`: the gated jobs boot no runner and `no-skip-ci-label`
|
|
26
|
+
* sits `pending` by design, so neither "pending" nor "failing" describes it.
|
|
28
27
|
*/
|
|
29
28
|
verdict: 'failing' | 'passed' | 'paused' | 'pending';
|
|
30
29
|
/**
|
|
31
30
|
* Every required context by what it reported. These four,
|
|
32
|
-
* {@link ChecksSummary.missing} and {@link ChecksSummary.notRun} are
|
|
33
|
-
*
|
|
31
|
+
* {@link ChecksSummary.missing} and {@link ChecksSummary.notRun} are disjoint
|
|
32
|
+
* and cover the required list.
|
|
34
33
|
*/
|
|
35
34
|
passed: readonly string[];
|
|
36
35
|
failed: readonly string[];
|
|
@@ -44,9 +43,9 @@ export type ChecksSummary = Readonly<{
|
|
|
44
43
|
missing: readonly string[];
|
|
45
44
|
/**
|
|
46
45
|
* Required contexts with nothing reported, on a pull request whose base the
|
|
47
|
-
* ruleset does not cover — a stacked one. A workflow may run on pull
|
|
48
|
-
*
|
|
49
|
-
*
|
|
46
|
+
* ruleset does not cover — a stacked one. A workflow may run on pull requests
|
|
47
|
+
* into `main` only, and then its contexts never come here; nothing waits for
|
|
48
|
+
* them, since GitHub requires nothing of this base either.
|
|
50
49
|
*/
|
|
51
50
|
notRun: readonly string[];
|
|
52
51
|
/** How many contexts the verdict was reached over. */
|
|
@@ -86,28 +85,28 @@ export type PullRequestFacts = Readonly<{
|
|
|
86
85
|
labels: readonly Label[];
|
|
87
86
|
/**
|
|
88
87
|
* Whether auto-merge is armed. Separate from `merge-queued`, which is the
|
|
89
|
-
* author saying a pull request is to be landed: the label is the request
|
|
90
|
-
*
|
|
91
|
-
*
|
|
88
|
+
* author saying a pull request is to be landed: the label is the request and
|
|
89
|
+
* this is the mechanism, which `unblock-prs` arms when it picks the pull
|
|
90
|
+
* request.
|
|
92
91
|
*/
|
|
93
92
|
autoMerge: boolean;
|
|
94
93
|
headRef: string;
|
|
95
94
|
headSha: string;
|
|
96
95
|
baseRef: string;
|
|
97
96
|
/**
|
|
98
|
-
* Whether the head branch lives in a fork, which keeps it from being read
|
|
99
|
-
*
|
|
97
|
+
* Whether the head branch lives in a fork, which keeps it from being read as
|
|
98
|
+
* the parent of a stacked pull request. See `stack.mts`.
|
|
100
99
|
*/
|
|
101
100
|
fromFork: boolean;
|
|
102
101
|
url: string;
|
|
103
102
|
/**
|
|
104
|
-
* When anything about the pull request last changed — a label, a comment,
|
|
105
|
-
*
|
|
103
|
+
* When anything about the pull request last changed — a label, a comment, an
|
|
104
|
+
* edit — which is why it is not {@link PullRequestFacts.headCommittedAt}.
|
|
106
105
|
*/
|
|
107
106
|
updatedAt: string;
|
|
108
107
|
/**
|
|
109
|
-
* When the head commit was made, which is when the branch was last pushed
|
|
110
|
-
*
|
|
108
|
+
* When the head commit was made, which is when the branch was last pushed to
|
|
109
|
+
* as nearly as GitHub records it. Undefined when it could not be read.
|
|
111
110
|
*/
|
|
112
111
|
headCommittedAt: string | undefined;
|
|
113
112
|
/** Undefined when the comparison could not be read. */
|
|
@@ -115,8 +114,8 @@ export type PullRequestFacts = Readonly<{
|
|
|
115
114
|
/** What every context reported on the head commit, required or not. */
|
|
116
115
|
reported: ReadonlyMap<string, ContextState>;
|
|
117
116
|
/**
|
|
118
|
-
* Whether any check run on the head commit has not finished, required or
|
|
119
|
-
*
|
|
117
|
+
* Whether any check run on the head commit has not finished, required or not.
|
|
118
|
+
* See `anyRunInProgress` for why the required ones are not enough.
|
|
120
119
|
*/
|
|
121
120
|
checksRunning: boolean;
|
|
122
121
|
linkedIssues: readonly LinkedIssue[];
|
|
@@ -132,8 +131,8 @@ export type ReportEntry = PullRequestFacts &
|
|
|
132
131
|
*/
|
|
133
132
|
stackedOn: number | undefined;
|
|
134
133
|
/**
|
|
135
|
-
* The open pull requests it merges after because an issue it closes
|
|
136
|
-
*
|
|
134
|
+
* The open pull requests it merges after because an issue it closes starts
|
|
135
|
+
* after them (`start-after.mts`'s `inheritStartAfter`), less what
|
|
137
136
|
* `mergeAfter` and `stackedOn` already say.
|
|
138
137
|
*/
|
|
139
138
|
inheritedMergeAfter: readonly number[];
|
|
@@ -153,9 +152,9 @@ export type ReportEntry = PullRequestFacts &
|
|
|
153
152
|
|
|
154
153
|
/**
|
|
155
154
|
* One pull request in the merge order. `repeated` marks the second and later
|
|
156
|
-
* appearances of a pull request with more than one predecessor — declared,
|
|
157
|
-
*
|
|
158
|
-
*
|
|
155
|
+
* appearances of a pull request with more than one predecessor — declared, or
|
|
156
|
+
* the one it is stacked on: it is drawn under each of them, but expanded under
|
|
157
|
+
* the first only.
|
|
159
158
|
*/
|
|
160
159
|
export type TreeNode = Readonly<{
|
|
161
160
|
number: number;
|
|
@@ -166,8 +165,8 @@ export type TreeNode = Readonly<{
|
|
|
166
165
|
/**
|
|
167
166
|
* One pull request that has already landed, for the section that says what
|
|
168
167
|
* shipped. Nothing that is true of an open pull request — a merge order, a
|
|
169
|
-
* check verdict, a distance from its base — is true of one that has merged,
|
|
170
|
-
*
|
|
168
|
+
* check verdict, a distance from its base — is true of one that has merged, so
|
|
169
|
+
* it is its own shape rather than an entry with the fields blanked.
|
|
171
170
|
*/
|
|
172
171
|
export type MergedPullRequest = Readonly<{
|
|
173
172
|
number: number;
|
|
@@ -202,8 +201,8 @@ export type OpenIssue = Readonly<{
|
|
|
202
201
|
*/
|
|
203
202
|
startAfter: readonly number[];
|
|
204
203
|
/**
|
|
205
|
-
* What a `Merge-After:` in its body names. That line is not read on an
|
|
206
|
-
*
|
|
204
|
+
* What a `Merge-After:` in its body names. That line is not read on an issue,
|
|
205
|
+
* and is shown as a slip to fix: `Start-After:` is the issue's.
|
|
207
206
|
*/
|
|
208
207
|
misplacedMergeAfter: readonly number[];
|
|
209
208
|
}>;
|
|
@@ -224,8 +223,8 @@ export type IssueDeclarations = Readonly<{
|
|
|
224
223
|
/** Each issue's `Start-After:`; an issue not in it declares nothing. */
|
|
225
224
|
startAfter: ReadonlyMap<number, readonly number[]>;
|
|
226
225
|
/**
|
|
227
|
-
* The numbers known to be open issues, beyond the ones an open pull
|
|
228
|
-
*
|
|
226
|
+
* The numbers known to be open issues, beyond the ones an open pull request
|
|
227
|
+
* links as open. Decides only what is said not to be started.
|
|
229
228
|
*/
|
|
230
229
|
open: ReadonlySet<number>;
|
|
231
230
|
}>;
|