@shivaedev/pr-watch 0.2.0 → 0.3.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/CHANGELOG.md +19 -0
- package/README.md +20 -5
- package/dist/GitHub.d.ts +1 -1
- package/dist/GitHub.js +1 -1
- package/dist/GitHub.js.map +1 -1
- package/dist/GitHubHttp.d.ts +1 -1
- package/dist/GitHubHttp.d.ts.map +1 -1
- package/dist/GitHubHttp.js +12 -4
- package/dist/GitHubHttp.js.map +1 -1
- package/dist/Watcher.d.ts +1 -1
- package/dist/Watcher.d.ts.map +1 -1
- package/dist/Watcher.js +10 -5
- package/dist/Watcher.js.map +1 -1
- package/dist/arguments.d.ts +5 -2
- package/dist/arguments.d.ts.map +1 -1
- package/dist/arguments.js +28 -1
- package/dist/arguments.js.map +1 -1
- package/dist/cli.js +8 -8
- package/dist/cli.js.map +1 -1
- package/dist/events.d.ts +4 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +5 -2
- package/dist/events.js.map +1 -1
- package/dist/health.d.ts +9 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +36 -0
- package/dist/health.js.map +1 -0
- package/dist/model.d.ts +3 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +1 -0
- package/dist/model.js.map +1 -1
- package/dist/program.d.ts +3 -2
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +42 -22
- package/dist/program.js.map +1 -1
- package/package.json +5 -5
- package/src/GitHub.ts +1 -1
- package/src/GitHubHttp.ts +12 -4
- package/src/Watcher.ts +11 -6
- package/src/arguments.ts +29 -1
- package/src/cli.ts +13 -10
- package/src/events.ts +11 -6
- package/src/health.ts +42 -0
- package/src/model.ts +3 -0
- package/src/program.ts +57 -25
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 - 2026-10-25
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Release with updated workspace dependencies.
|
|
8
|
+
|
|
9
|
+
## 0.3.0 - 2026-10-25
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Select PR transitions with `--events KIND,...`; reject unknown kinds at startup with the valid choices.
|
|
14
|
+
- Print unfiltered JSON health lines for heartbeats, errors, quota cooldowns and polling stops on stdout.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Keep long quota-paced waits visible with interval heartbeats and the next poll time instead of silently sleeping.
|
|
19
|
+
- Exit non-zero after a failed round instead of swallowing the error and retrying indefinitely; retain successful snapshots and report rate-limit retry times.
|
|
20
|
+
- Keep rate-limit logs out of the CLI's JSON-line stdout stream.
|
|
21
|
+
|
|
3
22
|
## 0.2.0 - 2026-10-25
|
|
4
23
|
|
|
5
24
|
### Changed
|
package/README.md
CHANGED
|
@@ -14,11 +14,11 @@ pr-watch --repo acme/project --fleet
|
|
|
14
14
|
{"branch":"feature","event":"merged","number":42,"title":"Ship the feature"}
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Each PR event occupies one JSON line with its PR number, head branch and title. Health lines share stdout so an orchestrator can distinguish a quiet watch from a stopped one.
|
|
18
18
|
|
|
19
19
|
## Run the watcher
|
|
20
20
|
|
|
21
|
-
Each successful observation compares a PR with its saved snapshot. The first observation establishes a baseline. If the PR already has auto-merge enabled with conflicts or failing checks, it immediately emits `stuck` and the corresponding `conflict` or `checks-failed` events. Failed requests
|
|
21
|
+
Each successful observation compares a PR with its saved snapshot. The first observation establishes a baseline. If the PR already has auto-merge enabled with conflicts or failing checks, it immediately emits `stuck` and the corresponding `conflict` or `checks-failed` events. Failed requests and invalid responses retain the previous snapshot. Pending mergeability skips that PR silently, keeps its previous snapshot or discovery-only tracking, and reads it again next round while other PRs continue normally. Checks and queue refs are polled even when the PR detail response is unchanged.
|
|
22
22
|
|
|
23
23
|
Install with Node 24 or later and the repository's Effect peer version:
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ Install with Node 24 or later and the repository's Effect peer version:
|
|
|
26
26
|
npm install @shivaedev/pr-watch effect@4.0.5 @effect/platform-node@4.0.5 @effect/platform-node-shared@4.0.5
|
|
27
27
|
export GH_TOKEN=YOUR_READ_ONLY_TOKEN
|
|
28
28
|
pr-watch --repo acme/project 42 57 --state ./watch-state.json
|
|
29
|
-
pr-watch --repo acme/project --fleet --interval 60 --state ./fleet-state.json
|
|
29
|
+
pr-watch --repo acme/project --fleet --interval 60 --state ./fleet-state.json --events dequeued,stuck,conflict,auto-merge-off,closed
|
|
30
30
|
pr-watch --repo acme/project 42 --once
|
|
31
31
|
```
|
|
32
32
|
|
|
@@ -34,10 +34,12 @@ pr-watch --repo acme/project 42 --once
|
|
|
34
34
|
|
|
35
35
|
Choose explicit PR numbers or `--fleet`. Fleet mode polls all open PRs and discovers PRs opened after startup. Discovery saves open PR numbers before requesting queue refs and full snapshots, so a failed initial observation does not lose the PR. PRs already recorded in the state file stay tracked when they disappear from the open list, so their merge or closure can be observed. After that terminal observation, they stay in the state file but leave the polled set, including after a restart. Keep one watcher per state file. The default state path is `.pr-watch/OWNER-REPO.json`; a file from another repository or an invalid file causes startup to fail instead of resetting history.
|
|
36
36
|
|
|
37
|
-
`--interval SECONDS` sets the minimum interval (default 60, minimum 1). `--once` performs one observation round and exits; a failed round exits unsuccessfully. `--api-url URL` sets the REST base for GitHub Enterprise or a synthetic server, allowing HTTPS or loopback HTTP. The GraphQL endpoint is the same base with `/graphql` appended, or `/api/graphql` for an Enterprise `/api/v3` REST base. `--help` lists the commands.
|
|
37
|
+
`--interval SECONDS` sets the minimum interval (default 60, minimum 1). `--heartbeat SECONDS` sets the quiet heartbeat period (default 900, or 15 minutes); `0` disables heartbeats. Every stdout line restarts that period. `--once` performs one observation round and exits; a failed round exits unsuccessfully. `--api-url URL` sets the REST base for GitHub Enterprise or a synthetic server, allowing HTTPS or loopback HTTP. The GraphQL endpoint is the same base with `/graphql` appended, or `/api/graphql` for an Enterprise `/api/v3` REST base. `--help` lists the commands. Errors also go to stderr. A failed round ends the process with a non-zero exit code after reporting health on stdout. SIGINT and SIGTERM interrupt the watcher and print a `stopped` line.
|
|
38
38
|
|
|
39
39
|
### Events
|
|
40
40
|
|
|
41
|
+
`--events KIND,...` selects which PR transitions reach stdout, for example `--events dequeued,stuck,conflict,auto-merge-off,closed`. Without it, all transitions are printed. An unknown kind fails startup with the valid choices. Filtering still saves each successful snapshot, so omitted transitions are acknowledged and do not reappear on the next run.
|
|
42
|
+
|
|
41
43
|
The watcher emits these transitions, once per successful comparison:
|
|
42
44
|
|
|
43
45
|
| Event | Transition |
|
|
@@ -53,13 +55,26 @@ The watcher emits these transitions, once per successful comparison:
|
|
|
53
55
|
|
|
54
56
|
Failure evidence includes completed check runs with `failure`, `timed_out`, `cancelled`, `action_required`, `startup_failure` or `stale`, and combined commit statuses with `failure` or `error`. Pending, successful, neutral and skipped check runs do not count as failures. Checks use the current head SHA and include all response pages. Queue discovery uses the REST matching refs endpoint, recognizing `gh-readonly-queue/.../pr-N-...` names; it does not discover queue membership from auto-merge settings. Entering the queue emits `queued` even when GitHub clears the auto-merge request. A queued PR never emits `auto-merge-off`. When a previously queued open PR loses its refs, a GraphQL request confirms the PR’s own queue entry and auto-merge request. Either one still present retains its previous queue membership during a rebuild. A confirmed drop with auto-merge still off emits both `dequeued` and `auto-merge-off`. A failed, incomplete or errored confirmation retains the last successful snapshot.
|
|
55
57
|
|
|
58
|
+
### Health lines
|
|
59
|
+
|
|
60
|
+
Health lines always reach stdout, including with `--events`. They have `event` and an ISO UTC `at` timestamp rather than PR fields:
|
|
61
|
+
|
|
62
|
+
| Event | Meaning |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `heartbeat` | No line has printed for `--heartbeat` seconds while the process waits for its next poll. `nextPollAt` gives its scheduled time. The heartbeat period spans polling rounds and continues during quota pacing. |
|
|
65
|
+
| `cooldown` | Quota pacing extends the interval, or GitHub refuses requests until a retry instant. `nextPollAt` gives that instant; pacing also includes `delayMs`. This line prints immediately, even with heartbeats disabled. |
|
|
66
|
+
| `error` | An observation or startup operation failed. `message` describes it; no failed observation replaces a saved snapshot. |
|
|
67
|
+
| `stopped` | The program finished, failed or was interrupted. `reason` distinguishes these outcomes. |
|
|
68
|
+
|
|
69
|
+
A rate-limited or otherwise failed round reports its error, any known cooldown and a stop, then exits non-zero. Start a new process after resolving the error or reaching the retry instant. Successful rounds can still pace their next poll for quota without stopping; periodic heartbeats continue throughout that wait unless disabled. `--once` also prints a stop after its result. Health lines do not add GitHub requests. A pipe receives lines as they are written, without waiting for process exit.
|
|
70
|
+
|
|
56
71
|
### Quota cost
|
|
57
72
|
|
|
58
73
|
At a 60-second interval, for N open PRs, one page of checks per PR and one page of queue refs, the watcher sends up to `60 × (3N + 1)` REST requests per hour. Fleet mode adds up to `60 × max(1, ceil(open PRs / 100))` discovery requests. Each additional check or queue page adds 60 requests per hour. Each suspected queue drop adds one GraphQL request for that PR in that round. Merged and closed PRs make no further requests after their terminal observation. With no active PRs, queue discovery also stops; fleet discovery continues.
|
|
59
74
|
|
|
60
75
|
These are request counts, not necessarily charged quota. With authentication, a successful ETag conditional request returning 304 costs zero primary rate-limit quota. Every REST endpoint sends `If-None-Match` after receiving an ETag and reuses its successful cached body on 304. Initial requests, changed responses and endpoints without ETags consume quota normally. Caches are in memory, so a restart makes fresh requests. Secondary limits still apply.
|
|
61
76
|
|
|
62
|
-
The minimum interval doubles below 50% remaining quota, increases fivefold below 20% and tenfold below 10%. At low quota, the delay also spreads the observed round's request count over the remaining reset window. Rate-limited requests
|
|
77
|
+
The minimum interval doubles below 50% remaining quota, increases fivefold below 20% and tenfold below 10%. At low quota, the delay also spreads the observed round's request count over the remaining reset window. Rate-limited requests report effect-github’s `retryAt`, derived from `Retry-After` or the primary reset instant, before exiting. Successful rounds with exhausted primary quota schedule the next poll at reset. Permission failures remain failed observations without a quota cooldown. No further request starts during a known cooldown.
|
|
63
78
|
|
|
64
79
|
### Restart and delivery limits
|
|
65
80
|
|
package/dist/GitHub.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export declare const GitHub: import("effect/Context").Service<"@shivaedev/pr-wat
|
|
|
35
35
|
queued: boolean;
|
|
36
36
|
state: "closed" | "open";
|
|
37
37
|
title: string;
|
|
38
|
-
}, WatchError, never>;
|
|
38
|
+
} | undefined, WatchError, never>;
|
|
39
39
|
}>> & {
|
|
40
40
|
readonly layer: import("effect/Layer").Layer<"@shivaedev/pr-watch/GitHub", never, "@shivaedev/pr-watch/GitHubHttp">;
|
|
41
41
|
};
|
package/dist/GitHub.js
CHANGED
|
@@ -52,7 +52,7 @@ export const GitHub = defineService({
|
|
|
52
52
|
return yield* Effect.fail(new WatchError({ message: "GitHub returned the wrong PR" }));
|
|
53
53
|
}
|
|
54
54
|
if (pr.state === "open" && (pr.mergeable === null || pr.mergeableState === "unknown")) {
|
|
55
|
-
return
|
|
55
|
+
return undefined;
|
|
56
56
|
}
|
|
57
57
|
let failed = false;
|
|
58
58
|
if (pr.state === "open") {
|
package/dist/GitHub.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"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"}
|
package/dist/GitHubHttp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import { WatchError } from "
|
|
2
|
+
import { WatchError } from "#model.ts";
|
|
3
3
|
export declare const GitHubHttp: import("effect/Context").Service<"@shivaedev/pr-watch/GitHubHttp", Readonly<{
|
|
4
4
|
readonly delay: (interval: number) => Effect.Effect<number, never, never>;
|
|
5
5
|
readonly get: (url: string) => Effect.Effect<unknown, WatchError, never>;
|
package/dist/GitHubHttp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubHttp.d.ts","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAIjE,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"GitHubHttp.d.ts","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAIjE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,eAAO,MAAM,UAAU;;;;;;;CA+DrB,CAAC"}
|
package/dist/GitHubHttp.js
CHANGED
|
@@ -2,8 +2,8 @@ import { Clock, DateTime, Effect, Schema, Stream } from "effect";
|
|
|
2
2
|
import { GitHubRateLimited } from "@shivaedev/effect-github/errors.ts";
|
|
3
3
|
import { GitHub } from "@shivaedev/effect-github/GitHub.ts";
|
|
4
4
|
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
5
|
-
import { WatchError } from "
|
|
6
|
-
import { pollDelay, quotaRetryAt } from "
|
|
5
|
+
import { WatchError } from "#model.ts";
|
|
6
|
+
import { pollDelay, quotaRetryAt } from "#quota.ts";
|
|
7
7
|
export const GitHubHttp = defineService({
|
|
8
8
|
id: "@shivaedev/pr-watch/GitHubHttp",
|
|
9
9
|
initialize: Effect.gen(function* () {
|
|
@@ -15,14 +15,22 @@ export const GitHubHttp = defineService({
|
|
|
15
15
|
const now = yield* Clock.currentTimeMillis;
|
|
16
16
|
const observations = yield* state.github.observations();
|
|
17
17
|
if (quotaRetryAt(observations, state.retryAt) > now) {
|
|
18
|
-
return yield* new WatchError({ message: "GitHub quota cooldown" });
|
|
18
|
+
return yield* new WatchError({ message: "GitHub quota cooldown", retryAt: quotaRetryAt(observations, state.retryAt) });
|
|
19
19
|
}
|
|
20
20
|
return yield* operation;
|
|
21
21
|
}).pipe(Effect.scoped, Effect.timeout("30 seconds"), Effect.tapError((cause) => Effect.sync(() => {
|
|
22
22
|
if (cause instanceof GitHubRateLimited) {
|
|
23
23
|
state.retryAt = DateTime.toEpochMillis(cause.retryAt);
|
|
24
24
|
}
|
|
25
|
-
})), Effect.mapError(() =>
|
|
25
|
+
})), Effect.mapError((cause) => {
|
|
26
|
+
if (cause instanceof WatchError) {
|
|
27
|
+
return cause;
|
|
28
|
+
}
|
|
29
|
+
if (cause instanceof GitHubRateLimited) {
|
|
30
|
+
return new WatchError({ message: "GitHub quota cooldown", retryAt: DateTime.toEpochMillis(cause.retryAt) });
|
|
31
|
+
}
|
|
32
|
+
return new WatchError({ message: "GitHub request failed" });
|
|
33
|
+
}));
|
|
26
34
|
}
|
|
27
35
|
function counted(operation) {
|
|
28
36
|
return Effect.suspend(() => {
|
package/dist/GitHubHttp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubHttp.js","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"GitHubHttp.js","sourceRoot":"","sources":["../src/GitHubHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEpD,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;IACvC,EAAE,EAAE,gCAAgC;IACpC,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC/B,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAC3D,CAAC,CAAC;IACF,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;QAClB,SAAS,OAAO,CAAU,SAAiC;YAC1D,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;gBAC3C,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;gBACxD,IAAI,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;oBACrD,OAAO,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACxH,CAAC;gBACD,OAAO,KAAK,CAAC,CAAC,SAAS,CAAC;YACzB,CAAC,CAAC,CAAC,IAAI,CACN,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAC5B,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACzB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBAChB,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;oBACxC,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvD,CAAC;YACF,CAAC,CAAC,CACF,EACD,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE;gBACzB,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;oBACjC,OAAO,KAAK,CAAC;gBACd,CAAC;gBACD,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;oBACxC,OAAO,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC7G,CAAC;gBACD,OAAO,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;YAC7D,CAAC,CAAC,CACF,CAAC;QACH,CAAC;QACD,SAAS,OAAO,CAAU,SAAiC;YAC1D,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC1B,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;gBACpB,OAAO,SAAS,CAAC;YAClB,CAAC,CAAC,CAAC;QACJ,CAAC;QACD,OAAO;YACN,KAAK,EAAE,CAAC,QAAgB,EAAE,EAAE,CAC3B,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;gBACnB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;gBAC3C,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;gBACxD,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBACjG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACnB,OAAO,KAAK,CAAC;YACd,CAAC,CAAC;YACH,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAClI,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CACrB,OAAO,CACN,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CACzC,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EACxE,MAAM,CAAC,UAAU,CACjB,CACD;YACF,IAAI,EAAE,CAAC,GAAW,EAAE,IAAa,EAAE,EAAE,CACpC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;SAC5H,CAAC;IACH,CAAC;IACD,QAAQ,EAAE,CAAC,MAAM,CAAC;CAClB,CAAC,CAAC"}
|
package/dist/Watcher.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import type { Options, WatchError } from "
|
|
2
|
+
import type { Options, WatchError } from "#model.ts";
|
|
3
3
|
export declare const Watcher: import("effect/Context").Service<"@shivaedev/pr-watch/Watcher", Readonly<{
|
|
4
4
|
readonly delay: (interval: number) => Effect.Effect<number, never, never>;
|
|
5
5
|
readonly load: (options: Options) => Effect.Effect<{
|
package/dist/Watcher.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Watcher.d.ts","sourceRoot":"","sources":["../src/Watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,OAAO,KAAK,EAAE,OAAO,EAAmB,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"Watcher.d.ts","sourceRoot":"","sources":["../src/Watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,OAAO,KAAK,EAAE,OAAO,EAAmB,UAAU,EAAE,MAAM,WAAW,CAAC;AAStE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAuDH,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,wBACjC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;CA2BlE,CAAC"}
|
package/dist/Watcher.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
3
|
-
import { events } from "
|
|
4
|
-
import { GitHub } from "
|
|
5
|
-
import { StateFile } from "
|
|
3
|
+
import { events } from "#events.ts";
|
|
4
|
+
import { GitHub } from "#GitHub.ts";
|
|
5
|
+
import { StateFile } from "#StateFile.ts";
|
|
6
6
|
function activeNumbers(options, state) {
|
|
7
7
|
return [...new Set([...options.numbers, ...(state.openNumbers ?? []), ...Object.keys(state.prs).map(Number)])].filter((number) => {
|
|
8
8
|
const saved = state.prs[String(number)];
|
|
@@ -21,7 +21,7 @@ export const Watcher = defineService({
|
|
|
21
21
|
const baseline = before === undefined && snapshot.state === "closed" && state.openNumbers?.includes(snapshot.number)
|
|
22
22
|
? { ...snapshot, merged: false, state: "open" }
|
|
23
23
|
: before;
|
|
24
|
-
for (const line of events(baseline, snapshot)) {
|
|
24
|
+
for (const line of events(baseline, snapshot, options.events)) {
|
|
25
25
|
yield* emit(line);
|
|
26
26
|
}
|
|
27
27
|
const next = {
|
|
@@ -36,6 +36,9 @@ export const Watcher = defineService({
|
|
|
36
36
|
function observe(options, number, queue, before) {
|
|
37
37
|
return Effect.gen(function* () {
|
|
38
38
|
const snapshot = yield* github.snapshot(options, number, queue);
|
|
39
|
+
if (snapshot === undefined) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
39
42
|
return before?.queued === true && snapshot.state === "open" && !snapshot.queued ? yield* github.confirmQueue(options, snapshot) : snapshot;
|
|
40
43
|
});
|
|
41
44
|
}
|
|
@@ -68,7 +71,9 @@ export const Watcher = defineService({
|
|
|
68
71
|
failure = result.failure;
|
|
69
72
|
continue;
|
|
70
73
|
}
|
|
71
|
-
|
|
74
|
+
if (result.success !== undefined) {
|
|
75
|
+
state = yield* commit(state, result.success, options, emit);
|
|
76
|
+
}
|
|
72
77
|
}
|
|
73
78
|
if (failure !== undefined) {
|
|
74
79
|
return yield* Effect.fail(failure);
|
package/dist/Watcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Watcher.js","sourceRoot":"","sources":["../src/Watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"Watcher.js","sourceRoot":"","sources":["../src/Watcher.ts"],"names":[],"mappings":"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"}
|
package/dist/arguments.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import { WatchError } from "
|
|
3
|
-
export declare const help = "pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]\n --state PATH Snapshot file (default .pr-watch/OWNER-REPO.json)\n --interval SECONDS Poll interval (default 60; slows as quota falls)\n --once Poll once and exit\n --api-url URL GitHub REST base URL (default https://api.github.com)\n --help Show this help\nAuthentication: GH_TOKEN or GITHUB_TOKEN";
|
|
2
|
+
import { WatchError } from "#model.ts";
|
|
3
|
+
export declare const help = "pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]\n --state PATH Snapshot file (default .pr-watch/OWNER-REPO.json)\n --interval SECONDS Poll interval (default 60; slows as quota falls)\n --heartbeat SECONDS Quiet heartbeat period (default 900; 0 disables)\n --events KINDS Comma-separated PR event kinds (health lines always print)\n --once Poll once and exit\n --api-url URL GitHub REST base URL (default https://api.github.com)\n --help Show this help\nAuthentication: GH_TOKEN or GITHUB_TOKEN";
|
|
4
4
|
export declare function argumentsFor(args: readonly string[]): Effect.Effect<{
|
|
5
5
|
help: true;
|
|
6
|
+
heartbeat?: never;
|
|
6
7
|
once?: never;
|
|
7
8
|
options?: never;
|
|
8
9
|
} | {
|
|
10
|
+
heartbeat: number;
|
|
9
11
|
help: false;
|
|
10
12
|
once: boolean;
|
|
11
13
|
options: {
|
|
12
14
|
apiUrl: string;
|
|
15
|
+
events?: readonly ("auto-merge-off" | "checks-failed" | "closed" | "conflict" | "dequeued" | "merged" | "queued" | "stuck")[];
|
|
13
16
|
fleet: boolean;
|
|
14
17
|
interval: number;
|
|
15
18
|
numbers: readonly number[];
|
package/dist/arguments.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAgB,UAAU,EAAE,MAAM,WAAW,CAAC;AACrD,eAAO,MAAM,IAAI,qiBAQwB,CAAC;AAC1C,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE;;;;;;;;;;;;;;;;;;sBA8CnD"}
|
package/dist/arguments.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
-
import {
|
|
3
|
+
import { eventKinds } from "#events.ts";
|
|
4
|
+
import { WatchError } from "#model.ts";
|
|
4
5
|
export const help = `pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]
|
|
5
6
|
--state PATH Snapshot file (default .pr-watch/OWNER-REPO.json)
|
|
6
7
|
--interval SECONDS Poll interval (default 60; slows as quota falls)
|
|
8
|
+
--heartbeat SECONDS Quiet heartbeat period (default 900; 0 disables)
|
|
9
|
+
--events KINDS Comma-separated PR event kinds (health lines always print)
|
|
7
10
|
--once Poll once and exit
|
|
8
11
|
--api-url URL GitHub REST base URL (default https://api.github.com)
|
|
9
12
|
--help Show this help
|
|
@@ -17,7 +20,9 @@ export function argumentsFor(args) {
|
|
|
17
20
|
args: [...args],
|
|
18
21
|
options: {
|
|
19
22
|
"api-url": { type: "string" },
|
|
23
|
+
events: { type: "string" },
|
|
20
24
|
fleet: { type: "boolean" },
|
|
25
|
+
heartbeat: { type: "string" },
|
|
21
26
|
help: { type: "boolean" },
|
|
22
27
|
interval: { type: "string" },
|
|
23
28
|
once: { type: "boolean" },
|
|
@@ -32,14 +37,17 @@ export function argumentsFor(args) {
|
|
|
32
37
|
if (repository.match(/^[\w.-]+\/[\w.-]+$/u) === null) {
|
|
33
38
|
throw new Error("--repo OWNER/REPO is required");
|
|
34
39
|
}
|
|
40
|
+
const selected = eventsFor(values.events);
|
|
35
41
|
const numbers = numbersFor(positionals, values.fleet ?? false);
|
|
36
42
|
const interval = intervalFor(values.interval);
|
|
37
43
|
const apiUrl = apiUrlFor(values["api-url"]);
|
|
38
44
|
return {
|
|
45
|
+
heartbeat: heartbeatFor(values.heartbeat),
|
|
39
46
|
help: false,
|
|
40
47
|
once: values.once ?? false,
|
|
41
48
|
options: {
|
|
42
49
|
apiUrl,
|
|
50
|
+
...(selected === undefined ? {} : { events: selected }),
|
|
43
51
|
fleet: values.fleet ?? false,
|
|
44
52
|
interval,
|
|
45
53
|
numbers,
|
|
@@ -50,6 +58,13 @@ export function argumentsFor(args) {
|
|
|
50
58
|
},
|
|
51
59
|
});
|
|
52
60
|
}
|
|
61
|
+
function heartbeatFor(value) {
|
|
62
|
+
const heartbeat = Number(value ?? 900) * 1000;
|
|
63
|
+
if (!Number.isFinite(heartbeat) || heartbeat < 0) {
|
|
64
|
+
throw new Error("--heartbeat must be zero or more seconds");
|
|
65
|
+
}
|
|
66
|
+
return heartbeat;
|
|
67
|
+
}
|
|
53
68
|
function numbersFor(positionals, fleet) {
|
|
54
69
|
if (positionals.some((value) => value.match(/^[1-9]\d*$/u) === null)) {
|
|
55
70
|
throw new Error("PR numbers must be positive integers");
|
|
@@ -80,4 +95,16 @@ function apiUrlFor(value) {
|
|
|
80
95
|
}
|
|
81
96
|
return apiUrl;
|
|
82
97
|
}
|
|
98
|
+
function eventsFor(value) {
|
|
99
|
+
if (value === undefined) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return value.split(",").map((name) => {
|
|
103
|
+
const kind = eventKinds.find((valid) => valid === name);
|
|
104
|
+
if (kind === undefined) {
|
|
105
|
+
throw new Error(`Unknown event kind ${JSON.stringify(name)}. Valid kinds: ${eventKinds.join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
return kind;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
83
110
|
//# sourceMappingURL=arguments.js.map
|
package/dist/arguments.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arguments.js","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,
|
|
1
|
+
{"version":3,"file":"arguments.js","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { NodeFileSystem } from "@effect/platform-node";
|
|
4
|
-
import { Effect, Layer } from "effect";
|
|
4
|
+
import { Effect, Layer, Logger } from "effect";
|
|
5
5
|
import { FetchHttpClient } from "effect/http";
|
|
6
6
|
import { GitHub as GitHubClient } from "@shivaedev/effect-github/GitHub.ts";
|
|
7
7
|
import { GitHubToken } from "@shivaedev/effect-github/GitHubToken.ts";
|
|
8
|
-
import { GitHub } from "
|
|
9
|
-
import { GitHubHttp } from "
|
|
10
|
-
import { WatchError } from "
|
|
11
|
-
import { program } from "
|
|
12
|
-
import { StateFile } from "
|
|
13
|
-
import { Watcher } from "
|
|
8
|
+
import { GitHub } from "#GitHub.ts";
|
|
9
|
+
import { GitHubHttp } from "#GitHubHttp.ts";
|
|
10
|
+
import { WatchError } from "#model.ts";
|
|
11
|
+
import { program } from "#program.ts";
|
|
12
|
+
import { StateFile } from "#StateFile.ts";
|
|
13
|
+
import { Watcher } from "#Watcher.ts";
|
|
14
14
|
const services = Watcher.layer.pipe(Layer.provide(Layer.mergeAll(StateFile.layer, GitHub.layer.pipe(Layer.provide(GitHubHttp.layer.pipe(Layer.provide(GitHubClient.layer), Layer.provide(GitHubToken.fromEnv)))))), Layer.provide(Layer.mergeAll(NodeFileSystem.layer, FetchHttpClient.layer.pipe(Layer.provide(Layer.succeed(FetchHttpClient.RequestInit)({ redirect: "error" }))))));
|
|
15
15
|
function write(stream) {
|
|
16
16
|
return (line) => Effect.tryPromise({
|
|
@@ -22,7 +22,7 @@ const abort = new AbortController();
|
|
|
22
22
|
process.once("SIGINT", () => abort.abort());
|
|
23
23
|
process.once("SIGTERM", () => abort.abort());
|
|
24
24
|
try {
|
|
25
|
-
await Effect.runPromise(program(process.argv.slice(2), write(process.stdout), write(process.stderr)).pipe(Effect.provide(services)), {
|
|
25
|
+
await Effect.runPromise(program(process.argv.slice(2), write(process.stdout), write(process.stderr)).pipe(Effect.provide(services), Effect.provide(Logger.layer([]))), {
|
|
26
26
|
signal: abort.signal,
|
|
27
27
|
});
|
|
28
28
|
}
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/events.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
import type { Snapshot } from "
|
|
2
|
-
export declare
|
|
1
|
+
import type { Snapshot } from "#model.ts";
|
|
2
|
+
export declare const eventKinds: readonly ["merged", "closed", "conflict", "queued", "dequeued", "auto-merge-off", "checks-failed", "stuck"];
|
|
3
|
+
export type EventKind = (typeof eventKinds)[number];
|
|
4
|
+
export declare function events(before: Snapshot | undefined, after: Snapshot, selected?: readonly EventKind[]): readonly string[];
|
|
3
5
|
//# sourceMappingURL=events.d.ts.map
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,eAAO,MAAM,UAAU,YAAI,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,CAAU,CAAC;AACtI,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAgBpD,wBAAgB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,MAAM,EAAE,CAkBxH"}
|
package/dist/events.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export const eventKinds = ["merged", "closed", "conflict", "queued", "dequeued", "auto-merge-off", "checks-failed", "stuck"];
|
|
1
2
|
function stuck(pr) {
|
|
2
3
|
return pr.state === "open" && pr.autoMerge && (pr.dirty || pr.failed);
|
|
3
4
|
}
|
|
@@ -12,7 +13,7 @@ function openEvents(before, after) {
|
|
|
12
13
|
];
|
|
13
14
|
return transitions.flatMap(([changed, event]) => (changed ? [event] : []));
|
|
14
15
|
}
|
|
15
|
-
export function events(before, after) {
|
|
16
|
+
export function events(before, after, selected) {
|
|
16
17
|
if (before === undefined && !stuck(after)) {
|
|
17
18
|
return [];
|
|
18
19
|
}
|
|
@@ -27,6 +28,8 @@ export function events(before, after) {
|
|
|
27
28
|
if (after.state === "open") {
|
|
28
29
|
found.push(...openEvents(baseline, after));
|
|
29
30
|
}
|
|
30
|
-
return found
|
|
31
|
+
return found
|
|
32
|
+
.filter((event) => selected === undefined || selected.includes(event))
|
|
33
|
+
.map((event) => JSON.stringify({ branch: after.branch, event, number: after.number, title: after.title }));
|
|
31
34
|
}
|
|
32
35
|
//# sourceMappingURL=events.js.map
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,SAAS,KAAK,CAAC,EAAY;IAC1B,OAAO,EAAE,CAAC,KAAK,KAAK,MAAM,IAAI,EAAE,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;AACvE,CAAC;AACD,SAAS,UAAU,CAAC,MAAgB,EAAE,KAAe;IACpD,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE,OAAO,CAAU,CAAC;AAGtI,SAAS,KAAK,CAAC,EAAY;IAC1B,OAAO,EAAE,CAAC,KAAK,KAAK,MAAM,IAAI,EAAE,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;AACvE,CAAC;AACD,SAAS,UAAU,CAAC,MAAgB,EAAE,KAAe;IACpD,MAAM,WAAW,GAA+C;QAC/D,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC;QAC1C,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC1C,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC;QAC5C,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC;QAC5F,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,eAAe,CAAC;QACjD,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KACzC,CAAC;IACF,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5E,CAAC;AACD,MAAM,UAAU,MAAM,CAAC,MAA4B,EAAE,KAAe,EAAE,QAA+B;IACpG,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,CAAC;IACX,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,IAAI,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACvF,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5E,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,KAAK;SACV,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SACrE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC7G,CAAC"}
|
package/dist/health.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { WatchError } from "#model.ts";
|
|
3
|
+
export type Emit = (line: string) => Effect.Effect<void, WatchError>;
|
|
4
|
+
export declare const health: (emit: Emit, event: "cooldown" | "error" | "heartbeat" | "stopped", fields?: Record<string, unknown> | undefined) => Effect.Effect<void, WatchError, never>;
|
|
5
|
+
export declare const makeOutput: (emit: Emit, heartbeat: number) => Effect.Effect<{
|
|
6
|
+
emit: Emit;
|
|
7
|
+
waitForPoll: (interval: number, delay: number) => Effect.Effect<void, WatchError, never>;
|
|
8
|
+
}, never, never>;
|
|
9
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACrE,eAAO,MAAM,MAAM,6JAOjB,CAAC;AAEH,eAAO,MAAM,UAAU;;;gBA4BrB,CAAC"}
|
package/dist/health.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Clock, Effect } from "effect";
|
|
2
|
+
export const health = Effect.fnUntraced(function* (emit, event, fields = {}) {
|
|
3
|
+
const at = new Date(yield* Clock.currentTimeMillis).toISOString();
|
|
4
|
+
yield* emit(JSON.stringify({ at, event, ...fields }));
|
|
5
|
+
});
|
|
6
|
+
export const makeOutput = Effect.fnUntraced(function* (emit, heartbeat) {
|
|
7
|
+
let lastOutputAt = yield* Clock.currentTimeMillis;
|
|
8
|
+
const write = Effect.fnUntraced(function* (line) {
|
|
9
|
+
yield* emit(line);
|
|
10
|
+
lastOutputAt = yield* Clock.currentTimeMillis;
|
|
11
|
+
});
|
|
12
|
+
const waitForPoll = Effect.fnUntraced(function* (interval, delay) {
|
|
13
|
+
const next = (yield* Clock.currentTimeMillis) + delay;
|
|
14
|
+
const nextPollAt = new Date(next).toISOString();
|
|
15
|
+
if (delay > interval) {
|
|
16
|
+
yield* health(write, "cooldown", { delayMs: delay, message: "GitHub quota pacing", nextPollAt });
|
|
17
|
+
}
|
|
18
|
+
let now = yield* Clock.currentTimeMillis;
|
|
19
|
+
while (now < next) {
|
|
20
|
+
if (heartbeat === 0) {
|
|
21
|
+
yield* Effect.sleep(next - now);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const due = lastOutputAt + heartbeat;
|
|
25
|
+
if (now >= due) {
|
|
26
|
+
yield* health(write, "heartbeat", { nextPollAt });
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
yield* Effect.sleep(Math.min(next - now, due - now));
|
|
30
|
+
}
|
|
31
|
+
now = yield* Clock.currentTimeMillis;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return { emit: write, waitForPoll };
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIvC,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAChD,IAAU,EACV,KAAqD,EACrD,MAAM,GAA4B,EAAE;IAEpC,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,WAAW,EAAE,CAAC;IAClE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,IAAU,EAAE,SAAiB;IACnF,IAAI,YAAY,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAClD,MAAM,KAAK,GAAS,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,IAAY;QAC5D,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,YAAY,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;IAC/C,CAAC,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,QAAgB,EAAE,KAAa;QAC/E,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC;QACtD,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACtB,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;QACzC,OAAO,GAAG,GAAG,IAAI,EAAE,CAAC;YACnB,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;gBACrB,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;gBAChC,OAAO;YACR,CAAC;YACD,MAAM,GAAG,GAAG,YAAY,GAAG,SAAS,CAAC;YACrC,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;gBAChB,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACP,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;YACtD,CAAC;YACD,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;QACtC,CAAC;IACF,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;AACrC,CAAC,CAAC,CAAC"}
|
package/dist/model.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
+
import type { EventKind } from "#events.ts";
|
|
2
3
|
declare const WatchError_base: Schema.Class<WatchError, Schema.TaggedStruct<"WatchError", {
|
|
3
4
|
readonly message: Schema.String;
|
|
5
|
+
readonly retryAt: Schema.optionalKey<Schema.Number>;
|
|
4
6
|
}>, import("effect/Cause").YieldableError>;
|
|
5
7
|
export declare class WatchError extends WatchError_base {
|
|
6
8
|
}
|
|
@@ -35,6 +37,7 @@ export declare const State: Schema.Struct<{
|
|
|
35
37
|
export type State = typeof State.Type;
|
|
36
38
|
export interface Options {
|
|
37
39
|
readonly apiUrl: string;
|
|
40
|
+
readonly events?: readonly EventKind[];
|
|
38
41
|
readonly fleet: boolean;
|
|
39
42
|
readonly interval: number;
|
|
40
43
|
readonly numbers: readonly number[];
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;;;;;AAC5C,qBAAa,UAAW,SAAQ,eAG9B;CAAG;AACL,eAAO,MAAM,QAAQ;;;;;;;;;;EAUnB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAC;AAC5C,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;EAKhB,CAAC;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC;AACtC,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B"}
|
package/dist/model.js
CHANGED
package/dist/model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,WAAW,EAAc,CAAC,YAAY,EAAE;IAC9E,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC;CAC1C,CAAC;CAAG;AACL,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC,OAAO;IACrB,MAAM,EAAE,MAAM,CAAC,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC,MAAM;CACpB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzD,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC,MAAM;IACzB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;CAC1B,CAAC,CAAC"}
|
package/dist/program.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import type
|
|
3
|
-
|
|
2
|
+
import { type Emit } from "#health.ts";
|
|
3
|
+
import type { WatchError } from "#model.ts";
|
|
4
|
+
export declare const program: (args: readonly string[], emit: Emit, diagnostic: (message: string) => Effect.Effect<void, WatchError>) => Effect.Effect<void, WatchError, "@shivaedev/pr-watch/Watcher">;
|
|
4
5
|
//# sourceMappingURL=program.d.ts.map
|
package/dist/program.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,KAAK,IAAI,EAAsB,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAG5C,eAAO,MAAM,OAAO,8DAGG,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,mEAuD/D,CAAC"}
|
package/dist/program.js
CHANGED
|
@@ -1,30 +1,50 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
2
|
-
import { argumentsFor, help } from "
|
|
3
|
-
import {
|
|
1
|
+
import { Effect, Exit } from "effect";
|
|
2
|
+
import { argumentsFor, help } from "#arguments.ts";
|
|
3
|
+
import { health, makeOutput } from "#health.ts";
|
|
4
|
+
import { Watcher } from "#Watcher.ts";
|
|
4
5
|
export const program = Effect.fn("PrWatch.program")(function* (args, emit, diagnostic) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
let reported;
|
|
7
|
+
let watching = true;
|
|
8
|
+
const run = Effect.gen(function* () {
|
|
9
|
+
const parsed = yield* argumentsFor(args);
|
|
10
|
+
if (parsed.help) {
|
|
11
|
+
watching = false;
|
|
12
|
+
yield* emit(help);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const watcher = yield* Watcher;
|
|
16
|
+
const output = yield* makeOutput(emit, parsed.heartbeat);
|
|
17
|
+
let state = yield* watcher.load(parsed.options);
|
|
18
|
+
function report(message) {
|
|
19
|
+
return health(output.emit, "error", { message }).pipe(Effect.tap(Effect.sync(() => {
|
|
20
|
+
reported = message;
|
|
21
|
+
})), Effect.andThen(diagnostic(message)));
|
|
16
22
|
}
|
|
17
|
-
|
|
23
|
+
while (true) {
|
|
24
|
+
reported = undefined;
|
|
25
|
+
state = yield* watcher.poll(parsed.options, state, output.emit, report);
|
|
18
26
|
if (parsed.once) {
|
|
19
|
-
return
|
|
27
|
+
return;
|
|
20
28
|
}
|
|
21
|
-
yield*
|
|
22
|
-
state = yield* watcher.load(parsed.options);
|
|
29
|
+
yield* output.waitForPoll(parsed.options.interval, yield* watcher.delay(parsed.options.interval));
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
});
|
|
32
|
+
yield* run.pipe(Effect.tapError((error) => Effect.gen(function* () {
|
|
33
|
+
if (reported !== error.message) {
|
|
34
|
+
yield* health(emit, "error", { message: error.message });
|
|
35
|
+
}
|
|
36
|
+
if (error.retryAt !== undefined) {
|
|
37
|
+
yield* health(emit, "cooldown", { message: error.message, nextPollAt: new Date(error.retryAt).toISOString() });
|
|
38
|
+
}
|
|
39
|
+
})), Effect.onExit((exit) => {
|
|
40
|
+
if (!watching) {
|
|
41
|
+
return Effect.void;
|
|
42
|
+
}
|
|
43
|
+
let reason = "completed";
|
|
44
|
+
if (exit._tag === "Failure") {
|
|
45
|
+
reason = Exit.hasInterrupts(exit) ? "interrupted" : "failed";
|
|
26
46
|
}
|
|
27
|
-
|
|
28
|
-
}
|
|
47
|
+
return health(emit, "stopped", { reason }).pipe(Effect.orDie);
|
|
48
|
+
}));
|
|
29
49
|
});
|
|
30
50
|
//# sourceMappingURL=program.js.map
|
package/dist/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/pr-watch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "One REST watcher for pull request transitions across a repository",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/pr-watch#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -43,16 +43,16 @@
|
|
|
43
43
|
"README.md"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@shivaedev/effect-github": "0.
|
|
46
|
+
"@shivaedev/effect-github": "0.4.0",
|
|
47
47
|
"@shivaedev/effect-service": "0.4.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@effect/platform-node": "4.0.5",
|
|
51
51
|
"@effect/platform-node-shared": "4.0.5",
|
|
52
52
|
"@effect/vitest": "4.0.5",
|
|
53
|
-
"@shivaedev/effect-test": "0.
|
|
54
|
-
"@shivaedev/quality": "0.
|
|
55
|
-
"@shivaedev/test-story": "0.19.
|
|
53
|
+
"@shivaedev/effect-test": "0.9.0",
|
|
54
|
+
"@shivaedev/quality": "0.39.1",
|
|
55
|
+
"@shivaedev/test-story": "0.19.1",
|
|
56
56
|
"@types/node": "24.19.2",
|
|
57
57
|
"effect": "4.0.5",
|
|
58
58
|
"typescript": "7.0.2",
|
package/src/GitHub.ts
CHANGED
|
@@ -58,7 +58,7 @@ export const GitHub = defineService({
|
|
|
58
58
|
return yield* Effect.fail(new WatchError({ message: "GitHub returned the wrong PR" }));
|
|
59
59
|
}
|
|
60
60
|
if (pr.state === "open" && (pr.mergeable === null || pr.mergeableState === "unknown")) {
|
|
61
|
-
return
|
|
61
|
+
return undefined;
|
|
62
62
|
}
|
|
63
63
|
let failed = false;
|
|
64
64
|
if (pr.state === "open") {
|
package/src/GitHubHttp.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { Clock, DateTime, Effect, Schema, Stream } from "effect";
|
|
|
2
2
|
import { GitHubRateLimited } from "@shivaedev/effect-github/errors.ts";
|
|
3
3
|
import { GitHub } from "@shivaedev/effect-github/GitHub.ts";
|
|
4
4
|
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
5
|
-
import { WatchError } from "
|
|
6
|
-
import { pollDelay, quotaRetryAt } from "
|
|
5
|
+
import { WatchError } from "#model.ts";
|
|
6
|
+
import { pollDelay, quotaRetryAt } from "#quota.ts";
|
|
7
7
|
|
|
8
8
|
export const GitHubHttp = defineService({
|
|
9
9
|
id: "@shivaedev/pr-watch/GitHubHttp",
|
|
@@ -16,7 +16,7 @@ export const GitHubHttp = defineService({
|
|
|
16
16
|
const now = yield* Clock.currentTimeMillis;
|
|
17
17
|
const observations = yield* state.github.observations();
|
|
18
18
|
if (quotaRetryAt(observations, state.retryAt) > now) {
|
|
19
|
-
return yield* new WatchError({ message: "GitHub quota cooldown" });
|
|
19
|
+
return yield* new WatchError({ message: "GitHub quota cooldown", retryAt: quotaRetryAt(observations, state.retryAt) });
|
|
20
20
|
}
|
|
21
21
|
return yield* operation;
|
|
22
22
|
}).pipe(
|
|
@@ -29,7 +29,15 @@ export const GitHubHttp = defineService({
|
|
|
29
29
|
}
|
|
30
30
|
}),
|
|
31
31
|
),
|
|
32
|
-
Effect.mapError(() =>
|
|
32
|
+
Effect.mapError((cause) => {
|
|
33
|
+
if (cause instanceof WatchError) {
|
|
34
|
+
return cause;
|
|
35
|
+
}
|
|
36
|
+
if (cause instanceof GitHubRateLimited) {
|
|
37
|
+
return new WatchError({ message: "GitHub quota cooldown", retryAt: DateTime.toEpochMillis(cause.retryAt) });
|
|
38
|
+
}
|
|
39
|
+
return new WatchError({ message: "GitHub request failed" });
|
|
40
|
+
}),
|
|
33
41
|
);
|
|
34
42
|
}
|
|
35
43
|
function counted<T, E, R>(operation: Effect.Effect<T, E, R>) {
|
package/src/Watcher.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
3
|
-
import { events } from "
|
|
4
|
-
import { GitHub } from "
|
|
5
|
-
import type { Options, Snapshot, State, WatchError } from "
|
|
6
|
-
import { StateFile } from "
|
|
3
|
+
import { events } from "#events.ts";
|
|
4
|
+
import { GitHub } from "#GitHub.ts";
|
|
5
|
+
import type { Options, Snapshot, State, WatchError } from "#model.ts";
|
|
6
|
+
import { StateFile } from "#StateFile.ts";
|
|
7
7
|
|
|
8
8
|
function activeNumbers(options: Options, state: State) {
|
|
9
9
|
return [...new Set([...options.numbers, ...(state.openNumbers ?? []), ...Object.keys(state.prs).map(Number)])].filter((number) => {
|
|
@@ -25,7 +25,7 @@ export const Watcher = defineService({
|
|
|
25
25
|
before === undefined && snapshot.state === "closed" && state.openNumbers?.includes(snapshot.number)
|
|
26
26
|
? { ...snapshot, merged: false, state: "open" as const }
|
|
27
27
|
: before;
|
|
28
|
-
for (const line of events(baseline, snapshot)) {
|
|
28
|
+
for (const line of events(baseline, snapshot, options.events)) {
|
|
29
29
|
yield* emit(line);
|
|
30
30
|
}
|
|
31
31
|
const next = {
|
|
@@ -41,6 +41,9 @@ export const Watcher = defineService({
|
|
|
41
41
|
function observe(options: Options, number: number, queue: ReadonlySet<number>, before: Snapshot | undefined) {
|
|
42
42
|
return Effect.gen(function* () {
|
|
43
43
|
const snapshot = yield* github.snapshot(options, number, queue);
|
|
44
|
+
if (snapshot === undefined) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
44
47
|
return before?.queued === true && snapshot.state === "open" && !snapshot.queued ? yield* github.confirmQueue(options, snapshot) : snapshot;
|
|
45
48
|
});
|
|
46
49
|
}
|
|
@@ -79,7 +82,9 @@ export const Watcher = defineService({
|
|
|
79
82
|
failure = result.failure;
|
|
80
83
|
continue;
|
|
81
84
|
}
|
|
82
|
-
|
|
85
|
+
if (result.success !== undefined) {
|
|
86
|
+
state = yield* commit(state, result.success, options, emit);
|
|
87
|
+
}
|
|
83
88
|
}
|
|
84
89
|
if (failure !== undefined) {
|
|
85
90
|
return yield* Effect.fail(failure);
|
package/src/arguments.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { Effect } from "effect";
|
|
3
|
-
import { type
|
|
3
|
+
import { type EventKind, eventKinds } from "#events.ts";
|
|
4
|
+
import { type Options, WatchError } from "#model.ts";
|
|
4
5
|
export const help = `pr-watch --repo OWNER/REPO [--fleet | PR_NUMBER ...]
|
|
5
6
|
--state PATH Snapshot file (default .pr-watch/OWNER-REPO.json)
|
|
6
7
|
--interval SECONDS Poll interval (default 60; slows as quota falls)
|
|
8
|
+
--heartbeat SECONDS Quiet heartbeat period (default 900; 0 disables)
|
|
9
|
+
--events KINDS Comma-separated PR event kinds (health lines always print)
|
|
7
10
|
--once Poll once and exit
|
|
8
11
|
--api-url URL GitHub REST base URL (default https://api.github.com)
|
|
9
12
|
--help Show this help
|
|
@@ -17,7 +20,9 @@ export function argumentsFor(args: readonly string[]) {
|
|
|
17
20
|
args: [...args],
|
|
18
21
|
options: {
|
|
19
22
|
"api-url": { type: "string" },
|
|
23
|
+
events: { type: "string" },
|
|
20
24
|
fleet: { type: "boolean" },
|
|
25
|
+
heartbeat: { type: "string" },
|
|
21
26
|
help: { type: "boolean" },
|
|
22
27
|
interval: { type: "string" },
|
|
23
28
|
once: { type: "boolean" },
|
|
@@ -32,14 +37,17 @@ export function argumentsFor(args: readonly string[]) {
|
|
|
32
37
|
if (repository.match(/^[\w.-]+\/[\w.-]+$/u) === null) {
|
|
33
38
|
throw new Error("--repo OWNER/REPO is required");
|
|
34
39
|
}
|
|
40
|
+
const selected = eventsFor(values.events);
|
|
35
41
|
const numbers = numbersFor(positionals, values.fleet ?? false);
|
|
36
42
|
const interval = intervalFor(values.interval);
|
|
37
43
|
const apiUrl = apiUrlFor(values["api-url"]);
|
|
38
44
|
return {
|
|
45
|
+
heartbeat: heartbeatFor(values.heartbeat),
|
|
39
46
|
help: false as const,
|
|
40
47
|
once: values.once ?? false,
|
|
41
48
|
options: {
|
|
42
49
|
apiUrl,
|
|
50
|
+
...(selected === undefined ? {} : { events: selected }),
|
|
43
51
|
fleet: values.fleet ?? false,
|
|
44
52
|
interval,
|
|
45
53
|
numbers,
|
|
@@ -50,6 +58,13 @@ export function argumentsFor(args: readonly string[]) {
|
|
|
50
58
|
},
|
|
51
59
|
});
|
|
52
60
|
}
|
|
61
|
+
function heartbeatFor(value: string | undefined): number {
|
|
62
|
+
const heartbeat = Number(value ?? 900) * 1000;
|
|
63
|
+
if (!Number.isFinite(heartbeat) || heartbeat < 0) {
|
|
64
|
+
throw new Error("--heartbeat must be zero or more seconds");
|
|
65
|
+
}
|
|
66
|
+
return heartbeat;
|
|
67
|
+
}
|
|
53
68
|
function numbersFor(positionals: readonly string[], fleet: boolean): readonly number[] {
|
|
54
69
|
if (positionals.some((value) => value.match(/^[1-9]\d*$/u) === null)) {
|
|
55
70
|
throw new Error("PR numbers must be positive integers");
|
|
@@ -80,3 +95,16 @@ function apiUrlFor(value: string | undefined): string {
|
|
|
80
95
|
}
|
|
81
96
|
return apiUrl;
|
|
82
97
|
}
|
|
98
|
+
|
|
99
|
+
function eventsFor(value: string | undefined): readonly EventKind[] | undefined {
|
|
100
|
+
if (value === undefined) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
return value.split(",").map((name) => {
|
|
104
|
+
const kind = eventKinds.find((valid) => valid === name);
|
|
105
|
+
if (kind === undefined) {
|
|
106
|
+
throw new Error(`Unknown event kind ${JSON.stringify(name)}. Valid kinds: ${eventKinds.join(", ")}`);
|
|
107
|
+
}
|
|
108
|
+
return kind;
|
|
109
|
+
});
|
|
110
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { NodeFileSystem } from "@effect/platform-node";
|
|
4
|
-
import { Effect, Layer } from "effect";
|
|
4
|
+
import { Effect, Layer, Logger } from "effect";
|
|
5
5
|
import { FetchHttpClient } from "effect/http";
|
|
6
6
|
import { GitHub as GitHubClient } from "@shivaedev/effect-github/GitHub.ts";
|
|
7
7
|
import { GitHubToken } from "@shivaedev/effect-github/GitHubToken.ts";
|
|
8
|
-
import { GitHub } from "
|
|
9
|
-
import { GitHubHttp } from "
|
|
10
|
-
import { WatchError } from "
|
|
11
|
-
import { program } from "
|
|
12
|
-
import { StateFile } from "
|
|
13
|
-
import { Watcher } from "
|
|
8
|
+
import { GitHub } from "#GitHub.ts";
|
|
9
|
+
import { GitHubHttp } from "#GitHubHttp.ts";
|
|
10
|
+
import { WatchError } from "#model.ts";
|
|
11
|
+
import { program } from "#program.ts";
|
|
12
|
+
import { StateFile } from "#StateFile.ts";
|
|
13
|
+
import { Watcher } from "#Watcher.ts";
|
|
14
14
|
|
|
15
15
|
const services = Watcher.layer.pipe(
|
|
16
16
|
Layer.provide(
|
|
@@ -37,9 +37,12 @@ const abort = new AbortController();
|
|
|
37
37
|
process.once("SIGINT", () => abort.abort());
|
|
38
38
|
process.once("SIGTERM", () => abort.abort());
|
|
39
39
|
try {
|
|
40
|
-
await Effect.runPromise(
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
await Effect.runPromise(
|
|
41
|
+
program(process.argv.slice(2), write(process.stdout), write(process.stderr)).pipe(Effect.provide(services), Effect.provide(Logger.layer([]))),
|
|
42
|
+
{
|
|
43
|
+
signal: abort.signal,
|
|
44
|
+
},
|
|
45
|
+
);
|
|
43
46
|
} catch (cause) {
|
|
44
47
|
if (!abort.signal.aborted) {
|
|
45
48
|
process.stderr.write(`${cause instanceof Error ? cause.message : "Watcher failed"}\n`);
|
package/src/events.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { Snapshot } from "
|
|
1
|
+
import type { Snapshot } from "#model.ts";
|
|
2
|
+
|
|
3
|
+
export const eventKinds = ["merged", "closed", "conflict", "queued", "dequeued", "auto-merge-off", "checks-failed", "stuck"] as const;
|
|
4
|
+
export type EventKind = (typeof eventKinds)[number];
|
|
2
5
|
|
|
3
6
|
function stuck(pr: Snapshot): boolean {
|
|
4
7
|
return pr.state === "open" && pr.autoMerge && (pr.dirty || pr.failed);
|
|
5
8
|
}
|
|
6
|
-
function openEvents(before: Snapshot, after: Snapshot): readonly
|
|
7
|
-
const transitions: readonly (readonly [boolean,
|
|
9
|
+
function openEvents(before: Snapshot, after: Snapshot): readonly EventKind[] {
|
|
10
|
+
const transitions: readonly (readonly [boolean, EventKind])[] = [
|
|
8
11
|
[!before.dirty && after.dirty, "conflict"],
|
|
9
12
|
[!before.queued && after.queued, "queued"],
|
|
10
13
|
[before.queued && !after.queued, "dequeued"],
|
|
@@ -14,12 +17,12 @@ function openEvents(before: Snapshot, after: Snapshot): readonly string[] {
|
|
|
14
17
|
];
|
|
15
18
|
return transitions.flatMap(([changed, event]) => (changed ? [event] : []));
|
|
16
19
|
}
|
|
17
|
-
export function events(before: Snapshot | undefined, after: Snapshot): readonly string[] {
|
|
20
|
+
export function events(before: Snapshot | undefined, after: Snapshot, selected?: readonly EventKind[]): readonly string[] {
|
|
18
21
|
if (before === undefined && !stuck(after)) {
|
|
19
22
|
return [];
|
|
20
23
|
}
|
|
21
24
|
const baseline = before ?? { ...after, autoMerge: false, dirty: false, failed: false };
|
|
22
|
-
const found:
|
|
25
|
+
const found: EventKind[] = [];
|
|
23
26
|
if (!baseline.merged && after.merged) {
|
|
24
27
|
found.push("merged");
|
|
25
28
|
}
|
|
@@ -29,5 +32,7 @@ export function events(before: Snapshot | undefined, after: Snapshot): readonly
|
|
|
29
32
|
if (after.state === "open") {
|
|
30
33
|
found.push(...openEvents(baseline, after));
|
|
31
34
|
}
|
|
32
|
-
return found
|
|
35
|
+
return found
|
|
36
|
+
.filter((event) => selected === undefined || selected.includes(event))
|
|
37
|
+
.map((event) => JSON.stringify({ branch: after.branch, event, number: after.number, title: after.title }));
|
|
33
38
|
}
|
package/src/health.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Clock, Effect } from "effect";
|
|
2
|
+
import type { WatchError } from "#model.ts";
|
|
3
|
+
|
|
4
|
+
export type Emit = (line: string) => Effect.Effect<void, WatchError>;
|
|
5
|
+
export const health = Effect.fnUntraced(function* (
|
|
6
|
+
emit: Emit,
|
|
7
|
+
event: "heartbeat" | "cooldown" | "error" | "stopped",
|
|
8
|
+
fields: Record<string, unknown> = {},
|
|
9
|
+
) {
|
|
10
|
+
const at = new Date(yield* Clock.currentTimeMillis).toISOString();
|
|
11
|
+
yield* emit(JSON.stringify({ at, event, ...fields }));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const makeOutput = Effect.fnUntraced(function* (emit: Emit, heartbeat: number) {
|
|
15
|
+
let lastOutputAt = yield* Clock.currentTimeMillis;
|
|
16
|
+
const write: Emit = Effect.fnUntraced(function* (line: string) {
|
|
17
|
+
yield* emit(line);
|
|
18
|
+
lastOutputAt = yield* Clock.currentTimeMillis;
|
|
19
|
+
});
|
|
20
|
+
const waitForPoll = Effect.fnUntraced(function* (interval: number, delay: number) {
|
|
21
|
+
const next = (yield* Clock.currentTimeMillis) + delay;
|
|
22
|
+
const nextPollAt = new Date(next).toISOString();
|
|
23
|
+
if (delay > interval) {
|
|
24
|
+
yield* health(write, "cooldown", { delayMs: delay, message: "GitHub quota pacing", nextPollAt });
|
|
25
|
+
}
|
|
26
|
+
let now = yield* Clock.currentTimeMillis;
|
|
27
|
+
while (now < next) {
|
|
28
|
+
if (heartbeat === 0) {
|
|
29
|
+
yield* Effect.sleep(next - now);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const due = lastOutputAt + heartbeat;
|
|
33
|
+
if (now >= due) {
|
|
34
|
+
yield* health(write, "heartbeat", { nextPollAt });
|
|
35
|
+
} else {
|
|
36
|
+
yield* Effect.sleep(Math.min(next - now, due - now));
|
|
37
|
+
}
|
|
38
|
+
now = yield* Clock.currentTimeMillis;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return { emit: write, waitForPoll };
|
|
42
|
+
});
|
package/src/model.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
+
import type { EventKind } from "#events.ts";
|
|
2
3
|
export class WatchError extends Schema.TaggedError<WatchError>()("WatchError", {
|
|
3
4
|
message: Schema.String,
|
|
5
|
+
retryAt: Schema.optionalKey(Schema.Number),
|
|
4
6
|
}) {}
|
|
5
7
|
export const Snapshot = Schema.Struct({
|
|
6
8
|
autoMerge: Schema.Boolean,
|
|
@@ -23,6 +25,7 @@ export const State = Schema.Struct({
|
|
|
23
25
|
export type State = typeof State.Type;
|
|
24
26
|
export interface Options {
|
|
25
27
|
readonly apiUrl: string;
|
|
28
|
+
readonly events?: readonly EventKind[];
|
|
26
29
|
readonly fleet: boolean;
|
|
27
30
|
readonly interval: number;
|
|
28
31
|
readonly numbers: readonly number[];
|
package/src/program.ts
CHANGED
|
@@ -1,33 +1,65 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
2
|
-
import { argumentsFor, help } from "
|
|
3
|
-
import type
|
|
4
|
-
import {
|
|
1
|
+
import { Effect, Exit } from "effect";
|
|
2
|
+
import { argumentsFor, help } from "#arguments.ts";
|
|
3
|
+
import { type Emit, health, makeOutput } from "#health.ts";
|
|
4
|
+
import type { WatchError } from "#model.ts";
|
|
5
|
+
import { Watcher } from "#Watcher.ts";
|
|
6
|
+
|
|
5
7
|
export const program = Effect.fn("PrWatch.program")(function* (
|
|
6
8
|
args: readonly string[],
|
|
7
|
-
emit:
|
|
9
|
+
emit: Emit,
|
|
8
10
|
diagnostic: (message: string) => Effect.Effect<void, WatchError>,
|
|
9
11
|
) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
let reported: string | undefined;
|
|
13
|
+
let watching = true;
|
|
14
|
+
const run = Effect.gen(function* () {
|
|
15
|
+
const parsed = yield* argumentsFor(args);
|
|
16
|
+
if (parsed.help) {
|
|
17
|
+
watching = false;
|
|
18
|
+
yield* emit(help);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const watcher = yield* Watcher;
|
|
22
|
+
const output = yield* makeOutput(emit, parsed.heartbeat);
|
|
23
|
+
let state = yield* watcher.load(parsed.options);
|
|
24
|
+
function report(message: string) {
|
|
25
|
+
return health(output.emit, "error", { message }).pipe(
|
|
26
|
+
Effect.tap(
|
|
27
|
+
Effect.sync(() => {
|
|
28
|
+
reported = message;
|
|
29
|
+
}),
|
|
30
|
+
),
|
|
31
|
+
Effect.andThen(diagnostic(message)),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
while (true) {
|
|
35
|
+
reported = undefined;
|
|
36
|
+
state = yield* watcher.poll(parsed.options, state, output.emit, report);
|
|
22
37
|
if (parsed.once) {
|
|
23
|
-
return
|
|
38
|
+
return;
|
|
24
39
|
}
|
|
25
|
-
yield*
|
|
26
|
-
state = yield* watcher.load(parsed.options);
|
|
40
|
+
yield* output.waitForPoll(parsed.options.interval, yield* watcher.delay(parsed.options.interval));
|
|
27
41
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
42
|
+
});
|
|
43
|
+
yield* run.pipe(
|
|
44
|
+
Effect.tapError((error) =>
|
|
45
|
+
Effect.gen(function* () {
|
|
46
|
+
if (reported !== error.message) {
|
|
47
|
+
yield* health(emit, "error", { message: error.message });
|
|
48
|
+
}
|
|
49
|
+
if (error.retryAt !== undefined) {
|
|
50
|
+
yield* health(emit, "cooldown", { message: error.message, nextPollAt: new Date(error.retryAt).toISOString() });
|
|
51
|
+
}
|
|
52
|
+
}),
|
|
53
|
+
),
|
|
54
|
+
Effect.onExit((exit) => {
|
|
55
|
+
if (!watching) {
|
|
56
|
+
return Effect.void;
|
|
57
|
+
}
|
|
58
|
+
let reason = "completed";
|
|
59
|
+
if (exit._tag === "Failure") {
|
|
60
|
+
reason = Exit.hasInterrupts(exit) ? "interrupted" : "failed";
|
|
61
|
+
}
|
|
62
|
+
return health(emit, "stopped", { reason }).pipe(Effect.orDie);
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
33
65
|
});
|