pr-report-core 0.2.1 → 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.
Files changed (49) hide show
  1. package/README.md +5 -2
  2. package/dist/branch-rules.d.mts +30 -0
  3. package/dist/branch-rules.d.mts.map +1 -0
  4. package/dist/branch-rules.mjs +71 -0
  5. package/dist/branch-rules.mjs.map +1 -0
  6. package/dist/claim.d.mts +15 -8
  7. package/dist/claim.d.mts.map +1 -1
  8. package/dist/claim.mjs +2 -1
  9. package/dist/claim.mjs.map +1 -1
  10. package/dist/index.d.mts +3 -0
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +3 -0
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/issue-claim.d.mts +56 -0
  15. package/dist/issue-claim.d.mts.map +1 -0
  16. package/dist/issue-claim.mjs +87 -0
  17. package/dist/issue-claim.mjs.map +1 -0
  18. package/dist/issue-priority.d.mts +44 -0
  19. package/dist/issue-priority.d.mts.map +1 -0
  20. package/dist/issue-priority.mjs +91 -0
  21. package/dist/issue-priority.mjs.map +1 -0
  22. package/dist/labels.d.mts +6 -3
  23. package/dist/labels.d.mts.map +1 -1
  24. package/dist/labels.mjs +3 -0
  25. package/dist/labels.mjs.map +1 -1
  26. package/dist/queue-owner.d.mts +1 -1
  27. package/dist/queue-owner.d.mts.map +1 -1
  28. package/dist/queue-owner.mjs +18 -0
  29. package/dist/queue-owner.mjs.map +1 -1
  30. package/dist/ruleset.d.mts +6 -6
  31. package/dist/set-aside.d.mts +2 -1
  32. package/dist/set-aside.d.mts.map +1 -1
  33. package/dist/set-aside.mjs +2 -0
  34. package/dist/set-aside.mjs.map +1 -1
  35. package/package.json +9 -9
  36. package/src/branch-rules.mts +105 -0
  37. package/src/branch-rules.test.mts +221 -0
  38. package/src/claim.mts +10 -9
  39. package/src/index.mts +3 -0
  40. package/src/issue-claim.mts +138 -0
  41. package/src/issue-claim.test.mts +149 -0
  42. package/src/issue-priority.mts +116 -0
  43. package/src/issue-priority.test.mts +71 -0
  44. package/src/labels.mts +6 -3
  45. package/src/queue-owner.mts +21 -0
  46. package/src/queue-owner.test.mts +2 -0
  47. package/src/ruleset.mts +6 -6
  48. package/src/set-aside.mts +3 -1
  49. package/src/set-aside.test.mts +22 -0
@@ -33,8 +33,11 @@ export const SET_ASIDE_REASONS = [
33
33
  'arm-failed',
34
34
  'awaiting-bypass',
35
35
  'checks-failed',
36
+ 'checks-not-started',
37
+ 'head-out-of-sync',
36
38
  'not-merging',
37
39
  'push-failed',
40
+ 'read-failed',
38
41
  'rebase-failed',
39
42
  'unlabel-failed',
40
43
  'watch-timeout',
@@ -143,11 +146,26 @@ const setAsideOwner = (reason) => {
143
146
  owner: 'human',
144
147
  why: 'green, and only a ruleset bypass merges it',
145
148
  };
149
+ case 'checks-not-started':
150
+ return {
151
+ owner: 'human',
152
+ why: 'GitHub started no run for a required check on its head; the base moving puts it back in the queue to be rebased in its turn, and a new commit pushed to the branch starts the checks sooner',
153
+ };
154
+ case 'head-out-of-sync':
155
+ return {
156
+ owner: 'human',
157
+ why: 'GitHub never took in the last push to its branch, so it still shows an older head; push to the branch again, or close and reopen it',
158
+ };
146
159
  case 'not-merging':
147
160
  return {
148
161
  owner: 'human',
149
162
  why: 'green but not merging; something the worker cannot read holds it',
150
163
  };
164
+ case 'read-failed':
165
+ return {
166
+ owner: 'human',
167
+ why: 'its checks or its base could not be read survey after survey; the comment says what failed',
168
+ };
151
169
  case 'push-failed':
152
170
  return {
153
171
  owner: 'human',
@@ -1 +1 @@
1
- {"version":3,"file":"queue-owner.mjs","sourceRoot":"","sources":["../src/queue-owner.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"queue-owner.mjs","sourceRoot":"","sources":["../src/queue-owner.mts"],"names":[],"mappings":"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"}
@@ -17,12 +17,12 @@ export type RulesetRequirements = Readonly<{
17
17
  /**
18
18
  * The requirements, read from the declaration rather than from GitHub, for
19
19
  * `pnpm run pr-report`, which reads the checkout. The file is the desired
20
- * state; what GitHub enforces is {@link requirementsOfRules} over
21
- * `rules/branches/{branch}`, which `unblock-prs` and the Pull Requests
22
- * Manager read and which wants no more than read access. The gap is that a file
23
- * under `repo-settings/` changes nothing until `pnpm run repo-settings:apply`
24
- * runs, so a context added here and not applied is reported as missing on every
25
- * pull request — which is a fair thing for a report to say out loud.
20
+ * state; what GitHub enforces is `readBranchRequirements`, which reads it for
21
+ * `unblock-prs`, the Pull Requests Manager and `pr-report` pointed elsewhere,
22
+ * and which wants no more than read access. The gap is that a file under
23
+ * `repo-settings/` changes nothing until `pnpm run repo-settings:apply` runs,
24
+ * so a context added here and not applied is reported as missing on every pull
25
+ * request — which is a fair thing for a report to say out loud.
26
26
  *
27
27
  * `source` names the file in the messages.
28
28
  */
@@ -93,7 +93,8 @@ export declare const setAsideApplies: (setAside: SetAside, headTip: string, base
93
93
  * more — except two whose head a rebase would only put through the same matrix
94
94
  * again: `checks-failed`, which the push that carries the fix clears, and
95
95
  * `awaiting-bypass`, green and waiting for a ruleset bypass merge, which does
96
- * not wait for the base.
96
+ * not wait for the base. Nor does `head-out-of-sync`: GitHub not having taken
97
+ * in the branch's last push is not something the base moving changes.
97
98
  */
98
99
  export declare const setAsideStillApplies: (setAside: Readonly<{
99
100
  reason: string;
@@ -1 +1 @@
1
- {"version":3,"file":"set-aside.d.mts","sourceRoot":"","sources":["../src/set-aside.mts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC9B,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAClC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAC3D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,aACrB,QAAQ,SACX,MAAM,KACZ,MAOW,CAAC;AAEf,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,UAAW,MAAM,KAAG,MACI,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,SACzB,MAAM,KACX,eAAe,GAAG,SAoCpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,aAChB,QAAQ,WACT,MAAM,WACN,MAAM,KACd,OACsE,CAAC;AAE1E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,aACrB,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,WAC9C,MAAM,KACd,OAG2B,CAAC"}
1
+ {"version":3,"file":"set-aside.d.mts","sourceRoot":"","sources":["../src/set-aside.mts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC9B,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAClC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAC3D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,aACrB,QAAQ,SACX,MAAM,KACZ,MAOW,CAAC;AAEf,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,UAAW,MAAM,KAAG,MACI,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,SACzB,MAAM,KACX,eAAe,GAAG,SAoCpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,aAChB,QAAQ,WACT,MAAM,WACN,MAAM,KACd,OACsE,CAAC;AAE1E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,aACrB,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,WAC9C,MAAM,KACd,OAI2B,CAAC"}
@@ -105,8 +105,10 @@ export const setAsideApplies = (setAside, headTip, baseTip) => setAside.headSha
105
105
 
106
106
 
107
107
 
108
+
108
109
  export const setAsideStillApplies = (setAside, baseTip) => setAside.reason === 'checks-failed' ||
109
110
  setAside.reason === 'awaiting-bypass' ||
111
+ setAside.reason === 'head-out-of-sync' ||
110
112
  setAside.baseSha === baseTip;
111
113
 
112
114
  const MARKER = '<!-- unblock-prs:set-aside';
@@ -1 +1 @@
1
- {"version":3,"file":"set-aside.mjs","sourceRoot":"","sources":["../src/set-aside.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"set-aside.mjs","sourceRoot":"","sources":["../src/set-aside.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.1",
3
+ "version": "0.3.0",
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": [
@@ -40,25 +40,25 @@
40
40
  ],
41
41
  "dependencies": {
42
42
  "ts-data-forge": "^14.11.0",
43
- "ts-fortress": "^12.4.3"
43
+ "ts-fortress": "^12.4.4"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@octokit/openapi-types": "^29.0.1",
47
47
  "@types/node": "26.6.5",
48
- "@vitest/coverage-v8": "5.0.5",
48
+ "@vitest/coverage-istanbul": "5.0.5",
49
49
  "cspell": "10.4.0",
50
50
  "dedent": "1.7.2",
51
51
  "eslint": "10.13.0",
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",
52
+ "eslint-config-typed": "7.5.0",
53
+ "eslint-plugin-ts-data-forge": "0.10.10",
54
+ "eslint-plugin-ts-fortress": "1.3.14",
55
+ "eslint-plugin-ts-type-forge": "0.8.19",
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.2",
61
+ "ts-repo-utils": "10.7.3",
62
62
  "tsx": "4.23.15",
63
63
  "typescript": "6.0.3",
64
64
  "typescript-native": "npm:typescript@7.0.2",
@@ -70,7 +70,7 @@
70
70
  "pnpm": ">=9.0.0"
71
71
  },
72
72
  "volta": {
73
- "node": "26.12.1"
73
+ "node": "26.13.0"
74
74
  },
75
75
  "publishConfig": {
76
76
  "access": "public",
@@ -0,0 +1,105 @@
1
+ /**
2
+ * What GitHub enforces on a branch, read the one way every reader reads it:
3
+ * every ruleset that applies to the branch
4
+ * (`GET /repos/{owner}/{repo}/rules/branches/{branch}`), and the contexts a
5
+ * classic branch protection rule requires
6
+ * (`GET /repos/{owner}/{repo}/branches/{branch}`). Neither wants more than
7
+ * reading the repository, where the endpoints that list a ruleset's own
8
+ * settings or a protection rule's whole want an admin.
9
+ *
10
+ * What a classic rule says about reviews is not among what the second answers,
11
+ * so a code owner's approval is waited for only where a ruleset asks for it.
12
+ *
13
+ * Nothing here talks to GitHub: the reader hands over its own way of asking.
14
+ */
15
+
16
+ import { Arr, Result } from 'ts-data-forge';
17
+ import * as t from 'ts-fortress';
18
+ import { requirementsOfRules, type RulesetRequirements } from './ruleset.mjs';
19
+
20
+ /**
21
+ * One `GET`, by the reader's own transport. `path` is relative to
22
+ * `/repos/{owner}/{repo}` and may carry a query string; `what` names the
23
+ * request for a message.
24
+ */
25
+ export type BranchRulesGet = <A>(
26
+ path: string,
27
+ schema: t.Type<A>,
28
+ what: string,
29
+ ) => Promise<Result<A, string>>;
30
+
31
+ /**
32
+ * The requirements on `branch`, or why they could not be read. Either request
33
+ * failing fails it: a list of required contexts missing half of them would be
34
+ * read as the whole.
35
+ */
36
+ export const readBranchRequirements = async (
37
+ branch: string,
38
+ get: BranchRulesGet,
39
+ ): Promise<Result<RulesetRequirements, string>> => {
40
+ // One path segment, whatever the name holds: `release/1.x` included. The
41
+ // rule's premise, building a query string, is not what this is.
42
+ // eslint-disable-next-line no-restricted-globals
43
+ const segment = encodeURIComponent(branch);
44
+
45
+ const [rules, branchAnswer] = await Promise.all([
46
+ get(
47
+ `/rules/branches/${segment}?per_page=${RULES_PER_PAGE}`,
48
+ RulesSchema,
49
+ `the rules on ${branch}`,
50
+ ),
51
+ get(`/branches/${segment}`, BranchSchema, `the protection of ${branch}`),
52
+ ]);
53
+
54
+ if (Result.isErr(rules)) {
55
+ return rules;
56
+ }
57
+
58
+ if (Result.isErr(branchAnswer)) {
59
+ return branchAnswer;
60
+ }
61
+
62
+ const fromRulesets = requirementsOfRules(rules.value);
63
+
64
+ const protection = branchAnswer.value.protection;
65
+
66
+ const classic =
67
+ protection?.enabled === false
68
+ ? undefined
69
+ : protection?.required_status_checks;
70
+
71
+ return Result.ok({
72
+ ...fromRulesets,
73
+ requiredContexts: Arr.uniq([
74
+ ...fromRulesets.requiredContexts,
75
+ // GitHub's description leaves the level out of what it promises, so one
76
+ // not given is taken as enforcing.
77
+ ...(classic === undefined || classic.enforcement_level === 'off'
78
+ ? []
79
+ : classic.contexts),
80
+ ]),
81
+ });
82
+ };
83
+
84
+ /**
85
+ * As many rules as a page holds; GitHub's default is 30. Each ruleset
86
+ * contributes a handful, so a branch with more than a hundred is not one a
87
+ * person keeps.
88
+ */
89
+ const RULES_PER_PAGE = 100;
90
+
91
+ const RulesSchema = t.array(t.unknown());
92
+
93
+ const BranchSchema = t.record({
94
+ protection: t.optional(
95
+ t.record({
96
+ enabled: t.optional(t.boolean()),
97
+ required_status_checks: t.optional(
98
+ t.record({
99
+ enforcement_level: t.optional(t.string()),
100
+ contexts: t.array(t.string()),
101
+ }),
102
+ ),
103
+ }),
104
+ ),
105
+ });
@@ -0,0 +1,221 @@
1
+ import { Result } from 'ts-data-forge';
2
+ import type * as t from 'ts-fortress';
3
+ import {
4
+ readBranchRequirements,
5
+ type BranchRulesGet,
6
+ } from './branch-rules.mjs';
7
+
8
+ describe(readBranchRequirements, () => {
9
+ test('adds up the rulesets on the branch and its classic protection', async () => {
10
+ const { get, asked } = answering({
11
+ rules: [
12
+ {
13
+ type: 'pull_request',
14
+ parameters: {
15
+ require_code_owner_review: true,
16
+ required_review_thread_resolution: false,
17
+ },
18
+ },
19
+ {
20
+ type: 'required_status_checks',
21
+ parameters: {
22
+ required_status_checks: [
23
+ { context: 'code-check-result / result' },
24
+ { context: 'lint' },
25
+ ],
26
+ },
27
+ },
28
+ { type: 'deletion' },
29
+ ],
30
+ branch: {
31
+ protection: {
32
+ enabled: true,
33
+ required_status_checks: {
34
+ enforcement_level: 'non_admins',
35
+ contexts: ['lint', 'build'],
36
+ },
37
+ },
38
+ },
39
+ });
40
+
41
+ const read = await readBranchRequirements('main', get);
42
+
43
+ assert.isTrue(Result.isOk(read));
44
+
45
+ assert.deepStrictEqual(read.value, {
46
+ requiredContexts: ['code-check-result / result', 'lint', 'build'],
47
+ requireCodeOwnerReview: true,
48
+ requireConversationResolution: false,
49
+ });
50
+
51
+ assert.deepStrictEqual(asked.toSorted(), [
52
+ '/branches/main',
53
+ '/rules/branches/main?per_page=100',
54
+ ]);
55
+ });
56
+
57
+ test('reads the contexts of a classic rule where no ruleset applies', async () => {
58
+ const { get } = answering({
59
+ rules: [],
60
+ branch: {
61
+ protection: {
62
+ enabled: true,
63
+ required_status_checks: {
64
+ enforcement_level: 'everyone',
65
+ contexts: ['build'],
66
+ },
67
+ },
68
+ },
69
+ });
70
+
71
+ const read = await readBranchRequirements('main', get);
72
+
73
+ assert.isTrue(Result.isOk(read));
74
+
75
+ assert.deepStrictEqual(read.value.requiredContexts, ['build']);
76
+ });
77
+
78
+ test('requires nothing of a branch nothing protects', async () => {
79
+ const { get } = answering({ rules: [], branch: { protection: {} } });
80
+
81
+ const read = await readBranchRequirements('main', get);
82
+
83
+ assert.isTrue(Result.isOk(read));
84
+
85
+ assert.deepStrictEqual(read.value, {
86
+ requiredContexts: [],
87
+ requireCodeOwnerReview: false,
88
+ requireConversationResolution: false,
89
+ });
90
+ });
91
+
92
+ test('reads no contexts off classic protection that is switched off', async () => {
93
+ const { get } = answering({
94
+ rules: [],
95
+ branch: {
96
+ protection: {
97
+ enabled: true,
98
+ required_status_checks: {
99
+ enforcement_level: 'off',
100
+ contexts: ['stale'],
101
+ },
102
+ },
103
+ },
104
+ });
105
+
106
+ const read = await readBranchRequirements('main', get);
107
+
108
+ assert.isTrue(Result.isOk(read));
109
+
110
+ assert.deepStrictEqual(read.value.requiredContexts, []);
111
+ });
112
+
113
+ test('reads no contexts off classic protection that is disabled', async () => {
114
+ const { get } = answering({
115
+ rules: [],
116
+ branch: {
117
+ protection: {
118
+ enabled: false,
119
+ required_status_checks: { contexts: ['stale'] },
120
+ },
121
+ },
122
+ });
123
+
124
+ const read = await readBranchRequirements('main', get);
125
+
126
+ assert.isTrue(Result.isOk(read));
127
+
128
+ assert.deepStrictEqual(read.value.requiredContexts, []);
129
+ });
130
+
131
+ test('puts the branch name in the path as one segment', async () => {
132
+ const { get, asked } = answering({ rules: [], branch: {} });
133
+
134
+ await readBranchRequirements('release/1.x', get);
135
+
136
+ assert.deepStrictEqual(asked.toSorted(), [
137
+ '/branches/release%2F1.x',
138
+ '/rules/branches/release%2F1.x?per_page=100',
139
+ ]);
140
+ });
141
+
142
+ test.each(['/rules/', '/branches/main'] as const)(
143
+ 'fails when %s fails',
144
+ async (failing) => {
145
+ const get: BranchRulesGet = (path, schema, what) =>
146
+ Promise.resolve(
147
+ path.startsWith(failing)
148
+ ? Result.err(`refused ${what}`)
149
+ : validated(schema, path.startsWith('/rules/') ? [] : {}),
150
+ );
151
+
152
+ const read = await readBranchRequirements('main', get);
153
+
154
+ assert.isTrue(Result.isErr(read));
155
+
156
+ assert.include(read.value, 'main');
157
+ },
158
+ );
159
+
160
+ test('fails on rules of another shape', async () => {
161
+ const { get } = answering({ rules: { rules: [] }, branch: {} });
162
+
163
+ const read = await readBranchRequirements('main', get);
164
+
165
+ assert.isTrue(Result.isErr(read));
166
+ });
167
+
168
+ test('fails on protection of another shape', async () => {
169
+ const { get } = answering({
170
+ rules: [],
171
+ branch: { protection: { required_status_checks: { contexts: 'build' } } },
172
+ });
173
+
174
+ const read = await readBranchRequirements('main', get);
175
+
176
+ assert.isTrue(Result.isErr(read));
177
+ });
178
+
179
+ test('takes a classic rule that names no level as enforcing', async () => {
180
+ const { get } = answering({
181
+ rules: [],
182
+ branch: {
183
+ protection: { required_status_checks: { contexts: ['build'] } },
184
+ },
185
+ });
186
+
187
+ const read = await readBranchRequirements('main', get);
188
+
189
+ assert.isTrue(Result.isOk(read));
190
+
191
+ assert.deepStrictEqual(read.value.requiredContexts, ['build']);
192
+ });
193
+ });
194
+
195
+ const validated = <A,>(schema: t.Type<A>, body: unknown): Result<A, string> => {
196
+ const checked = schema.validate(body);
197
+
198
+ return Result.isErr(checked)
199
+ ? Result.err('not the shape expected')
200
+ : Result.ok(checked.value);
201
+ };
202
+
203
+ /** A `get` answering the two paths with the bodies given. */
204
+ const answering = (
205
+ bodies: Readonly<{ rules: unknown; branch: unknown }>,
206
+ ): Readonly<{ get: BranchRulesGet; asked: readonly string[] }> => {
207
+ const mut_asked: string[] = [];
208
+
209
+ const get: BranchRulesGet = (path, schema) => {
210
+ mut_asked.push(path);
211
+
212
+ return Promise.resolve(
213
+ validated(
214
+ schema,
215
+ path.startsWith('/rules/') ? bodies.rules : bodies.branch,
216
+ ),
217
+ );
218
+ };
219
+
220
+ return { get, asked: mut_asked };
221
+ };
package/src/claim.mts CHANGED
@@ -3,14 +3,15 @@
3
3
  * writer of the queue can read it.
4
4
  *
5
5
  * `unblock-prs` leaves a set-aside pull request alone until its head moves —
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 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.
6
+ * or, for every reason but `checks-failed`, `awaiting-bypass` and
7
+ * `head-out-of-sync`, until the base does, when it tries the rebase again. A
8
+ * session fixing that pull request is then racing the script, and a second
9
+ * session, or the one that opened the pull request and is woken by the
10
+ * set-aside comment, may be fixing the same failure. The leases on every push
11
+ * keep any of them from overwriting another's work, but not from doing it
12
+ * twice. So whoever starts on one says so first in a comment whose first line
13
+ * is a hidden record this module writes and reads, and everyone else — the
14
+ * script included — leaves that pull request to it.
14
15
  *
15
16
  * **It lasts while the head is the one it claimed**, and for at most
16
17
  * {@link CLAIM_LIFETIME_MINUTES}. The push that carries the fix moves the head
@@ -113,7 +114,7 @@ export const claimApplies = (
113
114
  * Further than that is a clock that would otherwise stretch the lifetime by
114
115
  * however far ahead it ran.
115
116
  */
116
- const CLOCK_SKEW_MINUTES = 5;
117
+ export const CLOCK_SKEW_MINUTES = 5;
117
118
 
118
119
  const MS_PER_MINUTE = 60_000;
119
120
 
package/src/index.mts CHANGED
@@ -1,7 +1,10 @@
1
+ export * from './branch-rules.mjs';
1
2
  export * from './checks.mjs';
2
3
  export * from './claim.mjs';
3
4
  export * from './closing-issues.mjs';
4
5
  export * from './code-owners.mjs';
6
+ export * from './issue-claim.mjs';
7
+ export * from './issue-priority.mjs';
5
8
  export * from './labels.mjs';
6
9
  export * from './merge-after.mjs';
7
10
  export * from './queue-comments.mjs';