@effected/github 0.6.1 → 0.8.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/GitHubRepository.js +42 -1
- package/README.md +18 -2
- package/index.d.ts +55 -103
- package/index.js +3 -3
- package/package.json +2 -1
- package/tsdoc-metadata.json +1 -1
- package/IssueReferences.js +0 -126
package/GitHubRepository.js
CHANGED
|
@@ -5,6 +5,47 @@ import { Context, Effect, Layer, Schema } from "effect";
|
|
|
5
5
|
|
|
6
6
|
//#region src/GitHubRepository.ts
|
|
7
7
|
/**
|
|
8
|
+
* A {@link RepositoryPatch} from a draft, dropping every explicitly-`undefined`
|
|
9
|
+
* field.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* The supported spelling for "apply only what was configured" — the natural
|
|
13
|
+
* shape for a sync action, and the one the checker cannot follow on its own.
|
|
14
|
+
* Without it a consumer under the recommended tsconfig is quietly pushed toward
|
|
15
|
+
* `as`, which is a real cost in a package whose stated design property is that
|
|
16
|
+
* the route is the key and there are no casts.
|
|
17
|
+
*
|
|
18
|
+
* Dropping the key rather than sending `undefined` is what the wire needs:
|
|
19
|
+
* `PATCH` treats an absent field as "leave it alone", while an explicit `null`
|
|
20
|
+
* or `undefined` is a value.
|
|
21
|
+
*
|
|
22
|
+
* A key-by-key loop still defeats TypeScript's correlation between two indexed
|
|
23
|
+
* accesses (`draft[key] = source[key]` over a union `key`), which no helper can
|
|
24
|
+
* fix — build the draft as a literal where you can.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { repositoryPatch } from "@effected/github";
|
|
29
|
+
*
|
|
30
|
+
* // `config.has_issues` is `boolean | undefined`; absent fields drop out.
|
|
31
|
+
* const patch = repositoryPatch({
|
|
32
|
+
* has_issues: config.has_issues,
|
|
33
|
+
* has_wiki: config.has_wiki,
|
|
34
|
+
* description: config.description,
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @param draft - The fields to apply, any of which may be `undefined`.
|
|
39
|
+
* @returns A patch carrying only the fields that were actually set.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
const repositoryPatch = (draft) => {
|
|
44
|
+
const out = {};
|
|
45
|
+
for (const [key, value] of Object.entries(draft)) if (value !== void 0) out[key] = value;
|
|
46
|
+
return out;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
8
49
|
* Fields in the user-facing `security_and_analysis` block that GitHub accepts
|
|
9
50
|
* as `{ status: "enabled" | "disabled" }`.
|
|
10
51
|
*
|
|
@@ -234,4 +275,4 @@ const make = (client) => {
|
|
|
234
275
|
};
|
|
235
276
|
|
|
236
277
|
//#endregion
|
|
237
|
-
export { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, transformSecurityAndAnalysis };
|
|
278
|
+
export { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, repositoryPatch, transformSecurityAndAnalysis };
|
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ const program = Effect.gen(function* () {
|
|
|
122
122
|
|
|
123
123
|
The existence check pages the issue's comments to the end and matches the marker in `upsert`'s exact spelling, so a comment either member writes stays findable by the other. It is a look-before-write: two runs racing on the same issue can both see no marker and both post, so treat the marker as the record rather than the check as a lock.
|
|
124
124
|
|
|
125
|
-
Whether a run should comment at all usually turns on which issues a pull request closes, and that is a grammar rather than an API call.
|
|
125
|
+
Whether a run should comment at all usually turns on which issues a pull request closes, and that is a grammar rather than an API call. That grammar now lives in [`@effected/github-references`](https://www.npmjs.com/package/@effected/github-references), a pure package with no octokit behind it; this package re-exports the two dialects it used to own so existing code keeps compiling:
|
|
126
126
|
|
|
127
127
|
```ts
|
|
128
128
|
import { harvestIssueReferences, parseBareLineReference } from "@effected/github";
|
|
@@ -140,6 +140,8 @@ console.log(parseBareLineReference("closes #12 for real"));
|
|
|
140
140
|
|
|
141
141
|
`harvestIssueReferences` reads the **inline-in-prose** dialect: one of the nine closing keywords (`CLOSING_KEYWORDS`) followed by whitespace and `#<number>`, anywhere in the text, no colon — the spelling GitHub itself scans a pull request body for. Duplicates come back as written, because whether `fixes #1, fixes #1` means one intent or two is the caller's question. `parseBareLineReference` reads the **bare-line** dialect, where the whole trimmed line is the reference and the colon is optional — the shape a generated references block writes, one per line. Cross-repo (`owner/repo#12`) and full-URL references are out of scope.
|
|
142
142
|
|
|
143
|
+
The re-export covers exactly six names — `CLOSING_KEYWORDS`, `ClosingKeyword`, `IssueReference`, `harvestIssueReferences`, `BareLineReference`, `parseBareLineReference` — and may be dropped at a later release. Import from `@effected/github-references` directly for new code; it also carries a third dialect this package does not re-export, the closing list (`Closes #247, #248 and #251`).
|
|
144
|
+
|
|
143
145
|
## Repository configuration
|
|
144
146
|
|
|
145
147
|
Six services cover the half of a repository that is policy rather than content: `RepositorySecret`, `RepositoryVariable`, `Ruleset`, `DeploymentEnvironment`, `RepositorySecurity` and `CodeScanning`. They are shaped for a program applying the same configuration across a fleet, so every list read paginates to the end and a truncated page never becomes a wrong decision.
|
|
@@ -187,6 +189,19 @@ const program = Effect.gen(function* () {
|
|
|
187
189
|
// GitHub would reject, which is what a person reading a dry run is checking for.
|
|
188
190
|
```
|
|
189
191
|
|
|
192
|
+
`updateSettings` takes octokit's own generated params, and those spell an optional field as `has_issues?: boolean` rather than `has_issues?: boolean | undefined` — so under `exactOptionalPropertyTypes` a `Partial<T>` built from your own settings schema does not assign to it at all. `repositoryPatch` is the supported way out, and it exists so the answer is never a cast:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { repositoryPatch } from "@effected/github";
|
|
196
|
+
|
|
197
|
+
declare const config: { has_issues?: boolean | undefined; description?: string | undefined };
|
|
198
|
+
|
|
199
|
+
const patch = repositoryPatch({ has_issues: config.has_issues, description: config.description });
|
|
200
|
+
// a RepositoryPatch carrying only the fields that were actually set
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Dropping the key is what the wire needs: `PATCH` reads an absent field as "leave it alone", while an explicit `null` is a value. `RepositoryPatchDraft` is the input type — the same fields, each allowed to be an explicit `undefined`. Build the draft as an object literal where you can: a key-by-key loop defeats TypeScript's correlation between two indexed accesses, which no helper can repair.
|
|
204
|
+
|
|
190
205
|
`security_and_analysis` accepts both the bare `"enabled"` a human writes in a config file and the `{ status: "enabled" }` GitHub's own parameter type declares. A map touching neither GraphQL-only setting never reads the node id, so the common case stays one request. `ownerType` answers `"User"` or `"Organization"` for the repository in `Repo`, which is how a shared settings template drops the fields GitHub accepts only on an organization-owned repository before applying itself to a personal one.
|
|
191
206
|
|
|
192
207
|
## GitHub App authentication
|
|
@@ -266,6 +281,7 @@ const TestClient = GitHubClient.layerFixture(fixtures);
|
|
|
266
281
|
- `GitHubClient` — the typed transport: `request`, `requestDecoded` (a mandatory-schema escape hatch for routes outside the generated map), `paginate` / `paginateStream`, `graphql`, and `rateLimit` (observation only — nothing here throttles on your behalf).
|
|
267
282
|
- `Repo` / `RepoRef` — the `{ owner, repo }` coordinate, resolved per call through `R`, with `Repo.provide` for multi-repository programs.
|
|
268
283
|
- `GitHubRepository` — the repository's settings as GitHub's own generated type, plus `defaultBranch`, `nodeId`, `ownerType` for gating organization-only fields, and `applySettings` reporting the keys it actually sent.
|
|
284
|
+
- `repositoryPatch` / `RepositoryPatchDraft` — build an `updateSettings` patch from fields that may be `undefined`, under `exactOptionalPropertyTypes`, without a cast.
|
|
269
285
|
- `GitHubError` / `GitHubGraphQLError` — one error per transport, `kind`-routed with `hasKind` for `Effect.catchIf`.
|
|
270
286
|
- `RetryPolicy` — the client's one retry policy: full-jitter backoff, server-advised delays honored up to a ceiling.
|
|
271
287
|
- `GitHubApp` — App JWT signing, installation token minting/revocation, app and installation identity, and `clientLayer` for an App-authenticated `GitHubClient`.
|
|
@@ -273,7 +289,7 @@ const TestClient = GitHubClient.layerFixture(fixtures);
|
|
|
273
289
|
- `CheckRun` — `withCheckRun` concludes on every exit path; `CheckRunOutput.truncated()` cuts rendered output to GitHub's byte limits.
|
|
274
290
|
- `PullRequest` / `PullRequestComment` — upserts for both, `listFiles` answering with the same full `CommitFile` records a commit read returns, `headSha`/`baseSha` on `PullRequestInfo`, plus `CommentMarker` for finding a sticky comment again.
|
|
275
291
|
- `GitHubIssue` — issues and their comments, including `commentOnce` for a marked comment that is posted exactly once and never edited, and `linkedIssues` for what a pull request closes.
|
|
276
|
-
- `
|
|
292
|
+
- `harvestIssueReferences` / `parseBareLineReference` — a compatibility re-export of the two closing-reference dialects that moved to `@effected/github-references`, with `CLOSING_KEYWORDS` and their result types.
|
|
277
293
|
- `GitHubRelease` — releases and asset uploads, including the one route (`uploadAsset`, with the endpoint's optional display label) outside GitHub's generated endpoint map.
|
|
278
294
|
- `RepositorySecret` / `RepositoryVariable` — repository and environment secrets and variables, with the sealed-box encryption GitHub's secrets API demands kept in one module nothing else imports.
|
|
279
295
|
- `Ruleset` / `DeploymentEnvironment` / `RepositorySecurity` / `CodeScanning` — the rest of the configuration tier: rulesets matched by name and scope, idempotent environment writes, the three security toggles GitHub keeps off the repository endpoint, and CodeQL default setup with the language detection that gates it.
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BareLineReference, CLOSING_KEYWORDS, ClosingKeyword, IssueReference, harvestIssueReferences, parseBareLineReference } from "@effected/github-references";
|
|
1
2
|
import { Config, Context, Duration, Effect, Layer, Option, Redacted, Result, Schedule, Schema, Scope, Stream } from "effect";
|
|
2
3
|
import { PaginatingEndpoints } from "@octokit/plugin-paginate-rest";
|
|
3
4
|
import { Endpoints, RequestHeaders } from "@octokit/types";
|
|
@@ -2276,6 +2277,59 @@ type RepositorySettings = Data<"GET /repos/{owner}/{repo}">;
|
|
|
2276
2277
|
* @public
|
|
2277
2278
|
*/
|
|
2278
2279
|
type RepositoryPatch = Omit<Params<"PATCH /repos/{owner}/{repo}">, "owner" | "repo">;
|
|
2280
|
+
/**
|
|
2281
|
+
* A {@link RepositoryPatch} under construction, where an absent field may be
|
|
2282
|
+
* spelled as an explicit `undefined`.
|
|
2283
|
+
*
|
|
2284
|
+
* @remarks
|
|
2285
|
+
* The shape you actually have when you are applying only what a user
|
|
2286
|
+
* configured. Octokit's generated params spell an optional field as
|
|
2287
|
+
* `has_issues?: boolean`, **not** `has_issues?: boolean | undefined`, so under
|
|
2288
|
+
* `exactOptionalPropertyTypes` — on in this repo and in the silk tsconfig base
|
|
2289
|
+
* — a `Partial<T>` built from your own settings schema does not assign to
|
|
2290
|
+
* `RepositoryPatch` at all. This type does, and {@link repositoryPatch} turns
|
|
2291
|
+
* it into one.
|
|
2292
|
+
*
|
|
2293
|
+
* @public
|
|
2294
|
+
*/
|
|
2295
|
+
type RepositoryPatchDraft = { readonly [K in keyof RepositoryPatch]?: RepositoryPatch[K] | undefined; };
|
|
2296
|
+
/**
|
|
2297
|
+
* A {@link RepositoryPatch} from a draft, dropping every explicitly-`undefined`
|
|
2298
|
+
* field.
|
|
2299
|
+
*
|
|
2300
|
+
* @remarks
|
|
2301
|
+
* The supported spelling for "apply only what was configured" — the natural
|
|
2302
|
+
* shape for a sync action, and the one the checker cannot follow on its own.
|
|
2303
|
+
* Without it a consumer under the recommended tsconfig is quietly pushed toward
|
|
2304
|
+
* `as`, which is a real cost in a package whose stated design property is that
|
|
2305
|
+
* the route is the key and there are no casts.
|
|
2306
|
+
*
|
|
2307
|
+
* Dropping the key rather than sending `undefined` is what the wire needs:
|
|
2308
|
+
* `PATCH` treats an absent field as "leave it alone", while an explicit `null`
|
|
2309
|
+
* or `undefined` is a value.
|
|
2310
|
+
*
|
|
2311
|
+
* A key-by-key loop still defeats TypeScript's correlation between two indexed
|
|
2312
|
+
* accesses (`draft[key] = source[key]` over a union `key`), which no helper can
|
|
2313
|
+
* fix — build the draft as a literal where you can.
|
|
2314
|
+
*
|
|
2315
|
+
* @example
|
|
2316
|
+
* ```ts
|
|
2317
|
+
* import { repositoryPatch } from "@effected/github";
|
|
2318
|
+
*
|
|
2319
|
+
* // `config.has_issues` is `boolean | undefined`; absent fields drop out.
|
|
2320
|
+
* const patch = repositoryPatch({
|
|
2321
|
+
* has_issues: config.has_issues,
|
|
2322
|
+
* has_wiki: config.has_wiki,
|
|
2323
|
+
* description: config.description,
|
|
2324
|
+
* });
|
|
2325
|
+
* ```
|
|
2326
|
+
*
|
|
2327
|
+
* @param draft - The fields to apply, any of which may be `undefined`.
|
|
2328
|
+
* @returns A patch carrying only the fields that were actually set.
|
|
2329
|
+
*
|
|
2330
|
+
* @public
|
|
2331
|
+
*/
|
|
2332
|
+
declare const repositoryPatch: (draft: RepositoryPatchDraft) => RepositoryPatch;
|
|
2279
2333
|
/**
|
|
2280
2334
|
* Whether an account is a user or an organization.
|
|
2281
2335
|
*
|
|
@@ -2549,108 +2603,6 @@ declare class GitTag extends GitTag_base {
|
|
|
2549
2603
|
static readonly layerTest: (overrides?: Partial<GitTagShape>) => Layer.Layer<GitTag>;
|
|
2550
2604
|
}
|
|
2551
2605
|
//#endregion
|
|
2552
|
-
//#region src/IssueReferences.d.ts
|
|
2553
|
-
/**
|
|
2554
|
-
* GitHub's closing-keyword issue-reference grammar, as pure functions.
|
|
2555
|
-
*
|
|
2556
|
-
* @remarks
|
|
2557
|
-
* GitHub links an issue to a pull request when the PR's description carries
|
|
2558
|
-
* `<keyword> #<number>` for one of nine documented keywords. Consumers speak
|
|
2559
|
-
* that grammar in two distinct dialects, and this module models exactly those
|
|
2560
|
-
* two — no service, no layer, nothing but strings in and values out:
|
|
2561
|
-
*
|
|
2562
|
-
* - **Inline-in-prose** ({@link harvestIssueReferences}): a reference may appear anywhere in
|
|
2563
|
-
* running text — `"fixes #12 and closes #13"` — with mandatory whitespace
|
|
2564
|
-
* and **no colon**, because that is the spelling GitHub itself scans PR
|
|
2565
|
-
* bodies for. This is the dialect a release pipeline harvests from commit
|
|
2566
|
-
* subjects and PR descriptions.
|
|
2567
|
-
* - **Bare-line** ({@link parseBareLineReference}): the whole line, after trimming, *is*
|
|
2568
|
-
* the reference — `"Closes: #12"` — with an **optional colon**, because a
|
|
2569
|
-
* generated references region writes one reference per line and a colon
|
|
2570
|
-
* reads better there. GitHub does not require the colon; the region format
|
|
2571
|
-
* allows it, so the parser must too. The dialects differ because their
|
|
2572
|
-
* producers do: prose is written by humans for GitHub's scanner, the region
|
|
2573
|
-
* is written by tooling for humans.
|
|
2574
|
-
*
|
|
2575
|
-
* Deliberately out of scope this round: cross-repo references
|
|
2576
|
-
* (`owner/repo#N`) and full-URL references
|
|
2577
|
-
* (`https://github.com/owner/repo/issues/N`). Both are real GitHub spellings;
|
|
2578
|
-
* neither dialect's consumers emit them yet, and guessing at their shape here
|
|
2579
|
-
* would freeze an API nobody has driven.
|
|
2580
|
-
*/
|
|
2581
|
-
/**
|
|
2582
|
-
* The nine closing keywords GitHub documents, lowercased.
|
|
2583
|
-
*
|
|
2584
|
-
* @public
|
|
2585
|
-
*/
|
|
2586
|
-
declare const CLOSING_KEYWORDS: readonly ["close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"];
|
|
2587
|
-
/**
|
|
2588
|
-
* One of the nine documented closing keywords, in canonical lowercase form.
|
|
2589
|
-
*
|
|
2590
|
-
* @public
|
|
2591
|
-
*/
|
|
2592
|
-
type ClosingKeyword = (typeof CLOSING_KEYWORDS)[number];
|
|
2593
|
-
/**
|
|
2594
|
-
* One closing reference found in prose by {@link harvestIssueReferences}.
|
|
2595
|
-
*
|
|
2596
|
-
* @public
|
|
2597
|
-
*/
|
|
2598
|
-
interface IssueReference {
|
|
2599
|
-
/** The referenced issue number. */
|
|
2600
|
-
readonly issueNumber: number;
|
|
2601
|
-
/** The matched keyword, lowercased to its canonical form. */
|
|
2602
|
-
readonly keyword: ClosingKeyword;
|
|
2603
|
-
/** Offset of the first character of the whole match (`keyword` through digits). */
|
|
2604
|
-
readonly start: number;
|
|
2605
|
-
/** Offset one past the last character of the whole match. */
|
|
2606
|
-
readonly end: number;
|
|
2607
|
-
}
|
|
2608
|
-
/**
|
|
2609
|
-
* The closing reference a bare line carries, per {@link parseBareLineReference}.
|
|
2610
|
-
*
|
|
2611
|
-
* @remarks
|
|
2612
|
-
* No offsets: in the bare-line dialect the whole line is the reference, so
|
|
2613
|
-
* positions within it locate nothing a caller acts on.
|
|
2614
|
-
*
|
|
2615
|
-
* @public
|
|
2616
|
-
*/
|
|
2617
|
-
interface BareLineReference {
|
|
2618
|
-
/** The referenced issue number. */
|
|
2619
|
-
readonly issueNumber: number;
|
|
2620
|
-
/** The matched keyword, lowercased to its canonical form. */
|
|
2621
|
-
readonly keyword: ClosingKeyword;
|
|
2622
|
-
}
|
|
2623
|
-
/**
|
|
2624
|
-
* Every inline closing reference in `text`, in document order.
|
|
2625
|
-
*
|
|
2626
|
-
* @remarks
|
|
2627
|
-
* The **inline-in-prose** dialect: case-insensitive `<keyword> #<number>`
|
|
2628
|
-
* anywhere in the text, whitespace mandatory, colon not accepted — a colon
|
|
2629
|
-
* spelling belongs to the bare-line dialect and {@link parseBareLineReference}.
|
|
2630
|
-
* Duplicates are preserved: whether `fixes #1, fixes #1` means one reference
|
|
2631
|
-
* or two is the caller's business, not a parser's.
|
|
2632
|
-
*
|
|
2633
|
-
* A match whose digits exceed `Number.MAX_SAFE_INTEGER` is skipped, not
|
|
2634
|
-
* misparsed — see the module remarks for the scope boundary.
|
|
2635
|
-
*
|
|
2636
|
-
* @public
|
|
2637
|
-
*/
|
|
2638
|
-
declare const harvestIssueReferences: (text: string) => ReadonlyArray<IssueReference>;
|
|
2639
|
-
/**
|
|
2640
|
-
* The reference a whole line carries, or `Option.none()`.
|
|
2641
|
-
*
|
|
2642
|
-
* @remarks
|
|
2643
|
-
* The **bare-line** dialect: after trimming, the entire line must be
|
|
2644
|
-
* `<keyword>[:] #<number>` — keyword case-insensitive, colon optional,
|
|
2645
|
-
* whitespace before the `#` mandatory. Trailing prose, a missing keyword, or
|
|
2646
|
-
* anything else at all is a rejection, never a partial parse; a line carries
|
|
2647
|
-
* one reference or none. Digits past `Number.MAX_SAFE_INTEGER` reject too,
|
|
2648
|
-
* for the same reason {@link harvestIssueReferences} skips them.
|
|
2649
|
-
*
|
|
2650
|
-
* @public
|
|
2651
|
-
*/
|
|
2652
|
-
declare const parseBareLineReference: (line: string) => Option.Option<BareLineReference>;
|
|
2653
|
-
//#endregion
|
|
2654
2606
|
//#region src/PullRequest.d.ts
|
|
2655
2607
|
/** How a pull request is merged. @public */
|
|
2656
2608
|
declare const MergeMethod: Schema.Literals<readonly ["merge", "squash", "rebase"]>;
|
|
@@ -3380,5 +3332,5 @@ declare class WorkflowDispatch extends WorkflowDispatch_base {
|
|
|
3380
3332
|
static readonly layerTest: (overrides?: Partial<WorkflowDispatchShape>) => Layer.Layer<WorkflowDispatch>;
|
|
3381
3333
|
}
|
|
3382
3334
|
//#endregion
|
|
3383
|
-
export { Annotation, AnnotationLevel, type AppCredentials, AppIdentity, type AppliedSettings, ArtifactMetadata, type ArtifactMetadataShape, Attestation, AttestationListEntry, AttestationRecord, type AttestationShape, type BareLineReference, BotIdentity, type BranchOutcome, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, type CheckRunShape, type ClosingKeyword, CodeScanning, type CodeScanningSetup, type CodeScanningShape, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, type ConcludeCheckRun, DeploymentEnvironment, type DeploymentEnvironmentInfo, type DeploymentEnvironmentShape, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, type GitBranchShape, GitCommit, type GitCommitShape, GitHubApp, GitHubAppError, type GitHubAppOptions, type GitHubAppShape, GitHubClient, type GitHubClientOptions, type GitHubClientShape, GitHubCommit, type GitHubCommitShape, GitHubContent, type GitHubContentShape, GitHubError, GitHubErrorKind, type GitHubFixtures, GitHubGraphQLError, GitHubIssue, type GitHubIssueShape, GitHubRelease, type GitHubReleaseShape, GitHubRepository, type GitHubRepositoryShape, GitTag, type GitTagShape, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, type IssueReference, type LatestSemverOptions, LinkedIssue, MergeMethod, type OwnerType, PageOptions, PermissionGap, PermissionLevel, PermissionResult, type PollOptions, PullRequest, PullRequestComment, type PullRequestCommentShape, PullRequestInfo, type PullRequestShape, RateLimitSnapshot, type RecordedCall, ReleaseAsset, ReleaseInfo, Repo, RepoRef, type RepositoryPatch, RepositorySecret, type RepositorySecretShape, RepositorySecurity, type RepositorySecurityShape, type RepositorySettings, RepositoryVariable, type RepositoryVariableShape, type Data as RestData, type RequestExtras as RestExtras, type Item as RestItem, type PaginatingRoute as RestPaginatingRoute, type Params as RestParams, type Response as RestResponse, type Route as RestRoute, RetryPolicy, type RetryableFailure, Ruleset, type RulesetInfo, type RulesetPayload, type RulesetShape, SECURITY_ANALYSIS_STATUS_FIELDS, type SecretInfo, type SecretScope, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, type TokenRequest, type UpsertedPullRequest, type VariableInfo, type VersionFromTag, WorkflowDispatch, type WorkflowDispatchShape, type WorkflowInfo, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, transformSecurityAndAnalysis, versionFromTag };
|
|
3335
|
+
export { Annotation, AnnotationLevel, type AppCredentials, AppIdentity, type AppliedSettings, ArtifactMetadata, type ArtifactMetadataShape, Attestation, AttestationListEntry, AttestationRecord, type AttestationShape, type BareLineReference, BotIdentity, type BranchOutcome, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, type CheckRunShape, type ClosingKeyword, CodeScanning, type CodeScanningSetup, type CodeScanningShape, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, type ConcludeCheckRun, DeploymentEnvironment, type DeploymentEnvironmentInfo, type DeploymentEnvironmentShape, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, type GitBranchShape, GitCommit, type GitCommitShape, GitHubApp, GitHubAppError, type GitHubAppOptions, type GitHubAppShape, GitHubClient, type GitHubClientOptions, type GitHubClientShape, GitHubCommit, type GitHubCommitShape, GitHubContent, type GitHubContentShape, GitHubError, GitHubErrorKind, type GitHubFixtures, GitHubGraphQLError, GitHubIssue, type GitHubIssueShape, GitHubRelease, type GitHubReleaseShape, GitHubRepository, type GitHubRepositoryShape, GitTag, type GitTagShape, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, type IssueReference, type LatestSemverOptions, LinkedIssue, MergeMethod, type OwnerType, PageOptions, PermissionGap, PermissionLevel, PermissionResult, type PollOptions, PullRequest, PullRequestComment, type PullRequestCommentShape, PullRequestInfo, type PullRequestShape, RateLimitSnapshot, type RecordedCall, ReleaseAsset, ReleaseInfo, Repo, RepoRef, type RepositoryPatch, type RepositoryPatchDraft, RepositorySecret, type RepositorySecretShape, RepositorySecurity, type RepositorySecurityShape, type RepositorySettings, RepositoryVariable, type RepositoryVariableShape, type Data as RestData, type RequestExtras as RestExtras, type Item as RestItem, type PaginatingRoute as RestPaginatingRoute, type Params as RestParams, type Response as RestResponse, type Route as RestRoute, RetryPolicy, type RetryableFailure, Ruleset, type RulesetInfo, type RulesetPayload, type RulesetShape, SECURITY_ANALYSIS_STATUS_FIELDS, type SecretInfo, type SecretScope, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, type TokenRequest, type UpsertedPullRequest, type VariableInfo, type VersionFromTag, WorkflowDispatch, type WorkflowDispatchShape, type WorkflowInfo, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, repositoryPatch, transformSecurityAndAnalysis, versionFromTag };
|
|
3384
3336
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -16,9 +16,8 @@ import { GitHubContent } from "./GitHubContent.js";
|
|
|
16
16
|
import { CommentMarker, CommentRecord, PullRequestComment } from "./PullRequestComment.js";
|
|
17
17
|
import { CommentOnceResult, GitHubIssue, IssueInfo, LinkedIssue } from "./GitHubIssue.js";
|
|
18
18
|
import { GitHubRelease, ReleaseAsset, ReleaseInfo } from "./GitHubRelease.js";
|
|
19
|
-
import { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, transformSecurityAndAnalysis } from "./GitHubRepository.js";
|
|
19
|
+
import { GRAPHQL_ONLY_SETTINGS, GitHubRepository, SECURITY_ANALYSIS_STATUS_FIELDS, repositoryPatch, transformSecurityAndAnalysis } from "./GitHubRepository.js";
|
|
20
20
|
import { GitTag, SemverTag, TagRef, versionFromTag } from "./GitTag.js";
|
|
21
|
-
import { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference } from "./IssueReferences.js";
|
|
22
21
|
import { PageOptions } from "./Rest.js";
|
|
23
22
|
import { MergeMethod, PullRequest, PullRequestInfo } from "./PullRequest.js";
|
|
24
23
|
import { RepositorySecret } from "./RepositorySecret.js";
|
|
@@ -27,5 +26,6 @@ import { RepositoryVariable } from "./RepositoryVariable.js";
|
|
|
27
26
|
import { Ruleset } from "./Ruleset.js";
|
|
28
27
|
import { ExtraPermission, PermissionGap, PermissionLevel, PermissionResult, TokenPermissionError, TokenPermissions } from "./TokenPermissions.js";
|
|
29
28
|
import { WorkflowDispatch, WorkflowRunStatus } from "./WorkflowDispatch.js";
|
|
29
|
+
import { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference } from "@effected/github-references";
|
|
30
30
|
|
|
31
|
-
export { Annotation, AnnotationLevel, AppIdentity, ArtifactMetadata, Attestation, AttestationListEntry, AttestationRecord, BotIdentity, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CodeScanning, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, DeploymentEnvironment, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, GitCommit, GitHubApp, GitHubAppError, GitHubClient, GitHubCommit, GitHubContent, GitHubError, GitHubErrorKind, GitHubGraphQLError, GitHubIssue, GitHubRelease, GitHubRepository, GitTag, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, PullRequest, PullRequestComment, PullRequestInfo, RateLimitSnapshot, ReleaseAsset, ReleaseInfo, Repo, RepoRef, RepositorySecret, RepositorySecurity, RepositoryVariable, RetryPolicy, Ruleset, SECURITY_ANALYSIS_STATUS_FIELDS, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, WorkflowDispatch, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, transformSecurityAndAnalysis, versionFromTag };
|
|
31
|
+
export { Annotation, AnnotationLevel, AppIdentity, ArtifactMetadata, Attestation, AttestationListEntry, AttestationRecord, BotIdentity, CLOSING_KEYWORDS, CheckConclusion, CheckRun, CheckRunOutput, CheckRunRef, CodeScanning, CommentMarker, CommentOnceResult, CommentRecord, CommitComparison, CommitFile, CommitRef, CommitSummary, DeploymentEnvironment, ExtraPermission, FileChange, FileContent, FileDeletion, FileMode, FileStatus, GRAPHQL_ONLY_SETTINGS, GitBranch, GitCommit, GitHubApp, GitHubAppError, GitHubClient, GitHubCommit, GitHubContent, GitHubError, GitHubErrorKind, GitHubGraphQLError, GitHubIssue, GitHubRelease, GitHubRepository, GitTag, GraphQLDocument, GraphQLErrorEntry, Installation, InstallationToken, InvalidRepoRefError, IssueInfo, LinkedIssue, MergeMethod, PageOptions, PermissionGap, PermissionLevel, PermissionResult, PullRequest, PullRequestComment, PullRequestInfo, RateLimitSnapshot, ReleaseAsset, ReleaseInfo, Repo, RepoRef, RepositorySecret, RepositorySecurity, RepositoryVariable, RetryPolicy, Ruleset, SECURITY_ANALYSIS_STATUS_FIELDS, SemverTag, StorageRecordInput, TagRef, TokenPermissionError, TokenPermissions, WorkflowDispatch, WorkflowRunStatus, harvestIssueReferences, parseBareLineReference, repositoryPatch, transformSecurityAndAnalysis, versionFromTag };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/github",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Typed GitHub REST and GraphQL services over the octokit core request surface, with app auth and resource helpers.",
|
|
6
6
|
"keywords": [
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"./package.json": "./package.json"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"@effected/github-references": "^0.1.0",
|
|
41
42
|
"@effected/semver": "^0.5.0",
|
|
42
43
|
"@octokit/core": "^7.0.6",
|
|
43
44
|
"@octokit/plugin-paginate-rest": "^15.0.0",
|
package/tsdoc-metadata.json
CHANGED
package/IssueReferences.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { Option } from "effect";
|
|
2
|
-
|
|
3
|
-
//#region src/IssueReferences.ts
|
|
4
|
-
/**
|
|
5
|
-
* GitHub's closing-keyword issue-reference grammar, as pure functions.
|
|
6
|
-
*
|
|
7
|
-
* @remarks
|
|
8
|
-
* GitHub links an issue to a pull request when the PR's description carries
|
|
9
|
-
* `<keyword> #<number>` for one of nine documented keywords. Consumers speak
|
|
10
|
-
* that grammar in two distinct dialects, and this module models exactly those
|
|
11
|
-
* two — no service, no layer, nothing but strings in and values out:
|
|
12
|
-
*
|
|
13
|
-
* - **Inline-in-prose** ({@link harvestIssueReferences}): a reference may appear anywhere in
|
|
14
|
-
* running text — `"fixes #12 and closes #13"` — with mandatory whitespace
|
|
15
|
-
* and **no colon**, because that is the spelling GitHub itself scans PR
|
|
16
|
-
* bodies for. This is the dialect a release pipeline harvests from commit
|
|
17
|
-
* subjects and PR descriptions.
|
|
18
|
-
* - **Bare-line** ({@link parseBareLineReference}): the whole line, after trimming, *is*
|
|
19
|
-
* the reference — `"Closes: #12"` — with an **optional colon**, because a
|
|
20
|
-
* generated references region writes one reference per line and a colon
|
|
21
|
-
* reads better there. GitHub does not require the colon; the region format
|
|
22
|
-
* allows it, so the parser must too. The dialects differ because their
|
|
23
|
-
* producers do: prose is written by humans for GitHub's scanner, the region
|
|
24
|
-
* is written by tooling for humans.
|
|
25
|
-
*
|
|
26
|
-
* Deliberately out of scope this round: cross-repo references
|
|
27
|
-
* (`owner/repo#N`) and full-URL references
|
|
28
|
-
* (`https://github.com/owner/repo/issues/N`). Both are real GitHub spellings;
|
|
29
|
-
* neither dialect's consumers emit them yet, and guessing at their shape here
|
|
30
|
-
* would freeze an API nobody has driven.
|
|
31
|
-
*/
|
|
32
|
-
/**
|
|
33
|
-
* The nine closing keywords GitHub documents, lowercased.
|
|
34
|
-
*
|
|
35
|
-
* @public
|
|
36
|
-
*/
|
|
37
|
-
const CLOSING_KEYWORDS = [
|
|
38
|
-
"close",
|
|
39
|
-
"closes",
|
|
40
|
-
"closed",
|
|
41
|
-
"fix",
|
|
42
|
-
"fixes",
|
|
43
|
-
"fixed",
|
|
44
|
-
"resolve",
|
|
45
|
-
"resolves",
|
|
46
|
-
"resolved"
|
|
47
|
-
];
|
|
48
|
-
/**
|
|
49
|
-
* Both patterns derive from {@link CLOSING_KEYWORDS} so the constant and the
|
|
50
|
-
* grammar cannot drift. Alternation order is safe: the regex engine backtracks
|
|
51
|
-
* through alternatives, so `close` matching inside `closes` fails at the
|
|
52
|
-
* mandatory `#`-introducer and retries the longer keyword.
|
|
53
|
-
*/
|
|
54
|
-
const KEYWORDS = CLOSING_KEYWORDS.join("|");
|
|
55
|
-
/** Inline-in-prose: mandatory whitespace, no colon. */
|
|
56
|
-
const INLINE_PATTERN = new RegExp(`\\b(${KEYWORDS})\\s+#(\\d+)`, "gi");
|
|
57
|
-
/**
|
|
58
|
-
* Bare-line: optional colon, then mandatory same-line whitespace. `[ \t]`
|
|
59
|
-
* rather than `\s`, so an embedded newline cannot smuggle two lines past a
|
|
60
|
-
* parser whose contract is one.
|
|
61
|
-
*/
|
|
62
|
-
const BARE_LINE_PATTERN = new RegExp(`^(${KEYWORDS}):?[ \\t]+#(\\d+)$`, "i");
|
|
63
|
-
/**
|
|
64
|
-
* `#<digits>` parsed to a number — or `undefined` when the digits exceed
|
|
65
|
-
* `Number.MAX_SAFE_INTEGER`, because a silently rounded issue number is worse
|
|
66
|
-
* than a skipped match. Callers skip such matches; they do not fail.
|
|
67
|
-
*/
|
|
68
|
-
const safeIssueNumber = (digits) => {
|
|
69
|
-
const value = Number(digits);
|
|
70
|
-
return Number.isSafeInteger(value) ? value : void 0;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Every inline closing reference in `text`, in document order.
|
|
74
|
-
*
|
|
75
|
-
* @remarks
|
|
76
|
-
* The **inline-in-prose** dialect: case-insensitive `<keyword> #<number>`
|
|
77
|
-
* anywhere in the text, whitespace mandatory, colon not accepted — a colon
|
|
78
|
-
* spelling belongs to the bare-line dialect and {@link parseBareLineReference}.
|
|
79
|
-
* Duplicates are preserved: whether `fixes #1, fixes #1` means one reference
|
|
80
|
-
* or two is the caller's business, not a parser's.
|
|
81
|
-
*
|
|
82
|
-
* A match whose digits exceed `Number.MAX_SAFE_INTEGER` is skipped, not
|
|
83
|
-
* misparsed — see the module remarks for the scope boundary.
|
|
84
|
-
*
|
|
85
|
-
* @public
|
|
86
|
-
*/
|
|
87
|
-
const harvestIssueReferences = (text) => {
|
|
88
|
-
const references = [];
|
|
89
|
-
for (const match of text.matchAll(INLINE_PATTERN)) {
|
|
90
|
-
const issueNumber = safeIssueNumber(match[2] ?? "");
|
|
91
|
-
if (issueNumber === void 0) continue;
|
|
92
|
-
references.push({
|
|
93
|
-
issueNumber,
|
|
94
|
-
keyword: (match[1] ?? "").toLowerCase(),
|
|
95
|
-
start: match.index,
|
|
96
|
-
end: match.index + match[0].length
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
return references;
|
|
100
|
-
};
|
|
101
|
-
/**
|
|
102
|
-
* The reference a whole line carries, or `Option.none()`.
|
|
103
|
-
*
|
|
104
|
-
* @remarks
|
|
105
|
-
* The **bare-line** dialect: after trimming, the entire line must be
|
|
106
|
-
* `<keyword>[:] #<number>` — keyword case-insensitive, colon optional,
|
|
107
|
-
* whitespace before the `#` mandatory. Trailing prose, a missing keyword, or
|
|
108
|
-
* anything else at all is a rejection, never a partial parse; a line carries
|
|
109
|
-
* one reference or none. Digits past `Number.MAX_SAFE_INTEGER` reject too,
|
|
110
|
-
* for the same reason {@link harvestIssueReferences} skips them.
|
|
111
|
-
*
|
|
112
|
-
* @public
|
|
113
|
-
*/
|
|
114
|
-
const parseBareLineReference = (line) => {
|
|
115
|
-
const match = BARE_LINE_PATTERN.exec(line.trim());
|
|
116
|
-
if (match === null) return Option.none();
|
|
117
|
-
const issueNumber = safeIssueNumber(match[2] ?? "");
|
|
118
|
-
if (issueNumber === void 0) return Option.none();
|
|
119
|
-
return Option.some({
|
|
120
|
-
issueNumber,
|
|
121
|
-
keyword: (match[1] ?? "").toLowerCase()
|
|
122
|
-
});
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
//#endregion
|
|
126
|
-
export { CLOSING_KEYWORDS, harvestIssueReferences, parseBareLineReference };
|