@shivaedev/effect-github 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/GitHub.d.ts +71 -9
- package/dist/GitHub.d.ts.map +1 -1
- package/dist/GitHub.js +12 -30
- package/dist/GitHub.js.map +1 -1
- package/dist/checkRuns.d.ts +104 -0
- package/dist/checkRuns.d.ts.map +1 -0
- package/dist/checkRuns.js +42 -0
- package/dist/checkRuns.js.map +1 -0
- package/dist/representations.d.ts +18 -0
- package/dist/representations.d.ts.map +1 -0
- package/dist/representations.js +28 -0
- package/dist/representations.js.map +1 -0
- package/dist/stickyComments.d.ts +34 -0
- package/dist/stickyComments.d.ts.map +1 -0
- package/dist/stickyComments.js +32 -0
- package/dist/stickyComments.js.map +1 -0
- package/package.json +3 -3
- package/src/GitHub.ts +12 -47
- package/src/checkRuns.ts +48 -0
- package/src/representations.ts +48 -0
- package/src/stickyComments.ts +41 -0
package/README.md
CHANGED
|
@@ -102,6 +102,39 @@ const receiveWorkflowRun = (
|
|
|
102
102
|
|
|
103
103
|
This decodes a signed `workflow_run` delivery with the fields the application needs. Keep the body bytes as received: parsing and reserializing JSON changes what was signed.
|
|
104
104
|
|
|
105
|
+
### Sticky comments and check runs
|
|
106
|
+
|
|
107
|
+
Use the service's `upsertStickyComment` to keep a report in one pull-request comment. Pass a marker name; the method prefixes the body with `<!-- name -->`, searches comment pages, and edits the first match. It creates a comment when no match exists. An optional `author` login restricts matching to that author's comments, leaving another author's report alone. A forbidden comment write fails with a typed `RemoteHttpError` and creates no comment.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const report = Effect.gen(function* () {
|
|
111
|
+
const github = yield* GitHub;
|
|
112
|
+
return yield* github.upsertStickyComment({
|
|
113
|
+
owner: "acme", repo: "widgets", number: 1,
|
|
114
|
+
marker: "coverage", author: "coverage[bot]",
|
|
115
|
+
body: "Coverage: 90%",
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`createCheckRun(owner, repo, input)` creates a check for `headSha` with a name and status. `updateCheckRun(owner, repo, id, input)` moves it to `in_progress` or `completed`; completion requires a conclusion. Output contains `title`, `summary` and optional `text`. Request and response Schemas are exported from `checkRuns.ts`.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const check = (headSha: string) => Effect.gen(function* () {
|
|
124
|
+
const github = yield* GitHub;
|
|
125
|
+
const created = yield* github.createCheckRun("acme", "widgets", {
|
|
126
|
+
headSha, name: "Coverage", status: "queued",
|
|
127
|
+
});
|
|
128
|
+
yield* github.updateCheckRun("acme", "widgets", created.id, {
|
|
129
|
+
status: "in_progress", output: { title: "Coverage", summary: "Measuring" },
|
|
130
|
+
});
|
|
131
|
+
return yield* github.updateCheckRun("acme", "widgets", created.id, {
|
|
132
|
+
status: "completed", conclusion: "success",
|
|
133
|
+
output: { title: "Coverage", summary: "90% covered", text: "All targets measured" },
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
105
138
|
### Rate limits and failures
|
|
106
139
|
|
|
107
140
|
`github.observations()` returns the latest `resource`, `limit`, `remaining`, `used` and UTC `reset` from response headers, including conditional and failed responses. Core and search budgets remain separate. A primary or secondary rate limit fails with `GitHubRateLimited` from `@shivaedev/effect-github/errors.ts`; its `retryAt` is a UTC `DateTime` usable directly by a job scheduler. Requests to a blocked resource fail locally until that instant. Each rate-limited failure records a log and span event with the request path and budget, excluding credentials and query strings.
|
package/dist/GitHub.d.ts
CHANGED
|
@@ -1,25 +1,87 @@
|
|
|
1
1
|
import { Effect, Schema, Stream } from "effect";
|
|
2
2
|
import { HttpClient } from "effect/http";
|
|
3
|
-
import
|
|
4
|
-
import { GitHubToken } from "./GitHubToken.ts";
|
|
3
|
+
import { GitHubToken } from "#GitHubToken.ts";
|
|
5
4
|
export declare const GitHub: import("effect/Context").Service<"@shivaedev/effect-github/GitHub", Readonly<{
|
|
6
|
-
readonly
|
|
7
|
-
readonly list: (path: string, beforeRequest?: ((resource: string) => Effect.Effect<void, ServiceUnavailable>) | undefined) => Effect.Effect<Stream.Stream<{
|
|
5
|
+
readonly list: (path: string, beforeRequest?: ((resource: string) => Effect.Effect<void, import("@shivaedev/platform/errors/taxonomy.ts").ServiceUnavailable>) | undefined) => Effect.Effect<Stream.Stream<{
|
|
8
6
|
decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
|
|
9
|
-
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>, never, never>;
|
|
10
|
-
readonly observations: () => Effect.Effect<import("./rateLimits.ts").RateLimitObservation[], never, never>;
|
|
7
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>, never, never>;
|
|
11
8
|
readonly read: (path: string) => Effect.Effect<{
|
|
12
9
|
decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
|
|
13
10
|
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
14
|
-
readonly resource: (path: string) => Effect.Effect<string, never, never>;
|
|
15
|
-
readonly text: (path: string, accept: string, limit: number) => Effect.Effect<string, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
16
11
|
readonly write: (method: "PATCH" | "POST", path: string, body: unknown) => Effect.Effect<{
|
|
17
12
|
decode: <TSchema extends Schema.Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], Schema.SchemaError, TSchema["DecodingServices"]>;
|
|
18
13
|
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
14
|
+
readonly createCheckRun: (owner: string, repo: string, input: {
|
|
15
|
+
readonly conclusion?: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | undefined;
|
|
16
|
+
readonly headSha: string;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly output?: {
|
|
19
|
+
readonly summary: string;
|
|
20
|
+
readonly text?: string | undefined;
|
|
21
|
+
readonly title: string;
|
|
22
|
+
} | undefined;
|
|
23
|
+
readonly status: "completed" | "in_progress" | "queued";
|
|
24
|
+
}) => Effect.Effect<{
|
|
25
|
+
readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
|
|
26
|
+
readonly headSha: string;
|
|
27
|
+
readonly id: number;
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly output: {
|
|
30
|
+
readonly summary: string | null;
|
|
31
|
+
readonly text: string | null;
|
|
32
|
+
readonly title: string | null;
|
|
33
|
+
};
|
|
34
|
+
readonly status: "completed" | "in_progress" | "queued";
|
|
35
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
36
|
+
readonly updateCheckRun: (owner: string, repo: string, id: number, input: {
|
|
37
|
+
readonly output?: {
|
|
38
|
+
readonly summary: string;
|
|
39
|
+
readonly text?: string | undefined;
|
|
40
|
+
readonly title: string;
|
|
41
|
+
} | undefined;
|
|
42
|
+
readonly status: "in_progress" | "queued";
|
|
43
|
+
} | {
|
|
44
|
+
readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out";
|
|
45
|
+
readonly output?: {
|
|
46
|
+
readonly summary: string;
|
|
47
|
+
readonly text?: string | undefined;
|
|
48
|
+
readonly title: string;
|
|
49
|
+
} | undefined;
|
|
50
|
+
readonly status: "completed";
|
|
51
|
+
}) => Effect.Effect<{
|
|
52
|
+
readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
|
|
53
|
+
readonly headSha: string;
|
|
54
|
+
readonly id: number;
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly output: {
|
|
57
|
+
readonly summary: string | null;
|
|
58
|
+
readonly text: string | null;
|
|
59
|
+
readonly title: string | null;
|
|
60
|
+
};
|
|
61
|
+
readonly status: "completed" | "in_progress" | "queued";
|
|
62
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
63
|
+
readonly upsertStickyComment: (input: {
|
|
64
|
+
readonly author?: string | undefined;
|
|
65
|
+
readonly body: string;
|
|
66
|
+
readonly marker: string;
|
|
67
|
+
readonly number: number;
|
|
68
|
+
readonly owner: string;
|
|
69
|
+
readonly repo: string;
|
|
70
|
+
}) => Effect.Effect<{
|
|
71
|
+
readonly body: string;
|
|
72
|
+
readonly id: number;
|
|
73
|
+
readonly user: {
|
|
74
|
+
readonly login: string;
|
|
75
|
+
} | null;
|
|
76
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
77
|
+
readonly bytes: (path: string, accept: string, limit: number) => Effect.Effect<Uint8Array<ArrayBufferLike>, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
78
|
+
readonly observations: () => Effect.Effect<import("#rateLimits.ts").RateLimitObservation[], never, never>;
|
|
79
|
+
readonly resource: (path: string) => Effect.Effect<string, never, never>;
|
|
80
|
+
readonly text: (path: string, accept: string, limit: number) => Effect.Effect<string, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
19
81
|
}>> & {
|
|
20
82
|
readonly layer: import("effect/Layer").Layer<"@shivaedev/effect-github/GitHub", never, GitHubToken | HttpClient.HttpClient>;
|
|
21
83
|
};
|
|
22
84
|
export declare function read<TSchema extends Schema.Constraint>(path: string, schema: TSchema): Effect.Effect<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
|
|
23
|
-
export declare function list<TSchema extends Schema.Constraint>(path: string, schema: TSchema): Stream.Stream<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
|
|
85
|
+
export declare function list<TSchema extends Schema.Constraint>(path: string, schema: TSchema): Stream.Stream<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
|
|
24
86
|
export declare function write<TSchema extends Schema.Constraint>(method: "POST" | "PATCH", path: string, body: unknown, schema: TSchema): Effect.Effect<TSchema["Type"], import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, "@shivaedev/effect-github/GitHub" | TSchema["DecodingServices"]>;
|
|
25
87
|
//# sourceMappingURL=GitHub.d.ts.map
|
package/dist/GitHub.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GitHub.d.ts","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"GitHub.d.ts","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAM9C,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBjB,CAAC;AAEH,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,wYAEpF;AAED,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,okBAKpF;AAED,wBAAgB,KAAK,CAAC,OAAO,SAAS,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,ubAE9H"}
|
package/dist/GitHub.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Effect, Schema, Stream } from "effect";
|
|
2
|
-
import { HttpClient
|
|
2
|
+
import { HttpClient } from "effect/http";
|
|
3
3
|
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
4
|
-
import {
|
|
5
|
-
import { GitHubConfig } from "
|
|
6
|
-
import { GitHubToken } from "
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { requests } from "
|
|
4
|
+
import { checkRuns } from "#checkRuns.ts";
|
|
5
|
+
import { GitHubConfig } from "#GitHubConfig.ts";
|
|
6
|
+
import { GitHubToken } from "#GitHubToken.ts";
|
|
7
|
+
import { rateLimits } from "#rateLimits.ts";
|
|
8
|
+
import { representations } from "#representations.ts";
|
|
9
|
+
import { requests } from "#requests.ts";
|
|
10
|
+
import { stickyComments } from "#stickyComments.ts";
|
|
10
11
|
export const GitHub = defineService({
|
|
11
12
|
id: "@shivaedev/effect-github/GitHub",
|
|
12
13
|
initialize: Effect.gen(function* () {
|
|
@@ -19,34 +20,15 @@ export const GitHub = defineService({
|
|
|
19
20
|
};
|
|
20
21
|
}),
|
|
21
22
|
methods: ({ apiUrl, rates, request }) => {
|
|
22
|
-
|
|
23
|
-
return HttpClientRequest.get(new URL(path, apiUrl).href, { headers: { Accept: accept } });
|
|
24
|
-
}
|
|
25
|
-
function readRepresentation(path) {
|
|
26
|
-
return Effect.map(request(get(path), 1024 * 1024), jsonResponse);
|
|
27
|
-
}
|
|
28
|
-
function listRepresentations(path, beforeRequest) {
|
|
29
|
-
const entries = new WeakMap();
|
|
30
|
-
function fetchPage(input) {
|
|
31
|
-
return (beforeRequest?.(rates.resource(new URL(input.url).pathname)) ?? Effect.void).pipe(Effect.andThen(request(input, 1024 * 1024)), Effect.map((entry) => {
|
|
32
|
-
entries.set(entry.response, entry);
|
|
33
|
-
return entry.response;
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
const client = HttpClient.makeWith((effect) => Effect.flatMap(effect, fetchPage), Effect.succeed);
|
|
37
|
-
return Effect.succeed(paginate(client, get(path)).pipe(Stream.mapEffect((response) => Effect.fromNullishOr(entries.get(response))), Stream.map(jsonResponse)));
|
|
38
|
-
}
|
|
39
|
-
function writeRepresentation(method, path, body) {
|
|
40
|
-
return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe(HttpClientRequest.bodyJson(body), Effect.flatMap((input) => request(input, 1024 * 1024)), Effect.map(jsonResponse));
|
|
41
|
-
}
|
|
23
|
+
const { get, ...client } = representations(apiUrl, request, rates.resource);
|
|
42
24
|
return {
|
|
43
25
|
bytes: (path, accept, limit) => Effect.map(request(get(path, accept), limit), (entry) => entry.bytes),
|
|
44
|
-
|
|
26
|
+
...client,
|
|
27
|
+
...stickyComments(client),
|
|
28
|
+
...checkRuns(client),
|
|
45
29
|
observations: () => Effect.sync(() => [...rates.observations.values()]),
|
|
46
|
-
read: readRepresentation,
|
|
47
30
|
resource: (path) => Effect.sync(() => rates.resource(new URL(path, apiUrl).pathname)),
|
|
48
31
|
text: (path, accept, limit) => Effect.map(request(get(path, accept), limit), (entry) => new TextDecoder().decode(entry.bytes)),
|
|
49
|
-
write: writeRepresentation,
|
|
50
32
|
};
|
|
51
33
|
},
|
|
52
34
|
requires: [HttpClient.HttpClient, GitHubToken],
|
package/dist/GitHub.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"GitHub.js","sourceRoot":"","sources":["../src/GitHub.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { Representations } from "./representations.ts";
|
|
3
|
+
export declare const CheckRunOutput: Schema.Struct<{
|
|
4
|
+
readonly summary: Schema.String;
|
|
5
|
+
readonly text: Schema.optional<Schema.String>;
|
|
6
|
+
readonly title: Schema.String;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const CheckRunConclusion: Schema.Literals<readonly ["action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"]>;
|
|
9
|
+
export declare const CheckRunStatus: Schema.Literals<readonly ["queued", "in_progress", "completed"]>;
|
|
10
|
+
export declare const CreateCheckRun: Schema.encodeKeys<Schema.Struct<{
|
|
11
|
+
readonly conclusion: Schema.optional<Schema.Literals<readonly ["action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"]>>;
|
|
12
|
+
readonly headSha: Schema.String;
|
|
13
|
+
readonly name: Schema.String;
|
|
14
|
+
readonly output: Schema.optional<Schema.Struct<{
|
|
15
|
+
readonly summary: Schema.String;
|
|
16
|
+
readonly text: Schema.optional<Schema.String>;
|
|
17
|
+
readonly title: Schema.String;
|
|
18
|
+
}>>;
|
|
19
|
+
readonly status: Schema.Literals<readonly ["queued", "in_progress", "completed"]>;
|
|
20
|
+
}>, {
|
|
21
|
+
readonly headSha: "head_sha";
|
|
22
|
+
}>;
|
|
23
|
+
export declare const UpdateCheckRun: Schema.Union<readonly [Schema.Struct<{
|
|
24
|
+
readonly output: Schema.optional<Schema.Struct<{
|
|
25
|
+
readonly summary: Schema.String;
|
|
26
|
+
readonly text: Schema.optional<Schema.String>;
|
|
27
|
+
readonly title: Schema.String;
|
|
28
|
+
}>>;
|
|
29
|
+
readonly status: Schema.Literals<readonly ["queued", "in_progress"]>;
|
|
30
|
+
}>, Schema.Struct<{
|
|
31
|
+
readonly conclusion: Schema.Literals<readonly ["action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"]>;
|
|
32
|
+
readonly output: Schema.optional<Schema.Struct<{
|
|
33
|
+
readonly summary: Schema.String;
|
|
34
|
+
readonly text: Schema.optional<Schema.String>;
|
|
35
|
+
readonly title: Schema.String;
|
|
36
|
+
}>>;
|
|
37
|
+
readonly status: Schema.Literal<"completed">;
|
|
38
|
+
}>]>;
|
|
39
|
+
export declare const CheckRun: Schema.encodeKeys<Schema.Struct<{
|
|
40
|
+
readonly conclusion: Schema.NullOr<Schema.Literals<readonly ["action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"]>>;
|
|
41
|
+
readonly headSha: Schema.String;
|
|
42
|
+
readonly id: Schema.Number;
|
|
43
|
+
readonly name: Schema.String;
|
|
44
|
+
readonly output: Schema.Struct<{
|
|
45
|
+
readonly summary: Schema.NullOr<Schema.String>;
|
|
46
|
+
readonly text: Schema.NullOr<Schema.String>;
|
|
47
|
+
readonly title: Schema.NullOr<Schema.String>;
|
|
48
|
+
}>;
|
|
49
|
+
readonly status: Schema.Literals<readonly ["queued", "in_progress", "completed"]>;
|
|
50
|
+
}>, {
|
|
51
|
+
readonly headSha: "head_sha";
|
|
52
|
+
}>;
|
|
53
|
+
export declare function checkRuns(client: Representations): {
|
|
54
|
+
createCheckRun: (owner: string, repo: string, input: {
|
|
55
|
+
readonly conclusion?: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | undefined;
|
|
56
|
+
readonly headSha: string;
|
|
57
|
+
readonly name: string;
|
|
58
|
+
readonly output?: {
|
|
59
|
+
readonly summary: string;
|
|
60
|
+
readonly text?: string | undefined;
|
|
61
|
+
readonly title: string;
|
|
62
|
+
} | undefined;
|
|
63
|
+
readonly status: "completed" | "in_progress" | "queued";
|
|
64
|
+
}) => Effect.Effect<{
|
|
65
|
+
readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
|
|
66
|
+
readonly headSha: string;
|
|
67
|
+
readonly id: number;
|
|
68
|
+
readonly name: string;
|
|
69
|
+
readonly output: {
|
|
70
|
+
readonly summary: string | null;
|
|
71
|
+
readonly text: string | null;
|
|
72
|
+
readonly title: string | null;
|
|
73
|
+
};
|
|
74
|
+
readonly status: "completed" | "in_progress" | "queued";
|
|
75
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
76
|
+
updateCheckRun: (owner: string, repo: string, id: number, input: {
|
|
77
|
+
readonly output?: {
|
|
78
|
+
readonly summary: string;
|
|
79
|
+
readonly text?: string | undefined;
|
|
80
|
+
readonly title: string;
|
|
81
|
+
} | undefined;
|
|
82
|
+
readonly status: "in_progress" | "queued";
|
|
83
|
+
} | {
|
|
84
|
+
readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out";
|
|
85
|
+
readonly output?: {
|
|
86
|
+
readonly summary: string;
|
|
87
|
+
readonly text?: string | undefined;
|
|
88
|
+
readonly title: string;
|
|
89
|
+
} | undefined;
|
|
90
|
+
readonly status: "completed";
|
|
91
|
+
}) => Effect.Effect<{
|
|
92
|
+
readonly conclusion: "action_required" | "cancelled" | "failure" | "neutral" | "skipped" | "stale" | "success" | "timed_out" | null;
|
|
93
|
+
readonly headSha: string;
|
|
94
|
+
readonly id: number;
|
|
95
|
+
readonly name: string;
|
|
96
|
+
readonly output: {
|
|
97
|
+
readonly summary: string | null;
|
|
98
|
+
readonly text: string | null;
|
|
99
|
+
readonly title: string | null;
|
|
100
|
+
};
|
|
101
|
+
readonly status: "completed" | "in_progress" | "queued";
|
|
102
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=checkRuns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkRuns.d.ts","sourceRoot":"","sources":["../src/checkRuns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,eAAO,MAAM,cAAc;;;;EAIzB,CAAC;AAEH,eAAO,MAAM,kBAAkB,8HAAsH,CAAC;AACtJ,eAAO,MAAM,cAAc,kEAA0D,CAAC;AAEtF,eAAO,MAAM,cAAc;;;;;;;;;;;;EAMwB,CAAC;AAEpD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;IAGzB,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;EAO8B,CAAC;AAEpD,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe;IAE/C,cAAc;;;;;;;;;;;;;;;;;;;;;;IAKd,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMf"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
export const CheckRunOutput = Schema.Struct({
|
|
3
|
+
summary: Schema.String,
|
|
4
|
+
text: Schema.optional(Schema.String),
|
|
5
|
+
title: Schema.String,
|
|
6
|
+
});
|
|
7
|
+
export const CheckRunConclusion = Schema.Literals(["action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"]);
|
|
8
|
+
export const CheckRunStatus = Schema.Literals(["queued", "in_progress", "completed"]);
|
|
9
|
+
export const CreateCheckRun = Schema.Struct({
|
|
10
|
+
conclusion: Schema.optional(CheckRunConclusion),
|
|
11
|
+
headSha: Schema.String,
|
|
12
|
+
name: Schema.String,
|
|
13
|
+
output: Schema.optional(CheckRunOutput),
|
|
14
|
+
status: CheckRunStatus,
|
|
15
|
+
}).pipe(Schema.encodeKeys({ headSha: "head_sha" }));
|
|
16
|
+
export const UpdateCheckRun = Schema.Union([
|
|
17
|
+
Schema.Struct({ output: Schema.optional(CheckRunOutput), status: Schema.Literals(["queued", "in_progress"]) }),
|
|
18
|
+
Schema.Struct({ conclusion: CheckRunConclusion, output: Schema.optional(CheckRunOutput), status: Schema.Literal("completed") }),
|
|
19
|
+
]);
|
|
20
|
+
export const CheckRun = Schema.Struct({
|
|
21
|
+
conclusion: Schema.NullOr(CheckRunConclusion),
|
|
22
|
+
headSha: Schema.String,
|
|
23
|
+
id: Schema.Number,
|
|
24
|
+
name: Schema.String,
|
|
25
|
+
output: Schema.Struct({ summary: Schema.NullOr(Schema.String), text: Schema.NullOr(Schema.String), title: Schema.NullOr(Schema.String) }),
|
|
26
|
+
status: CheckRunStatus,
|
|
27
|
+
}).pipe(Schema.encodeKeys({ headSha: "head_sha" }));
|
|
28
|
+
export function checkRuns(client) {
|
|
29
|
+
return {
|
|
30
|
+
createCheckRun: Effect.fn("GitHub.createCheckRun")(function* (owner, repo, input) {
|
|
31
|
+
const body = yield* Schema.encodeEffect(CreateCheckRun)(input);
|
|
32
|
+
const response = yield* client.write("POST", `/repos/${owner}/${repo}/check-runs`, body);
|
|
33
|
+
return yield* response.decode(CheckRun);
|
|
34
|
+
}),
|
|
35
|
+
updateCheckRun: Effect.fn("GitHub.updateCheckRun")(function* (owner, repo, id, input) {
|
|
36
|
+
const body = yield* Schema.encodeEffect(UpdateCheckRun)(input);
|
|
37
|
+
const response = yield* client.write("PATCH", `/repos/${owner}/${repo}/check-runs/${id}`, body);
|
|
38
|
+
return yield* response.decode(CheckRun);
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=checkRuns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkRuns.js","sourceRoot":"","sources":["../src/checkRuns.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import { HttpClientRequest } from "effect/http";
|
|
3
|
+
import type { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
4
|
+
import type { requests } from "#requests.ts";
|
|
5
|
+
export declare function representations(apiUrl: string, request: ReturnType<typeof requests>, resource: (path: string) => string): {
|
|
6
|
+
get: (path: string, accept?: string) => HttpClientRequest.HttpClientRequest;
|
|
7
|
+
list: (path: string, beforeRequest?: (resource: string) => Effect.Effect<void, ServiceUnavailable>) => Effect.Effect<Stream.Stream<{
|
|
8
|
+
decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
|
|
9
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>, never, never>;
|
|
10
|
+
read: (path: string) => Effect.Effect<{
|
|
11
|
+
decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
|
|
12
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
13
|
+
write: (method: "POST" | "PATCH", path: string, body: unknown) => Effect.Effect<{
|
|
14
|
+
decode: <TSchema extends import("effect/Schema").Constraint>(schema: TSchema) => Effect.Effect<TSchema["Type"], import("effect/Schema").SchemaError, TSchema["DecodingServices"]>;
|
|
15
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
16
|
+
};
|
|
17
|
+
export type Representations = Omit<ReturnType<typeof representations>, "get">;
|
|
18
|
+
//# sourceMappingURL=representations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"representations.d.ts","sourceRoot":"","sources":["../src/representations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAc,iBAAiB,EAA2B,MAAM,aAAa,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAIjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;gBACpG,MAAM;iBAMU,MAAM,kBAAkB,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,kBAAkB,CAAC;;;iBAHtF,MAAM;;;oBAyBH,MAAM,GAAG,OAAO,QAAQ,MAAM,QAAQ,OAAO;;;EAQlF;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import { HttpClient, HttpClientRequest } from "effect/http";
|
|
3
|
+
import { paginate } from "@shivaedev/platform/http-client/paginate.ts";
|
|
4
|
+
import { jsonResponse } from "#json.ts";
|
|
5
|
+
export function representations(apiUrl, request, resource) {
|
|
6
|
+
function get(path, accept = "application/vnd.github+json") {
|
|
7
|
+
return HttpClientRequest.get(new URL(path, apiUrl).href, { headers: { Accept: accept } });
|
|
8
|
+
}
|
|
9
|
+
function readRepresentation(path) {
|
|
10
|
+
return Effect.map(request(get(path), 1024 * 1024), jsonResponse);
|
|
11
|
+
}
|
|
12
|
+
function listRepresentations(path, beforeRequest) {
|
|
13
|
+
const entries = new WeakMap();
|
|
14
|
+
function fetchPage(input) {
|
|
15
|
+
return (beforeRequest?.(resource(new URL(input.url).pathname)) ?? Effect.void).pipe(Effect.andThen(request(input, 1024 * 1024)), Effect.map((entry) => {
|
|
16
|
+
entries.set(entry.response, entry);
|
|
17
|
+
return entry.response;
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
const client = HttpClient.makeWith((effect) => Effect.flatMap(effect, fetchPage), Effect.succeed);
|
|
21
|
+
return Effect.succeed(paginate(client, get(path)).pipe(Stream.mapEffect((response) => Effect.fromNullishOr(entries.get(response))), Stream.map(jsonResponse)));
|
|
22
|
+
}
|
|
23
|
+
function writeRepresentation(method, path, body) {
|
|
24
|
+
return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe(HttpClientRequest.bodyJson(body), Effect.flatMap((input) => request(input, 1024 * 1024)), Effect.map(jsonResponse));
|
|
25
|
+
}
|
|
26
|
+
return { get, list: listRepresentations, read: readRepresentation, write: writeRepresentation };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=representations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"representations.js","sourceRoot":"","sources":["../src/representations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAA2B,MAAM,aAAa,CAAC;AAErF,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,OAAoC,EAAE,QAAkC;IACvH,SAAS,GAAG,CAAC,IAAY,EAAE,MAAM,GAAG,6BAA6B;QAChE,OAAO,iBAAiB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,SAAS,kBAAkB,CAAC,IAAY;QACvC,OAAO,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC;IAClE,CAAC;IACD,SAAS,mBAAmB,CAAC,IAAY,EAAE,aAA6E;QACvH,MAAM,OAAO,GAAG,IAAI,OAAO,EAAyD,CAAC;QACrF,SAAS,SAAS,CAAC,KAA0C;YAC5D,OAAO,CAAC,aAAa,EAAE,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAClF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,EAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACnC,OAAO,KAAK,CAAC,QAAQ,CAAC;YACvB,CAAC,CAAC,CACF,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CACjC,CAAC,MAA0D,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EACjG,MAAM,CAAC,OAAO,CACd,CAAC;QACF,OAAO,MAAM,CAAC,OAAO,CACpB,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAC/B,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAC3E,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CACxB,CACD,CAAC;IACH,CAAC;IACD,SAAS,mBAAmB,CAAC,MAAwB,EAAE,IAAY,EAAE,IAAa;QACjF,OAAO,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,EAAE,CAAC,CAAC,IAAI,CAC7H,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAChC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC,EACtD,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CACxB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { Representations } from "./representations.ts";
|
|
3
|
+
export declare const PullRequestComment: Schema.Struct<{
|
|
4
|
+
readonly body: Schema.String;
|
|
5
|
+
readonly id: Schema.Number;
|
|
6
|
+
readonly user: Schema.NullOr<Schema.Struct<{
|
|
7
|
+
readonly login: Schema.String;
|
|
8
|
+
}>>;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const StickyComment: Schema.Struct<{
|
|
11
|
+
readonly author: Schema.optional<Schema.String>;
|
|
12
|
+
readonly body: Schema.String;
|
|
13
|
+
readonly marker: Schema.String;
|
|
14
|
+
readonly number: Schema.Number;
|
|
15
|
+
readonly owner: Schema.String;
|
|
16
|
+
readonly repo: Schema.String;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function stickyComments(client: Representations): {
|
|
19
|
+
upsertStickyComment: (input: {
|
|
20
|
+
readonly author?: string | undefined;
|
|
21
|
+
readonly body: string;
|
|
22
|
+
readonly marker: string;
|
|
23
|
+
readonly number: number;
|
|
24
|
+
readonly owner: string;
|
|
25
|
+
readonly repo: string;
|
|
26
|
+
}) => Effect.Effect<{
|
|
27
|
+
readonly body: string;
|
|
28
|
+
readonly id: number;
|
|
29
|
+
readonly user: {
|
|
30
|
+
readonly login: string;
|
|
31
|
+
} | null;
|
|
32
|
+
}, import("./errors.ts").GitHubAppError | import("./errors.ts").GitHubRateLimited | import("./errors.ts").GitHubTransportError | import("effect/http/HttpBody").HttpBodyError | import("effect/Cause").NoSuchElementError | import("@shivaedev/platform/http-client/errors.ts").PaginationLinkError | import("@shivaedev/platform/http-client/errors.ts").ResponseBodyTooLarge | Schema.SchemaError | import("@shivaedev/platform/errors/taxonomy.ts").ServiceUnavailable | import("@shivaedev/platform/http-client/errors.ts").RemoteStatusError, never>;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=stickyComments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stickyComments.d.ts","sourceRoot":"","sources":["../src/stickyComments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,eAAO,MAAM,kBAAkB;;;;;;EAI7B,CAAC;AAEH,eAAO,MAAM,aAAa;;;;;;;EAOxB,CAAC;AAIH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe;IAEpD,mBAAmB;;;;;;;;;;;;;;EAkBpB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Effect, Option, Schema, Stream } from "effect";
|
|
2
|
+
export const PullRequestComment = Schema.Struct({
|
|
3
|
+
body: Schema.String,
|
|
4
|
+
id: Schema.Number,
|
|
5
|
+
user: Schema.NullOr(Schema.Struct({ login: Schema.String })),
|
|
6
|
+
});
|
|
7
|
+
export const StickyComment = Schema.Struct({
|
|
8
|
+
author: Schema.optional(Schema.String),
|
|
9
|
+
body: Schema.String,
|
|
10
|
+
marker: Schema.String,
|
|
11
|
+
number: Schema.Number,
|
|
12
|
+
owner: Schema.String,
|
|
13
|
+
repo: Schema.String,
|
|
14
|
+
});
|
|
15
|
+
const CommentBody = Schema.Struct({ body: Schema.String });
|
|
16
|
+
export function stickyComments(client) {
|
|
17
|
+
return {
|
|
18
|
+
upsertStickyComment: Effect.fn("GitHub.upsertStickyComment")(function* (input) {
|
|
19
|
+
const { owner, repo, number, marker, body, author } = yield* Schema.decodeUnknownEffect(StickyComment)(input);
|
|
20
|
+
const hiddenMarker = `<!-- ${marker} -->`;
|
|
21
|
+
const root = `/repos/${owner}/${repo}/issues`;
|
|
22
|
+
const pages = yield* client.list(`${root}/${number}/comments`);
|
|
23
|
+
const existing = yield* pages.pipe(Stream.mapEffect((page) => page.decode(Schema.Array(PullRequestComment))), Stream.flatMap(Stream.fromIterable), Stream.filter((comment) => comment.body.includes(hiddenMarker) && (author === undefined || comment.user?.login === author)), Stream.runHead);
|
|
24
|
+
const payload = yield* Schema.encodeEffect(CommentBody)({ body: `${hiddenMarker}\n${body}` });
|
|
25
|
+
const response = yield* Option.isSome(existing)
|
|
26
|
+
? client.write("PATCH", `${root}/comments/${existing.value.id}`, payload)
|
|
27
|
+
: client.write("POST", `${root}/${number}/comments`, payload);
|
|
28
|
+
return yield* response.decode(PullRequestComment);
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=stickyComments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stickyComments.js","sourceRoot":"","sources":["../src/stickyComments.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Typed GitHub REST requests, conditional reads and resource budgets for Effect applications",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-github#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@shivaedev/effect-service": "0.4.1",
|
|
43
|
-
"@shivaedev/platform": "0.28.
|
|
43
|
+
"@shivaedev/platform": "0.28.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@effect/platform-node": "4.0.5",
|
|
47
47
|
"@effect/platform-node-shared": "4.0.5",
|
|
48
48
|
"@effect/vitest": "4.0.5",
|
|
49
49
|
"@shivaedev/effect-test": "0.8.1",
|
|
50
|
-
"@shivaedev/quality": "0.
|
|
50
|
+
"@shivaedev/quality": "0.39.0",
|
|
51
51
|
"@shivaedev/test-story": "0.19.0",
|
|
52
52
|
"@types/node": "24.19.2",
|
|
53
53
|
"effect": "4.0.5",
|
package/src/GitHub.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Effect, Schema, Stream } from "effect";
|
|
2
|
-
import { HttpClient
|
|
2
|
+
import { HttpClient } from "effect/http";
|
|
3
3
|
import { defineService } from "@shivaedev/effect-service/defineService.ts";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { requests } from "./requests.ts";
|
|
4
|
+
import { checkRuns } from "#checkRuns.ts";
|
|
5
|
+
import { GitHubConfig } from "#GitHubConfig.ts";
|
|
6
|
+
import { GitHubToken } from "#GitHubToken.ts";
|
|
7
|
+
import { rateLimits } from "#rateLimits.ts";
|
|
8
|
+
import { representations } from "#representations.ts";
|
|
9
|
+
import { requests } from "#requests.ts";
|
|
10
|
+
import { stickyComments } from "#stickyComments.ts";
|
|
12
11
|
|
|
13
12
|
export const GitHub = defineService({
|
|
14
13
|
id: "@shivaedev/effect-github/GitHub",
|
|
@@ -22,50 +21,16 @@ export const GitHub = defineService({
|
|
|
22
21
|
};
|
|
23
22
|
}),
|
|
24
23
|
methods: ({ apiUrl, rates, request }) => {
|
|
25
|
-
|
|
26
|
-
return HttpClientRequest.get(new URL(path, apiUrl).href, { headers: { Accept: accept } });
|
|
27
|
-
}
|
|
28
|
-
function readRepresentation(path: string) {
|
|
29
|
-
return Effect.map(request(get(path), 1024 * 1024), jsonResponse);
|
|
30
|
-
}
|
|
31
|
-
function listRepresentations(path: string, beforeRequest?: (resource: string) => Effect.Effect<void, ServiceUnavailable>) {
|
|
32
|
-
const entries = new WeakMap<HttpClientResponse.HttpClientResponse, CachedResponse>();
|
|
33
|
-
function fetchPage(input: HttpClientRequest.HttpClientRequest) {
|
|
34
|
-
return (beforeRequest?.(rates.resource(new URL(input.url).pathname)) ?? Effect.void).pipe(
|
|
35
|
-
Effect.andThen(request(input, 1024 * 1024)),
|
|
36
|
-
Effect.map((entry) => {
|
|
37
|
-
entries.set(entry.response, entry);
|
|
38
|
-
return entry.response;
|
|
39
|
-
}),
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
const client = HttpClient.makeWith(
|
|
43
|
-
(effect: Effect.Effect<HttpClientRequest.HttpClientRequest>) => Effect.flatMap(effect, fetchPage),
|
|
44
|
-
Effect.succeed,
|
|
45
|
-
);
|
|
46
|
-
return Effect.succeed(
|
|
47
|
-
paginate(client, get(path)).pipe(
|
|
48
|
-
Stream.mapEffect((response) => Effect.fromNullishOr(entries.get(response))),
|
|
49
|
-
Stream.map(jsonResponse),
|
|
50
|
-
),
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
function writeRepresentation(method: "POST" | "PATCH", path: string, body: unknown) {
|
|
54
|
-
return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe(
|
|
55
|
-
HttpClientRequest.bodyJson(body),
|
|
56
|
-
Effect.flatMap((input) => request(input, 1024 * 1024)),
|
|
57
|
-
Effect.map(jsonResponse),
|
|
58
|
-
);
|
|
59
|
-
}
|
|
24
|
+
const { get, ...client } = representations(apiUrl, request, rates.resource);
|
|
60
25
|
return {
|
|
61
26
|
bytes: (path: string, accept: string, limit: number) => Effect.map(request(get(path, accept), limit), (entry) => entry.bytes),
|
|
62
|
-
|
|
27
|
+
...client,
|
|
28
|
+
...stickyComments(client),
|
|
29
|
+
...checkRuns(client),
|
|
63
30
|
observations: () => Effect.sync(() => [...rates.observations.values()]),
|
|
64
|
-
read: readRepresentation,
|
|
65
31
|
resource: (path: string) => Effect.sync(() => rates.resource(new URL(path, apiUrl).pathname)),
|
|
66
32
|
text: (path: string, accept: string, limit: number) =>
|
|
67
33
|
Effect.map(request(get(path, accept), limit), (entry) => new TextDecoder().decode(entry.bytes)),
|
|
68
|
-
write: writeRepresentation,
|
|
69
34
|
};
|
|
70
35
|
},
|
|
71
36
|
requires: [HttpClient.HttpClient, GitHubToken],
|
package/src/checkRuns.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import type { Representations } from "./representations.ts";
|
|
3
|
+
|
|
4
|
+
export const CheckRunOutput = Schema.Struct({
|
|
5
|
+
summary: Schema.String,
|
|
6
|
+
text: Schema.optional(Schema.String),
|
|
7
|
+
title: Schema.String,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const CheckRunConclusion = Schema.Literals(["action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", "timed_out"]);
|
|
11
|
+
export const CheckRunStatus = Schema.Literals(["queued", "in_progress", "completed"]);
|
|
12
|
+
|
|
13
|
+
export const CreateCheckRun = Schema.Struct({
|
|
14
|
+
conclusion: Schema.optional(CheckRunConclusion),
|
|
15
|
+
headSha: Schema.String,
|
|
16
|
+
name: Schema.String,
|
|
17
|
+
output: Schema.optional(CheckRunOutput),
|
|
18
|
+
status: CheckRunStatus,
|
|
19
|
+
}).pipe(Schema.encodeKeys({ headSha: "head_sha" }));
|
|
20
|
+
|
|
21
|
+
export const UpdateCheckRun = Schema.Union([
|
|
22
|
+
Schema.Struct({ output: Schema.optional(CheckRunOutput), status: Schema.Literals(["queued", "in_progress"]) }),
|
|
23
|
+
Schema.Struct({ conclusion: CheckRunConclusion, output: Schema.optional(CheckRunOutput), status: Schema.Literal("completed") }),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
export const CheckRun = Schema.Struct({
|
|
27
|
+
conclusion: Schema.NullOr(CheckRunConclusion),
|
|
28
|
+
headSha: Schema.String,
|
|
29
|
+
id: Schema.Number,
|
|
30
|
+
name: Schema.String,
|
|
31
|
+
output: Schema.Struct({ summary: Schema.NullOr(Schema.String), text: Schema.NullOr(Schema.String), title: Schema.NullOr(Schema.String) }),
|
|
32
|
+
status: CheckRunStatus,
|
|
33
|
+
}).pipe(Schema.encodeKeys({ headSha: "head_sha" }));
|
|
34
|
+
|
|
35
|
+
export function checkRuns(client: Representations) {
|
|
36
|
+
return {
|
|
37
|
+
createCheckRun: Effect.fn("GitHub.createCheckRun")(function* (owner: string, repo: string, input: typeof CreateCheckRun.Type) {
|
|
38
|
+
const body = yield* Schema.encodeEffect(CreateCheckRun)(input);
|
|
39
|
+
const response = yield* client.write("POST", `/repos/${owner}/${repo}/check-runs`, body);
|
|
40
|
+
return yield* response.decode(CheckRun);
|
|
41
|
+
}),
|
|
42
|
+
updateCheckRun: Effect.fn("GitHub.updateCheckRun")(function* (owner: string, repo: string, id: number, input: typeof UpdateCheckRun.Type) {
|
|
43
|
+
const body = yield* Schema.encodeEffect(UpdateCheckRun)(input);
|
|
44
|
+
const response = yield* client.write("PATCH", `/repos/${owner}/${repo}/check-runs/${id}`, body);
|
|
45
|
+
return yield* response.decode(CheckRun);
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import { HttpClient, HttpClientRequest, type HttpClientResponse } from "effect/http";
|
|
3
|
+
import type { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
4
|
+
import { paginate } from "@shivaedev/platform/http-client/paginate.ts";
|
|
5
|
+
import type { CachedResponse } from "#cache.ts";
|
|
6
|
+
import { jsonResponse } from "#json.ts";
|
|
7
|
+
import type { requests } from "#requests.ts";
|
|
8
|
+
|
|
9
|
+
export function representations(apiUrl: string, request: ReturnType<typeof requests>, resource: (path: string) => string) {
|
|
10
|
+
function get(path: string, accept = "application/vnd.github+json") {
|
|
11
|
+
return HttpClientRequest.get(new URL(path, apiUrl).href, { headers: { Accept: accept } });
|
|
12
|
+
}
|
|
13
|
+
function readRepresentation(path: string) {
|
|
14
|
+
return Effect.map(request(get(path), 1024 * 1024), jsonResponse);
|
|
15
|
+
}
|
|
16
|
+
function listRepresentations(path: string, beforeRequest?: (resource: string) => Effect.Effect<void, ServiceUnavailable>) {
|
|
17
|
+
const entries = new WeakMap<HttpClientResponse.HttpClientResponse, CachedResponse>();
|
|
18
|
+
function fetchPage(input: HttpClientRequest.HttpClientRequest) {
|
|
19
|
+
return (beforeRequest?.(resource(new URL(input.url).pathname)) ?? Effect.void).pipe(
|
|
20
|
+
Effect.andThen(request(input, 1024 * 1024)),
|
|
21
|
+
Effect.map((entry) => {
|
|
22
|
+
entries.set(entry.response, entry);
|
|
23
|
+
return entry.response;
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
const client = HttpClient.makeWith(
|
|
28
|
+
(effect: Effect.Effect<HttpClientRequest.HttpClientRequest>) => Effect.flatMap(effect, fetchPage),
|
|
29
|
+
Effect.succeed,
|
|
30
|
+
);
|
|
31
|
+
return Effect.succeed(
|
|
32
|
+
paginate(client, get(path)).pipe(
|
|
33
|
+
Stream.mapEffect((response) => Effect.fromNullishOr(entries.get(response))),
|
|
34
|
+
Stream.map(jsonResponse),
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
function writeRepresentation(method: "POST" | "PATCH", path: string, body: unknown) {
|
|
39
|
+
return HttpClientRequest.make(method)(new URL(path, apiUrl).href, { headers: { Accept: "application/vnd.github+json" } }).pipe(
|
|
40
|
+
HttpClientRequest.bodyJson(body),
|
|
41
|
+
Effect.flatMap((input) => request(input, 1024 * 1024)),
|
|
42
|
+
Effect.map(jsonResponse),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return { get, list: listRepresentations, read: readRepresentation, write: writeRepresentation };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type Representations = Omit<ReturnType<typeof representations>, "get">;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Effect, Option, Schema, Stream } from "effect";
|
|
2
|
+
import type { Representations } from "./representations.ts";
|
|
3
|
+
|
|
4
|
+
export const PullRequestComment = Schema.Struct({
|
|
5
|
+
body: Schema.String,
|
|
6
|
+
id: Schema.Number,
|
|
7
|
+
user: Schema.NullOr(Schema.Struct({ login: Schema.String })),
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export const StickyComment = Schema.Struct({
|
|
11
|
+
author: Schema.optional(Schema.String),
|
|
12
|
+
body: Schema.String,
|
|
13
|
+
marker: Schema.String,
|
|
14
|
+
number: Schema.Number,
|
|
15
|
+
owner: Schema.String,
|
|
16
|
+
repo: Schema.String,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const CommentBody = Schema.Struct({ body: Schema.String });
|
|
20
|
+
|
|
21
|
+
export function stickyComments(client: Representations) {
|
|
22
|
+
return {
|
|
23
|
+
upsertStickyComment: Effect.fn("GitHub.upsertStickyComment")(function* (input: typeof StickyComment.Type) {
|
|
24
|
+
const { owner, repo, number, marker, body, author } = yield* Schema.decodeUnknownEffect(StickyComment)(input);
|
|
25
|
+
const hiddenMarker = `<!-- ${marker} -->`;
|
|
26
|
+
const root = `/repos/${owner}/${repo}/issues`;
|
|
27
|
+
const pages = yield* client.list(`${root}/${number}/comments`);
|
|
28
|
+
const existing = yield* pages.pipe(
|
|
29
|
+
Stream.mapEffect((page) => page.decode(Schema.Array(PullRequestComment))),
|
|
30
|
+
Stream.flatMap(Stream.fromIterable),
|
|
31
|
+
Stream.filter((comment) => comment.body.includes(hiddenMarker) && (author === undefined || comment.user?.login === author)),
|
|
32
|
+
Stream.runHead,
|
|
33
|
+
);
|
|
34
|
+
const payload = yield* Schema.encodeEffect(CommentBody)({ body: `${hiddenMarker}\n${body}` });
|
|
35
|
+
const response = yield* Option.isSome(existing)
|
|
36
|
+
? client.write("PATCH", `${root}/comments/${existing.value.id}`, payload)
|
|
37
|
+
: client.write("POST", `${root}/${number}/comments`, payload);
|
|
38
|
+
return yield* response.decode(PullRequestComment);
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|