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.
Files changed (331) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +125 -2
  3. package/dist/claim-pr/claim-pr.d.mts +45 -0
  4. package/dist/claim-pr/claim-pr.d.mts.map +1 -0
  5. package/dist/claim-pr/claim-pr.mjs +217 -0
  6. package/dist/claim-pr/claim-pr.mjs.map +1 -0
  7. package/dist/claim-pr/index.d.mts +2 -0
  8. package/dist/claim-pr/index.d.mts.map +1 -0
  9. package/dist/claim-pr/index.mjs +2 -0
  10. package/dist/claim-pr/index.mjs.map +1 -0
  11. package/dist/cmd/claim-pr.d.mts +3 -0
  12. package/dist/cmd/claim-pr.d.mts.map +1 -0
  13. package/dist/cmd/claim-pr.mjs +20 -0
  14. package/dist/cmd/claim-pr.mjs.map +1 -0
  15. package/dist/cmd/open-pr.d.mts +3 -0
  16. package/dist/cmd/open-pr.d.mts.map +1 -0
  17. package/dist/cmd/open-pr.mjs +20 -0
  18. package/dist/cmd/open-pr.mjs.map +1 -0
  19. package/dist/cmd/pr-report.d.mts +3 -0
  20. package/dist/cmd/pr-report.d.mts.map +1 -0
  21. package/dist/cmd/pr-report.mjs +20 -0
  22. package/dist/cmd/pr-report.mjs.map +1 -0
  23. package/dist/cmd/push-fixed-pr.d.mts +3 -0
  24. package/dist/cmd/push-fixed-pr.d.mts.map +1 -0
  25. package/dist/cmd/push-fixed-pr.mjs +20 -0
  26. package/dist/cmd/push-fixed-pr.mjs.map +1 -0
  27. package/dist/cmd/report-unowned-prs.d.mts +3 -0
  28. package/dist/cmd/report-unowned-prs.d.mts.map +1 -0
  29. package/dist/cmd/report-unowned-prs.mjs +20 -0
  30. package/dist/cmd/report-unowned-prs.mjs.map +1 -0
  31. package/dist/cmd/unblock-prs.d.mts +3 -0
  32. package/dist/cmd/unblock-prs.d.mts.map +1 -0
  33. package/dist/cmd/unblock-prs.mjs +19 -0
  34. package/dist/cmd/unblock-prs.mjs.map +1 -0
  35. package/dist/entry-point.d.mts +3 -0
  36. package/dist/entry-point.d.mts.map +1 -0
  37. package/dist/entry-point.mjs +3 -0
  38. package/dist/entry-point.mjs.map +1 -0
  39. package/dist/lib/cli-args.d.mts +27 -0
  40. package/dist/lib/cli-args.d.mts.map +1 -0
  41. package/dist/lib/cli-args.mjs +55 -0
  42. package/dist/lib/cli-args.mjs.map +1 -0
  43. package/dist/lib/github-api.d.mts +153 -0
  44. package/dist/lib/github-api.d.mts.map +1 -0
  45. package/dist/lib/github-api.mjs +291 -0
  46. package/dist/lib/github-api.mjs.map +1 -0
  47. package/dist/lib/index.d.mts +7 -0
  48. package/dist/lib/index.d.mts.map +1 -0
  49. package/dist/lib/index.mjs +7 -0
  50. package/dist/lib/index.mjs.map +1 -0
  51. package/dist/lib/json.d.mts +12 -0
  52. package/dist/lib/json.d.mts.map +1 -0
  53. package/dist/lib/json.mjs +28 -0
  54. package/dist/lib/json.mjs.map +1 -0
  55. package/dist/lib/log.d.mts +10 -0
  56. package/dist/lib/log.d.mts.map +1 -0
  57. package/dist/lib/log.mjs +13 -0
  58. package/dist/lib/log.mjs.map +1 -0
  59. package/dist/lib/shell.d.mts +18 -0
  60. package/dist/lib/shell.d.mts.map +1 -0
  61. package/dist/lib/shell.mjs +42 -0
  62. package/dist/lib/shell.mjs.map +1 -0
  63. package/dist/lib/time.d.mts +17 -0
  64. package/dist/lib/time.d.mts.map +1 -0
  65. package/dist/lib/time.mjs +35 -0
  66. package/dist/lib/time.mjs.map +1 -0
  67. package/dist/open-pr/github.d.mts +72 -0
  68. package/dist/open-pr/github.d.mts.map +1 -0
  69. package/dist/open-pr/github.mjs +249 -0
  70. package/dist/open-pr/github.mjs.map +1 -0
  71. package/dist/open-pr/index.d.mts +6 -0
  72. package/dist/open-pr/index.d.mts.map +1 -0
  73. package/dist/open-pr/index.mjs +6 -0
  74. package/dist/open-pr/index.mjs.map +1 -0
  75. package/dist/open-pr/main.d.mts +36 -0
  76. package/dist/open-pr/main.d.mts.map +1 -0
  77. package/dist/open-pr/main.mjs +204 -0
  78. package/dist/open-pr/main.mjs.map +1 -0
  79. package/dist/open-pr/options.d.mts +20 -0
  80. package/dist/open-pr/options.d.mts.map +1 -0
  81. package/dist/open-pr/options.mjs +66 -0
  82. package/dist/open-pr/options.mjs.map +1 -0
  83. package/dist/open-pr/steps.d.mts +23 -0
  84. package/dist/open-pr/steps.d.mts.map +1 -0
  85. package/dist/open-pr/steps.mjs +38 -0
  86. package/dist/open-pr/steps.mjs.map +1 -0
  87. package/dist/open-pr/types.d.mts +179 -0
  88. package/dist/open-pr/types.d.mts.map +1 -0
  89. package/dist/open-pr/types.mjs +20 -0
  90. package/dist/open-pr/types.mjs.map +1 -0
  91. package/dist/pr-report/github.d.mts +59 -0
  92. package/dist/pr-report/github.d.mts.map +1 -0
  93. package/dist/pr-report/github.mjs +561 -0
  94. package/dist/pr-report/github.mjs.map +1 -0
  95. package/dist/pr-report/index.d.mts +8 -0
  96. package/dist/pr-report/index.d.mts.map +1 -0
  97. package/dist/pr-report/index.mjs +8 -0
  98. package/dist/pr-report/index.mjs.map +1 -0
  99. package/dist/pr-report/linked-issues.d.mts +15 -0
  100. package/dist/pr-report/linked-issues.d.mts.map +1 -0
  101. package/dist/pr-report/linked-issues.mjs +39 -0
  102. package/dist/pr-report/linked-issues.mjs.map +1 -0
  103. package/dist/pr-report/main.d.mts +42 -0
  104. package/dist/pr-report/main.d.mts.map +1 -0
  105. package/dist/pr-report/main.mjs +163 -0
  106. package/dist/pr-report/main.mjs.map +1 -0
  107. package/dist/pr-report/options.d.mts +36 -0
  108. package/dist/pr-report/options.d.mts.map +1 -0
  109. package/dist/pr-report/options.mjs +90 -0
  110. package/dist/pr-report/options.mjs.map +1 -0
  111. package/dist/pr-report/queue.d.mts +28 -0
  112. package/dist/pr-report/queue.d.mts.map +1 -0
  113. package/dist/pr-report/queue.mjs +74 -0
  114. package/dist/pr-report/queue.mjs.map +1 -0
  115. package/dist/pr-report/render.d.mts +14 -0
  116. package/dist/pr-report/render.d.mts.map +1 -0
  117. package/dist/pr-report/render.mjs +318 -0
  118. package/dist/pr-report/render.mjs.map +1 -0
  119. package/dist/pr-report/repo-settings.d.mts +12 -0
  120. package/dist/pr-report/repo-settings.d.mts.map +1 -0
  121. package/dist/pr-report/repo-settings.mjs +22 -0
  122. package/dist/pr-report/repo-settings.mjs.map +1 -0
  123. package/dist/push-fixed-pr/index.d.mts +2 -0
  124. package/dist/push-fixed-pr/index.d.mts.map +1 -0
  125. package/dist/push-fixed-pr/index.mjs +2 -0
  126. package/dist/push-fixed-pr/index.mjs.map +1 -0
  127. package/dist/push-fixed-pr/push-fixed-pr.d.mts +54 -0
  128. package/dist/push-fixed-pr/push-fixed-pr.d.mts.map +1 -0
  129. package/dist/push-fixed-pr/push-fixed-pr.mjs +172 -0
  130. package/dist/push-fixed-pr/push-fixed-pr.mjs.map +1 -0
  131. package/dist/report-unowned-prs/index.d.mts +2 -0
  132. package/dist/report-unowned-prs/index.d.mts.map +1 -0
  133. package/dist/report-unowned-prs/index.mjs +2 -0
  134. package/dist/report-unowned-prs/index.mjs.map +1 -0
  135. package/dist/report-unowned-prs/report-unowned-prs.d.mts +49 -0
  136. package/dist/report-unowned-prs/report-unowned-prs.d.mts.map +1 -0
  137. package/dist/report-unowned-prs/report-unowned-prs.mjs +127 -0
  138. package/dist/report-unowned-prs/report-unowned-prs.mjs.map +1 -0
  139. package/dist/tsconfig.json +1 -0
  140. package/dist/unblock-prs/auto-fix.d.mts +45 -0
  141. package/dist/unblock-prs/auto-fix.d.mts.map +1 -0
  142. package/dist/unblock-prs/auto-fix.mjs +207 -0
  143. package/dist/unblock-prs/auto-fix.mjs.map +1 -0
  144. package/dist/unblock-prs/checks.d.mts +307 -0
  145. package/dist/unblock-prs/checks.d.mts.map +1 -0
  146. package/dist/unblock-prs/checks.mjs +372 -0
  147. package/dist/unblock-prs/checks.mjs.map +1 -0
  148. package/dist/unblock-prs/claims.d.mts +21 -0
  149. package/dist/unblock-prs/claims.d.mts.map +1 -0
  150. package/dist/unblock-prs/claims.mjs +23 -0
  151. package/dist/unblock-prs/claims.mjs.map +1 -0
  152. package/dist/unblock-prs/config.d.mts +487 -0
  153. package/dist/unblock-prs/config.d.mts.map +1 -0
  154. package/dist/unblock-prs/config.mjs +119 -0
  155. package/dist/unblock-prs/config.mjs.map +1 -0
  156. package/dist/unblock-prs/constants.d.mts +28 -0
  157. package/dist/unblock-prs/constants.d.mts.map +1 -0
  158. package/dist/unblock-prs/constants.mjs +28 -0
  159. package/dist/unblock-prs/constants.mjs.map +1 -0
  160. package/dist/unblock-prs/demotions.d.mts +42 -0
  161. package/dist/unblock-prs/demotions.d.mts.map +1 -0
  162. package/dist/unblock-prs/demotions.mjs +50 -0
  163. package/dist/unblock-prs/demotions.mjs.map +1 -0
  164. package/dist/unblock-prs/github.d.mts +739 -0
  165. package/dist/unblock-prs/github.d.mts.map +1 -0
  166. package/dist/unblock-prs/github.mjs +626 -0
  167. package/dist/unblock-prs/github.mjs.map +1 -0
  168. package/dist/unblock-prs/index.d.mts +25 -0
  169. package/dist/unblock-prs/index.d.mts.map +1 -0
  170. package/dist/unblock-prs/index.mjs +25 -0
  171. package/dist/unblock-prs/index.mjs.map +1 -0
  172. package/dist/unblock-prs/labels.d.mts +49 -0
  173. package/dist/unblock-prs/labels.d.mts.map +1 -0
  174. package/dist/unblock-prs/labels.mjs +49 -0
  175. package/dist/unblock-prs/labels.mjs.map +1 -0
  176. package/dist/unblock-prs/main.d.mts +179 -0
  177. package/dist/unblock-prs/main.d.mts.map +1 -0
  178. package/dist/unblock-prs/main.mjs +640 -0
  179. package/dist/unblock-prs/main.mjs.map +1 -0
  180. package/dist/unblock-prs/merge-after.d.mts +46 -0
  181. package/dist/unblock-prs/merge-after.d.mts.map +1 -0
  182. package/dist/unblock-prs/merge-after.mjs +65 -0
  183. package/dist/unblock-prs/merge-after.mjs.map +1 -0
  184. package/dist/unblock-prs/options.d.mts +35 -0
  185. package/dist/unblock-prs/options.d.mts.map +1 -0
  186. package/dist/unblock-prs/options.mjs +88 -0
  187. package/dist/unblock-prs/options.mjs.map +1 -0
  188. package/dist/unblock-prs/owner.d.mts +32 -0
  189. package/dist/unblock-prs/owner.d.mts.map +1 -0
  190. package/dist/unblock-prs/owner.mjs +63 -0
  191. package/dist/unblock-prs/owner.mjs.map +1 -0
  192. package/dist/unblock-prs/quiet.d.mts +21 -0
  193. package/dist/unblock-prs/quiet.d.mts.map +1 -0
  194. package/dist/unblock-prs/quiet.mjs +42 -0
  195. package/dist/unblock-prs/quiet.mjs.map +1 -0
  196. package/dist/unblock-prs/rebase.d.mts +120 -0
  197. package/dist/unblock-prs/rebase.d.mts.map +1 -0
  198. package/dist/unblock-prs/rebase.mjs +576 -0
  199. package/dist/unblock-prs/rebase.mjs.map +1 -0
  200. package/dist/unblock-prs/release.d.mts +62 -0
  201. package/dist/unblock-prs/release.d.mts.map +1 -0
  202. package/dist/unblock-prs/release.mjs +94 -0
  203. package/dist/unblock-prs/release.mjs.map +1 -0
  204. package/dist/unblock-prs/set-aside-comment.d.mts +20 -0
  205. package/dist/unblock-prs/set-aside-comment.d.mts.map +1 -0
  206. package/dist/unblock-prs/set-aside-comment.mjs +93 -0
  207. package/dist/unblock-prs/set-aside-comment.mjs.map +1 -0
  208. package/dist/unblock-prs/set-aside-detail.d.mts +41 -0
  209. package/dist/unblock-prs/set-aside-detail.d.mts.map +1 -0
  210. package/dist/unblock-prs/set-aside-detail.mjs +56 -0
  211. package/dist/unblock-prs/set-aside-detail.mjs.map +1 -0
  212. package/dist/unblock-prs/skips.d.mts +85 -0
  213. package/dist/unblock-prs/skips.d.mts.map +1 -0
  214. package/dist/unblock-prs/skips.mjs +141 -0
  215. package/dist/unblock-prs/skips.mjs.map +1 -0
  216. package/dist/unblock-prs/stack.d.mts +98 -0
  217. package/dist/unblock-prs/stack.d.mts.map +1 -0
  218. package/dist/unblock-prs/stack.mjs +141 -0
  219. package/dist/unblock-prs/stack.mjs.map +1 -0
  220. package/dist/unblock-prs/triage.d.mts +28 -0
  221. package/dist/unblock-prs/triage.d.mts.map +1 -0
  222. package/dist/unblock-prs/triage.mjs +396 -0
  223. package/dist/unblock-prs/triage.mjs.map +1 -0
  224. package/dist/unblock-prs/types.d.mts +793 -0
  225. package/dist/unblock-prs/types.d.mts.map +1 -0
  226. package/dist/unblock-prs/types.mjs +26 -0
  227. package/dist/unblock-prs/types.mjs.map +1 -0
  228. package/dist/unblock-prs/util.d.mts +23 -0
  229. package/dist/unblock-prs/util.d.mts.map +1 -0
  230. package/dist/unblock-prs/util.mjs +60 -0
  231. package/dist/unblock-prs/util.mjs.map +1 -0
  232. package/dist/unblock-prs/version-pr.d.mts +57 -0
  233. package/dist/unblock-prs/version-pr.d.mts.map +1 -0
  234. package/dist/unblock-prs/version-pr.mjs +79 -0
  235. package/dist/unblock-prs/version-pr.mjs.map +1 -0
  236. package/dist/unblock-prs/watch.d.mts +17 -0
  237. package/dist/unblock-prs/watch.d.mts.map +1 -0
  238. package/dist/unblock-prs/watch.mjs +128 -0
  239. package/dist/unblock-prs/watch.mjs.map +1 -0
  240. package/package.json +118 -3
  241. package/src/claim-pr/claim-pr.mts +380 -0
  242. package/src/claim-pr/claim-pr.test.mts +176 -0
  243. package/src/claim-pr/index.mts +1 -0
  244. package/src/cmd/claim-pr.mts +32 -0
  245. package/src/cmd/open-pr.mts +28 -0
  246. package/src/cmd/pr-report.mts +28 -0
  247. package/src/cmd/push-fixed-pr.mts +36 -0
  248. package/src/cmd/report-unowned-prs.mts +37 -0
  249. package/src/cmd/unblock-prs.mts +24 -0
  250. package/src/entry-point.mts +3 -0
  251. package/src/lib/cli-args.mts +86 -0
  252. package/src/lib/cli-args.test.mts +92 -0
  253. package/src/lib/github-api.mts +463 -0
  254. package/src/lib/github-api.test.mts +40 -0
  255. package/src/lib/index.mts +6 -0
  256. package/src/lib/json.mts +43 -0
  257. package/src/lib/json.test.mts +34 -0
  258. package/src/lib/log.mts +19 -0
  259. package/src/lib/log.test.mts +45 -0
  260. package/src/lib/shell.mts +52 -0
  261. package/src/lib/time.mts +49 -0
  262. package/src/open-pr/README.md +237 -0
  263. package/src/open-pr/github.mts +444 -0
  264. package/src/open-pr/index.mts +5 -0
  265. package/src/open-pr/main.mts +327 -0
  266. package/src/open-pr/options.mts +101 -0
  267. package/src/open-pr/options.test.mts +67 -0
  268. package/src/open-pr/steps.mts +57 -0
  269. package/src/open-pr/steps.test.mts +59 -0
  270. package/src/open-pr/types.mts +42 -0
  271. package/src/pr-report/README.md +244 -0
  272. package/src/pr-report/github.mts +911 -0
  273. package/src/pr-report/index.mts +7 -0
  274. package/src/pr-report/linked-issues.mts +51 -0
  275. package/src/pr-report/linked-issues.test.mts +65 -0
  276. package/src/pr-report/main.mts +257 -0
  277. package/src/pr-report/options.mts +140 -0
  278. package/src/pr-report/queue.mts +125 -0
  279. package/src/pr-report/render.mts +428 -0
  280. package/src/pr-report/render.test.mts +379 -0
  281. package/src/pr-report/repo-settings.mts +34 -0
  282. package/src/push-fixed-pr/index.mts +1 -0
  283. package/src/push-fixed-pr/push-fixed-pr.mts +276 -0
  284. package/src/push-fixed-pr/push-fixed-pr.test.mts +228 -0
  285. package/src/report-unowned-prs/index.mts +1 -0
  286. package/src/report-unowned-prs/report-unowned-prs.mts +190 -0
  287. package/src/report-unowned-prs/report-unowned-prs.test.mts +87 -0
  288. package/src/unblock-prs/README.md +1616 -0
  289. package/src/unblock-prs/auto-fix.mts +334 -0
  290. package/src/unblock-prs/auto-fix.test.mts +159 -0
  291. package/src/unblock-prs/checks.mts +538 -0
  292. package/src/unblock-prs/checks.test.mts +507 -0
  293. package/src/unblock-prs/claims.mts +33 -0
  294. package/src/unblock-prs/claims.test.mts +64 -0
  295. package/src/unblock-prs/config.mts +187 -0
  296. package/src/unblock-prs/config.schema.json +71 -0
  297. package/src/unblock-prs/config.test.mts +139 -0
  298. package/src/unblock-prs/constants.mts +33 -0
  299. package/src/unblock-prs/demotions.mts +73 -0
  300. package/src/unblock-prs/demotions.test.mts +100 -0
  301. package/src/unblock-prs/github.mts +1042 -0
  302. package/src/unblock-prs/github.test.mts +84 -0
  303. package/src/unblock-prs/index.mts +24 -0
  304. package/src/unblock-prs/labels.mts +70 -0
  305. package/src/unblock-prs/main.mts +1051 -0
  306. package/src/unblock-prs/merge-after.mts +117 -0
  307. package/src/unblock-prs/merge-after.test.mts +120 -0
  308. package/src/unblock-prs/options.mts +157 -0
  309. package/src/unblock-prs/owner.mts +91 -0
  310. package/src/unblock-prs/owner.test.mts +114 -0
  311. package/src/unblock-prs/quiet.mts +62 -0
  312. package/src/unblock-prs/quiet.test.mts +175 -0
  313. package/src/unblock-prs/rebase.mts +962 -0
  314. package/src/unblock-prs/release.mts +149 -0
  315. package/src/unblock-prs/release.test.mts +209 -0
  316. package/src/unblock-prs/set-aside-comment.mts +143 -0
  317. package/src/unblock-prs/set-aside-comment.test.mts +148 -0
  318. package/src/unblock-prs/set-aside-detail.mts +82 -0
  319. package/src/unblock-prs/set-aside-detail.test.mts +131 -0
  320. package/src/unblock-prs/skips.mts +215 -0
  321. package/src/unblock-prs/skips.test.mts +280 -0
  322. package/src/unblock-prs/stack.mts +220 -0
  323. package/src/unblock-prs/stack.test.mts +449 -0
  324. package/src/unblock-prs/triage.mts +669 -0
  325. package/src/unblock-prs/triage.test.mts +100 -0
  326. package/src/unblock-prs/types.mts +358 -0
  327. package/src/unblock-prs/util.mts +78 -0
  328. package/src/unblock-prs/util.test.mts +26 -0
  329. package/src/unblock-prs/version-pr.mts +112 -0
  330. package/src/unblock-prs/version-pr.test.mts +78 -0
  331. package/src/unblock-prs/watch.mts +219 -0
@@ -0,0 +1,307 @@
1
+ /**
2
+ * What the merge is waiting for, read from the head commit's checks and
3
+ * judged against the contexts the ruleset requires.
4
+ */
5
+ import { Result } from 'ts-data-forge';
6
+ import * as t from 'ts-fortress';
7
+ import { type ApiContext } from '../lib/index.mjs';
8
+ import type { ChecksSummary } from './types.mjs';
9
+ /**
10
+ * One check on the head, in the shape `gh pr checks --json` printed, which
11
+ * is what this script read until it called the API itself.
12
+ */
13
+ export type ReportedCheck = Readonly<{
14
+ name: string;
15
+ /** `pass` | `fail` | `pending` | `skipping` | `cancel` */
16
+ bucket: string;
17
+ link: string;
18
+ /** ISO 8601; GitHub's zero time before the check has started. */
19
+ startedAt: string;
20
+ /** ISO 8601; GitHub's zero time before the check has finished. */
21
+ completedAt: string;
22
+ /** The workflow the job belongs to; empty for a commit status. */
23
+ workflow: string;
24
+ }>;
25
+ /**
26
+ * A check on the head that has not finished, when it started, and the
27
+ * workflow run it is a job of.
28
+ */
29
+ export type RunningCheck = Readonly<{
30
+ name: string;
31
+ startedAt: string;
32
+ workflow: string;
33
+ link: string;
34
+ }>;
35
+ /**
36
+ * The checks that gate the merge, as GitHub reports them for the head commit.
37
+ * `isRequired` is GitHub's own answer for this pull request, so the list
38
+ * follows the ruleset without this script having to know it.
39
+ */
40
+ export declare const listRequiredChecks: (api: ApiContext, prNumber: number) => Promise<Result<readonly ReportedCheck[], string>>;
41
+ /**
42
+ * The checks on the head commit that have not finished, required or not.
43
+ *
44
+ * A required aggregate has no run in a new round until the jobs it waits on
45
+ * are done, so until then the required ones answer with the round before.
46
+ * When that round was the one `skip-ci` skipped, every aggregate reads
47
+ * `skipped` and the commit looks green halfway through its matrix. Anything
48
+ * still running is what says the round is not over, and when it started is
49
+ * what tells a failure of the round before from one of this round.
50
+ */
51
+ export declare const listRunningChecks: (api: ApiContext, prNumber: number) => Promise<Result<readonly RunningCheck[], string>>;
52
+ /**
53
+ * What the head commit's checks say, as `gh pr checks` said it: each check
54
+ * run and commit status in a bucket, and of the runs of one job in one
55
+ * workflow and event only the latest — a re-run, or the round `skip-ci`
56
+ * cancelled under the one now running — so that a superseded failure does
57
+ * not speak for its context. `which` is `'required'` for only what GitHub
58
+ * says this pull request requires.
59
+ *
60
+ * Unlike `gh`, the survivors keep the order GitHub listed them in. A commit
61
+ * status's start and finish are both when it was set, the one time it has.
62
+ */
63
+ export declare const reportedChecksOf: (contexts: readonly CheckContextNode[], which: 'all' | 'required') => readonly ReportedCheck[];
64
+ /** A context of the head commit's status check rollup, as read. */
65
+ export type CheckContextNode = t.TypeOf<typeof CheckContextNodeSchema>;
66
+ declare const CheckContextNodeSchema: Readonly<{
67
+ typeName: string;
68
+ defaultValue: Readonly<{
69
+ __typename: "CheckRun";
70
+ checkSuite: Readonly<{
71
+ workflowRun: Readonly<{
72
+ event: string;
73
+ workflow: Readonly<{
74
+ name: string;
75
+ }>;
76
+ }> | null;
77
+ }> | null;
78
+ completedAt: string | null;
79
+ conclusion: string | null;
80
+ detailsUrl: string | null;
81
+ isRequired: boolean;
82
+ name: string;
83
+ startedAt: string | null;
84
+ status: string;
85
+ }> | Readonly<{
86
+ __typename: "StatusContext";
87
+ context: string;
88
+ createdAt: string;
89
+ isRequired: boolean;
90
+ state: string;
91
+ targetUrl: string | null;
92
+ }>;
93
+ is: (a: unknown) => a is Readonly<{
94
+ __typename: "CheckRun";
95
+ checkSuite: Readonly<{
96
+ workflowRun: Readonly<{
97
+ event: string;
98
+ workflow: Readonly<{
99
+ name: string;
100
+ }>;
101
+ }> | null;
102
+ }> | null;
103
+ completedAt: string | null;
104
+ conclusion: string | null;
105
+ detailsUrl: string | null;
106
+ isRequired: boolean;
107
+ name: string;
108
+ startedAt: string | null;
109
+ status: string;
110
+ }> | Readonly<{
111
+ __typename: "StatusContext";
112
+ context: string;
113
+ createdAt: string;
114
+ isRequired: boolean;
115
+ state: string;
116
+ targetUrl: string | null;
117
+ }>;
118
+ assertIs: (a: unknown) => asserts a is Readonly<{
119
+ __typename: "CheckRun";
120
+ checkSuite: Readonly<{
121
+ workflowRun: Readonly<{
122
+ event: string;
123
+ workflow: Readonly<{
124
+ name: string;
125
+ }>;
126
+ }> | null;
127
+ }> | null;
128
+ completedAt: string | null;
129
+ conclusion: string | null;
130
+ detailsUrl: string | null;
131
+ isRequired: boolean;
132
+ name: string;
133
+ startedAt: string | null;
134
+ status: string;
135
+ }> | Readonly<{
136
+ __typename: "StatusContext";
137
+ context: string;
138
+ createdAt: string;
139
+ isRequired: boolean;
140
+ state: string;
141
+ targetUrl: string | null;
142
+ }>;
143
+ cast: (a: unknown) => Readonly<{
144
+ __typename: "CheckRun";
145
+ checkSuite: Readonly<{
146
+ workflowRun: Readonly<{
147
+ event: string;
148
+ workflow: Readonly<{
149
+ name: string;
150
+ }>;
151
+ }> | null;
152
+ }> | null;
153
+ completedAt: string | null;
154
+ conclusion: string | null;
155
+ detailsUrl: string | null;
156
+ isRequired: boolean;
157
+ name: string;
158
+ startedAt: string | null;
159
+ status: string;
160
+ }> | Readonly<{
161
+ __typename: "StatusContext";
162
+ context: string;
163
+ createdAt: string;
164
+ isRequired: boolean;
165
+ state: string;
166
+ targetUrl: string | null;
167
+ }>;
168
+ fill: (a: unknown) => Readonly<{
169
+ __typename: "CheckRun";
170
+ checkSuite: Readonly<{
171
+ workflowRun: Readonly<{
172
+ event: string;
173
+ workflow: Readonly<{
174
+ name: string;
175
+ }>;
176
+ }> | null;
177
+ }> | null;
178
+ completedAt: string | null;
179
+ conclusion: string | null;
180
+ detailsUrl: string | null;
181
+ isRequired: boolean;
182
+ name: string;
183
+ startedAt: string | null;
184
+ status: string;
185
+ }> | Readonly<{
186
+ __typename: "StatusContext";
187
+ context: string;
188
+ createdAt: string;
189
+ isRequired: boolean;
190
+ state: string;
191
+ targetUrl: string | null;
192
+ }>;
193
+ prune: <B extends Readonly<{
194
+ __typename: "CheckRun";
195
+ checkSuite: Readonly<{
196
+ workflowRun: Readonly<{
197
+ event: string;
198
+ workflow: Readonly<{
199
+ name: string;
200
+ }>;
201
+ }> | null;
202
+ }> | null;
203
+ completedAt: string | null;
204
+ conclusion: string | null;
205
+ detailsUrl: string | null;
206
+ isRequired: boolean;
207
+ name: string;
208
+ startedAt: string | null;
209
+ status: string;
210
+ }> | Readonly<{
211
+ __typename: "StatusContext";
212
+ context: string;
213
+ createdAt: string;
214
+ isRequired: boolean;
215
+ state: string;
216
+ targetUrl: string | null;
217
+ }>>(a: B) => Readonly<{
218
+ __typename: "CheckRun";
219
+ checkSuite: Readonly<{
220
+ workflowRun: Readonly<{
221
+ event: string;
222
+ workflow: Readonly<{
223
+ name: string;
224
+ }>;
225
+ }> | null;
226
+ }> | null;
227
+ completedAt: string | null;
228
+ conclusion: string | null;
229
+ detailsUrl: string | null;
230
+ isRequired: boolean;
231
+ name: string;
232
+ startedAt: string | null;
233
+ status: string;
234
+ }> | Readonly<{
235
+ __typename: "StatusContext";
236
+ context: string;
237
+ createdAt: string;
238
+ isRequired: boolean;
239
+ state: string;
240
+ targetUrl: string | null;
241
+ }>;
242
+ validate: (a: unknown) => Result<Readonly<{
243
+ __typename: "CheckRun";
244
+ checkSuite: Readonly<{
245
+ workflowRun: Readonly<{
246
+ event: string;
247
+ workflow: Readonly<{
248
+ name: string;
249
+ }>;
250
+ }> | null;
251
+ }> | null;
252
+ completedAt: string | null;
253
+ conclusion: string | null;
254
+ detailsUrl: string | null;
255
+ isRequired: boolean;
256
+ name: string;
257
+ startedAt: string | null;
258
+ status: string;
259
+ }> | Readonly<{
260
+ __typename: "StatusContext";
261
+ context: string;
262
+ createdAt: string;
263
+ isRequired: boolean;
264
+ state: string;
265
+ targetUrl: string | null;
266
+ }>, readonly Readonly<{
267
+ path: readonly string[];
268
+ actualValue: unknown;
269
+ expectedType: string;
270
+ typeName: string;
271
+ details?: t.ValidationErrorDetails | undefined;
272
+ }>[]>;
273
+ structure?: t.TypeStructure;
274
+ annotations?: t.TypeAnnotations;
275
+ optional?: true;
276
+ }>;
277
+ /**
278
+ * `checks` is what {@link listRequiredChecks} reported for the head commit;
279
+ * `requiredContexts` is what the ruleset asks for. The difference between the
280
+ * two is the point: a context in the second and not the first has not
281
+ * reported yet, and GitHub will not merge until it does. `running` is every
282
+ * check on the head that has not finished ({@link listRunningChecks}); while
283
+ * it is not empty the required ones may be the round before speaking, so
284
+ * they cannot pass the pull request.
285
+ *
286
+ * Nor can they fail it when they finished before the round still running
287
+ * began: the round `skip-ci` cancelled, as `open-pr` opens every pull request
288
+ * under it, leaves its aggregates red, and reading that red as this round's
289
+ * set a pull request aside while its first real round was under way (#2246).
290
+ * Such a failure waits for the round to end, as a check not yet reported
291
+ * does. So does one that finished after the round began but whose workflow
292
+ * has a newer run still going: the round `skip-ci` was put on for can take
293
+ * long enough to be cancelled that its aggregate goes red after the round
294
+ * taking its place has started, and only the run that replaced it says it is
295
+ * the round before (#2463). A failure of this round still fails the pull
296
+ * request at once.
297
+ *
298
+ * The verdict itself is `pr-report-core`'s `summarizeChecks`, which
299
+ * `pr-report` and the page reach theirs through, so the worker and the report
300
+ * cannot disagree about one; what is here turns what GitHub reports into
301
+ * the states that reads.
302
+ */
303
+ export declare const summarizeChecks: (checks: readonly ReportedCheck[], requiredContexts: readonly string[], running: readonly RunningCheck[]) => ChecksSummary;
304
+ /** Everything the merge is still waiting for, reported and unreported. */
305
+ export declare const describeWaitingOn: (summary: ChecksSummary) => string;
306
+ export {};
307
+ //# sourceMappingURL=checks.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.d.mts","sourceRoot":"","sources":["../../src/unblock-prs/checks.mts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAY,MAAM,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AACjC,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QACxB,UAAU,YACL,MAAM,KACf,OAAO,CAAC,MAAM,CAAC,SAAS,aAAa,EAAE,EAAE,MAAM,CAAC,CAGhD,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,QACvB,UAAU,YACL,MAAM,KACf,OAAO,CAAC,MAAM,CAAC,SAAS,YAAY,EAAE,EAAE,MAAM,CAAC,CAU/C,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,aACjB,SAAS,gBAAgB,EAAE,SAC9B,KAAK,GAAG,UAAU,KACxB,SAAS,aAAa,EAqBxB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAsGvE,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B1B,CAAC;AAuGH;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,eAAe,WAClB,SAAS,aAAa,EAAE,oBACd,SAAS,MAAM,EAAE,WAC1B,SAAS,YAAY,EAAE,KAC/B,aAmEF,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,YAAa,aAAa,KAAG,MAQ1D,CAAC"}
@@ -0,0 +1,372 @@
1
+
2
+
3
+
4
+
5
+ import { combineContextStates, epochMsOf, summarizeChecks as summarizeContexts, } from 'pr-report-core';
6
+ import { Arr, Num, Result } from 'ts-data-forge';
7
+ import * as t from 'ts-fortress';
8
+ import { graphqlQuery } from '../lib/index.mjs';
9
+
10
+
11
+
12
+
13
+
14
+ export const listRequiredChecks = async (api, prNumber) => Result.map(await readCheckContexts(api, prNumber), (contexts) => reportedChecksOf(contexts, 'required'));
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+ export const listRunningChecks = async (api, prNumber) => Result.map(await readCheckContexts(api, prNumber), (contexts) => reportedChecksOf(contexts, 'all')
26
+ .filter((check) => check.bucket === 'pending')
27
+ .map(({ name, startedAt, workflow, link }) => ({
28
+ name,
29
+ startedAt,
30
+ workflow,
31
+ link,
32
+ })));
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+ export const reportedChecksOf = (contexts, which) => {
45
+ const mut_latest = new Map();
46
+ for (const context of contexts) {
47
+ const key = keyOf(context);
48
+ const kept = mut_latest.get(key);
49
+ if (kept === undefined || startedAtOf(context) > startedAtOf(kept)) {
50
+ mut_latest.set(key, context);
51
+ }
52
+ }
53
+ const survivors = new Set(mut_latest.values());
54
+ return contexts
55
+ .filter((context) => survivors.has(context) && (which === 'all' || context.isRequired))
56
+ .map(reportedCheckOf);
57
+ };
58
+
59
+
60
+
61
+
62
+ const readCheckContexts = async (api, prNumber) => {
63
+ const mut_contexts = [];
64
+ let mut_after = undefined;
65
+ for (const _page of Arr.seq(MAX_PAGES)) {
66
+ const rollup = await readRollupPage(api, prNumber, mut_after);
67
+ if (Result.isErr(rollup)) {
68
+ return rollup;
69
+ }
70
+ if (rollup.value === null) {
71
+ return Result.ok(mut_contexts);
72
+ }
73
+ mut_contexts.push(...rollup.value.nodes);
74
+ const { hasNextPage, endCursor } = rollup.value.pageInfo;
75
+ if (!hasNextPage || endCursor === null) {
76
+ return Result.ok(mut_contexts);
77
+ }
78
+ mut_after = endCursor;
79
+ }
80
+ return Result.err(`#${prNumber} has more than ${MAX_PAGES * PAGE_SIZE} checks on its head`);
81
+ };
82
+
83
+
84
+
85
+
86
+ const readRollupPage = async (api, prNumber, after) => Result.map(await graphqlQuery(api, CHECKS_QUERY, {
87
+ owner: api.repo.owner,
88
+ name: api.repo.name,
89
+ number: prNumber,
90
+ ...(after === undefined ? {} : { after }),
91
+ }, ChecksAnswerSchema), (answer) => answer.repository.pullRequest.commits.nodes[0]?.commit.statusCheckRollup
92
+ ?.contexts ?? null);
93
+ const PAGE_SIZE = 100;
94
+ const MAX_PAGES = 10;
95
+ const CHECKS_QUERY = [
96
+ 'query($owner: String!, $name: String!, $number: Int!, $after: String) {',
97
+ ' repository(owner: $owner, name: $name) {',
98
+ ' pullRequest(number: $number) {',
99
+ ' commits(last: 1) { nodes { commit { statusCheckRollup {',
100
+ ` contexts(first: ${PAGE_SIZE}, after: $after) {`,
101
+ ' pageInfo { hasNextPage endCursor }',
102
+ ' nodes {',
103
+ ' __typename',
104
+ ' ... on CheckRun {',
105
+ ' name status conclusion startedAt completedAt detailsUrl',
106
+ ' isRequired(pullRequestNumber: $number)',
107
+ ' checkSuite { workflowRun { event workflow { name } } }',
108
+ ' }',
109
+ ' ... on StatusContext {',
110
+ ' context state targetUrl createdAt',
111
+ ' isRequired(pullRequestNumber: $number)',
112
+ ' }',
113
+ ' }',
114
+ ' }',
115
+ ' } } }',
116
+ ' }',
117
+ ' }',
118
+ '}',
119
+ ].join('\n');
120
+ const CheckContextNodeSchema = t.union([
121
+ t.record({
122
+ __typename: t.literal('CheckRun'),
123
+ name: t.string(),
124
+ status: t.string(),
125
+ conclusion: t.union([t.string(), t.nullType]),
126
+ startedAt: t.union([t.string(), t.nullType]),
127
+ completedAt: t.union([t.string(), t.nullType]),
128
+ detailsUrl: t.union([t.string(), t.nullType]),
129
+ isRequired: t.boolean(),
130
+ checkSuite: t.union([
131
+ t.record({
132
+ workflowRun: t.union([
133
+ t.record({
134
+ event: t.string(),
135
+ workflow: t.record({ name: t.string() }),
136
+ }),
137
+ t.nullType,
138
+ ]),
139
+ }),
140
+ t.nullType,
141
+ ]),
142
+ }),
143
+ t.record({
144
+ __typename: t.literal('StatusContext'),
145
+ context: t.string(),
146
+ state: t.string(),
147
+ targetUrl: t.union([t.string(), t.nullType]),
148
+ createdAt: t.string(),
149
+ isRequired: t.boolean(),
150
+ }),
151
+ ]);
152
+ const ChecksAnswerSchema = t.record({
153
+ repository: t.record({
154
+ pullRequest: t.record({
155
+ commits: t.record({
156
+ nodes: t.array(t.record({
157
+ commit: t.record({
158
+ statusCheckRollup: t.union([
159
+ t.record({
160
+ contexts: t.record({
161
+ pageInfo: t.record({
162
+ hasNextPage: t.boolean(),
163
+ endCursor: t.union([t.string(), t.nullType]),
164
+ }),
165
+ nodes: t.array(CheckContextNodeSchema),
166
+ }),
167
+ }),
168
+ t.nullType,
169
+ ]),
170
+ }),
171
+ })),
172
+ }),
173
+ }),
174
+ }),
175
+ });
176
+
177
+ const ZERO_TIME = '0001-01-01T00:00:00Z';
178
+
179
+
180
+
181
+
182
+ const keyOf = (context) => context.__typename === 'StatusContext'
183
+ ? `status:${context.context}`
184
+ : [
185
+ 'run',
186
+ context.name,
187
+ context.checkSuite?.workflowRun?.workflow.name ?? '',
188
+ context.checkSuite?.workflowRun?.event ?? '',
189
+ ].join(':');
190
+ const startedAtOf = (context) => (context.__typename === 'StatusContext'
191
+ ? context.createdAt
192
+ : context.startedAt) ?? ZERO_TIME;
193
+ const reportedCheckOf = (context) => context.__typename === 'StatusContext'
194
+ ? {
195
+ name: context.context,
196
+ bucket: bucketOf(context.state),
197
+ link: context.targetUrl ?? '',
198
+ startedAt: context.createdAt,
199
+ completedAt: context.createdAt,
200
+ workflow: '',
201
+ }
202
+ : {
203
+ name: context.name,
204
+ bucket: bucketOf(context.status === 'COMPLETED'
205
+ ? (context.conclusion ?? '')
206
+ : context.status),
207
+ link: context.detailsUrl ?? '',
208
+ startedAt: context.startedAt ?? ZERO_TIME,
209
+ completedAt: context.completedAt ?? ZERO_TIME,
210
+ workflow: context.checkSuite?.workflowRun?.workflow.name ?? '',
211
+ };
212
+
213
+
214
+
215
+
216
+
217
+ const bucketOf = (state) => {
218
+ switch (state) {
219
+ case 'SUCCESS':
220
+ return 'pass';
221
+ case 'SKIPPED':
222
+ case 'NEUTRAL':
223
+ return 'skipping';
224
+ case 'ERROR':
225
+ case 'FAILURE':
226
+ case 'TIMED_OUT':
227
+ case 'ACTION_REQUIRED':
228
+ case 'STARTUP_FAILURE':
229
+ return 'fail';
230
+ case 'CANCELLED':
231
+ return 'cancel';
232
+ default:
233
+ return 'pending';
234
+ }
235
+ };
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+
260
+
261
+
262
+ export const summarizeChecks = (checks, requiredContexts, running) => {
263
+ const roundStartedMs = earliestStart(running);
264
+ const isOfRoundBefore = (check) => {
265
+ const completedMs = epochMsOf(check.completedAt);
266
+ return ((roundStartedMs !== undefined &&
267
+ completedMs !== undefined &&
268
+ completedMs < roundStartedMs) ||
269
+ isSuperseded(check, running));
270
+ };
271
+ const isFailureOfThisRound = (check) => isFailure(check) && !isOfRoundBefore(check);
272
+ const mut_reported = new Map();
273
+ for (const check of checks) {
274
+ const state = stateOf(check, isOfRoundBefore(check));
275
+ const previous = mut_reported.get(check.name);
276
+ mut_reported.set(check.name, previous === undefined ? state : combineContextStates(previous, state));
277
+ }
278
+ const pendingNames = new Set(checks
279
+ .filter((check) => mut_reported.get(check.name) === 'pending')
280
+ .map((check) => check.name));
281
+ const stillRunning = running
282
+ .map(({ name }) => name)
283
+ .filter((name) => !pendingNames.has(name));
284
+ const summary = summarizeContexts({
285
+
286
+
287
+ required: Arr.uniq([
288
+ ...requiredContexts,
289
+ ...checks.map((check) => check.name),
290
+ ]),
291
+ reported: mut_reported,
292
+
293
+ paused: false,
294
+
295
+
296
+ running: Arr.isNonEmpty(stillRunning) || !Arr.isNonEmpty(checks),
297
+
298
+
299
+
300
+
301
+ baseCovered: true,
302
+ });
303
+ return {
304
+ ...summary,
305
+ failedRuns: checks
306
+ .filter(isFailureOfThisRound)
307
+ .map(({ name, link }) => ({ name, link })),
308
+ running: stillRunning,
309
+ };
310
+ };
311
+
312
+ export const describeWaitingOn = (summary) => {
313
+ const waiting = [
314
+ ...summary.pending,
315
+ ...summary.missing.map((context) => `${context} (not reported yet)`),
316
+ ...summary.running.map((name) => `${name} (running)`),
317
+ ];
318
+ return Arr.isNonEmpty(waiting) ? waiting.join(', ') : 'checks to be reported';
319
+ };
320
+ const isFailure = (check) => check.bucket === 'fail' || check.bucket === 'cancel';
321
+
322
+
323
+
324
+
325
+ const stateOf = (check, ofRoundBefore) => isFailure(check)
326
+ ? ofRoundBefore
327
+ ? 'pending'
328
+ : 'failed'
329
+ : check.bucket === 'pending'
330
+ ? 'pending'
331
+ : check.bucket === 'skipping'
332
+ ? 'skipped'
333
+ : 'passed';
334
+
335
+
336
+
337
+
338
+
339
+ const isSuperseded = (check, running) => {
340
+ const runId = workflowRunId(check.link);
341
+ return (check.workflow !== '' &&
342
+ runId !== undefined &&
343
+ running.some((other) => {
344
+ const otherRunId = workflowRunId(other.link);
345
+ return (other.workflow === check.workflow &&
346
+ otherRunId !== undefined &&
347
+ otherRunId > runId);
348
+ }));
349
+ };
350
+
351
+ const workflowRunId = (link) => {
352
+ const id = /\/actions\/runs\/(\d+)\//u.exec(link)?.[1];
353
+ return id === undefined
354
+ ? undefined
355
+ : Result.unwrapOkOr(Num.safeParseInt(id), undefined);
356
+ };
357
+
358
+
359
+
360
+
361
+ const earliestStart = (running) => {
362
+ const starts = Arr.generate(function* () {
363
+ for (const { startedAt } of running) {
364
+ const ms = epochMsOf(startedAt);
365
+ if (ms !== undefined) {
366
+ yield ms;
367
+ }
368
+ }
369
+ });
370
+ return Arr.isNonEmpty(starts) ? Math.min(...starts) : undefined;
371
+ };
372
+ //# sourceMappingURL=checks.mjs.map