@theholocron/holocron-plugin-github 5.0.0-alpha.278 → 5.0.0-alpha.279
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/dist/index.d.mts +81 -0
- package/dist/index.mjs +63 -0
- package/package.json +8 -8
package/dist/index.d.mts
CHANGED
|
@@ -1,24 +1,41 @@
|
|
|
1
1
|
import { Auth, AuthError, Ci, CiRun, CiRunFilter, Environment, Environments, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, PagesConfig, PluginToken, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, SourceBranch, SourceFile, SourceRepoInfo, SourceRulesetDetail, SourceSecurity, SourceTeamMember, TeamEntry, TeamEntry as TeamEntry$1, TeamPermission, TeamPermission as TeamPermission$1, TrackerDoctorReport, TrackerUser, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess, createFeatureResolver } from "@theholocron/cli";
|
|
2
2
|
import { GitHubClient, GitHubClientOptions, createGitHubClient } from "@theholocron/github-client";
|
|
3
|
+
/** Resolves the token for read-only GitHub access (`HOLOCRON_READ_TOKEN`, keyring key `github.read`). */
|
|
3
4
|
export declare const resolveReadToken: import("@theholocron/cli").FeatureResolver;
|
|
5
|
+
/** Resolves the token for issue operations (`HOLOCRON_ISSUES_TOKEN`, keyring key `github.issues`). */
|
|
4
6
|
export declare const resolveIssuesToken: import("@theholocron/cli").FeatureResolver;
|
|
7
|
+
/** Resolves the token for syncing repo files and settings (`HOLOCRON_SYNC_TOKEN`, keyring key `github.sync`). */
|
|
5
8
|
export declare const resolveSyncToken: import("@theholocron/cli").FeatureResolver;
|
|
9
|
+
/** Resolves the token for release operations (`HOLOCRON_RELEASE_TOKEN`, keyring key `github.release`). */
|
|
6
10
|
export declare const resolveReleaseToken: import("@theholocron/cli").FeatureResolver;
|
|
11
|
+
/** Resolves the repo-scoped admin token (`HOLOCRON_ADMIN_TOKEN`, keyring key `github.admin`). */
|
|
7
12
|
export declare const resolveAdminToken: import("@theholocron/cli").FeatureResolver;
|
|
13
|
+
/** Resolves the org-level secrets token (`HOLOCRON_SECRETS_TOKEN`, keyring key `github.secrets`). */
|
|
8
14
|
export declare const resolveSecretsToken: import("@theholocron/cli").FeatureResolver;
|
|
15
|
+
/** Resolves the token for deployment operations (`HOLOCRON_DEPLOY_TOKEN`, keyring key `github.deploy`). */
|
|
9
16
|
export declare const resolveDeployToken: import("@theholocron/cli").FeatureResolver;
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the token for the user-sync files in the org's private config repo (`HOLOCRON_USER_SYNC_TOKEN`, keyring
|
|
19
|
+
* key `github.user-sync`).
|
|
20
|
+
*/
|
|
10
21
|
export declare const resolveUserSyncToken: import("@theholocron/cli").FeatureResolver;
|
|
22
|
+
/** Resolves the org-level token (`HOLOCRON_ORG_TOKEN`, keyring key `github.org`). */
|
|
11
23
|
export declare const resolveOrgToken: import("@theholocron/cli").FeatureResolver;
|
|
12
24
|
interface CiOptions {
|
|
13
25
|
repo: string;
|
|
14
26
|
}
|
|
27
|
+
/** The GitHub implementation of the `ci` capability, backed by GitHub Actions workflow runs. */
|
|
15
28
|
export declare class GitHubCi implements Ci {
|
|
16
29
|
private readonly client;
|
|
17
30
|
private readonly opts;
|
|
31
|
+
/** Capability key, always `"ci"`. */
|
|
18
32
|
readonly key: "ci";
|
|
33
|
+
/** Provider name, always `"github"`. */
|
|
19
34
|
readonly providerName = "github";
|
|
20
35
|
constructor(client: GitHubClient, opts: CiOptions);
|
|
36
|
+
/** Lists workflow runs for the repo, optionally filtered by branch, status and limit. */
|
|
21
37
|
listRuns(filter?: CiRunFilter): Promise<CiRun[]>;
|
|
38
|
+
/** Fetches one workflow run by id. */
|
|
22
39
|
getRun(id: string | number): Promise<CiRun>;
|
|
23
40
|
private mapRun;
|
|
24
41
|
private mapConclusion;
|
|
@@ -26,14 +43,20 @@ export declare class GitHubCi implements Ci {
|
|
|
26
43
|
interface EnvironmentsOptions {
|
|
27
44
|
repo: string;
|
|
28
45
|
}
|
|
46
|
+
/** The GitHub implementation of the `environments` capability, managing a repo's deployment environments. */
|
|
29
47
|
export declare class GitHubEnvironments implements Environments {
|
|
30
48
|
private readonly client;
|
|
31
49
|
private readonly opts;
|
|
50
|
+
/** Capability key, always `"environments"`. */
|
|
32
51
|
readonly key: "environments";
|
|
52
|
+
/** Provider name, always `"github"`. */
|
|
33
53
|
readonly providerName = "github";
|
|
34
54
|
constructor(client: GitHubClient, opts: EnvironmentsOptions);
|
|
55
|
+
/** Lists the repo's environments with their wait timer, self-review rule and required reviewers. */
|
|
35
56
|
listEnvironments(): Promise<Environment[]>;
|
|
57
|
+
/** Creates or updates an environment, sending only the settings the given environment defines. */
|
|
36
58
|
upsertEnvironment(env: Environment): Promise<void>;
|
|
59
|
+
/** Deletes the named environment. */
|
|
37
60
|
deleteEnvironment(name: string): Promise<void>;
|
|
38
61
|
private flattenReviewers;
|
|
39
62
|
}
|
|
@@ -50,9 +73,12 @@ interface IssuesOptions {
|
|
|
50
73
|
inReview: string;
|
|
51
74
|
};
|
|
52
75
|
}
|
|
76
|
+
/** The GitHub implementation of the `issues` capability, backed by GitHub Issues and status labels. */
|
|
53
77
|
export declare class GitHubIssues implements Issues {
|
|
54
78
|
private readonly client;
|
|
79
|
+
/** Capability key, always `"issues"`. */
|
|
55
80
|
readonly key: "issues";
|
|
81
|
+
/** Provider name, always `"github"`. */
|
|
56
82
|
readonly providerName = "github";
|
|
57
83
|
private readonly owner;
|
|
58
84
|
private readonly repoName;
|
|
@@ -60,8 +86,11 @@ export declare class GitHubIssues implements Issues {
|
|
|
60
86
|
private readonly labels;
|
|
61
87
|
constructor(client: GitHubClient, opts: IssuesOptions);
|
|
62
88
|
getMyself(): Promise<TrackerUser>;
|
|
89
|
+
/** Searches the repo's issues, newest update first, leaving out pull requests. */
|
|
63
90
|
search(filter: IssueSearchFilter): Promise<Issue[]>;
|
|
91
|
+
/** Fetches one issue by its key. */
|
|
64
92
|
get(key: string): Promise<Issue>;
|
|
93
|
+
/** Creates an issue and returns its key as `#<number>`; the milestone is resolved from its title. */
|
|
65
94
|
create(input: {
|
|
66
95
|
summary: string;
|
|
67
96
|
body?: string;
|
|
@@ -71,15 +100,21 @@ export declare class GitHubIssues implements Issues {
|
|
|
71
100
|
key: string;
|
|
72
101
|
}>;
|
|
73
102
|
transition(key: string, slot: LifecycleSlot): Promise<LifecycleResult>;
|
|
103
|
+
/** Adds a comment to the issue with the given key. */
|
|
74
104
|
comment(key: string, body: string): Promise<void>;
|
|
105
|
+
/** Checks the authenticated user, the repo and the label-backed lifecycle slots, and reports what resolves. */
|
|
75
106
|
doctor(): Promise<TrackerDoctorReport>;
|
|
76
107
|
private resolveMilestone;
|
|
77
108
|
private removeStatusLabels;
|
|
78
109
|
private mapIssue;
|
|
79
110
|
}
|
|
111
|
+
/** A label the repo is expected to have. */
|
|
80
112
|
interface CanonicalLabel {
|
|
113
|
+
/** The label's name. */
|
|
81
114
|
readonly name: string;
|
|
115
|
+
/** The label's color, as a hex string. */
|
|
82
116
|
readonly color: string;
|
|
117
|
+
/** The label's description. */
|
|
83
118
|
readonly description: string;
|
|
84
119
|
}
|
|
85
120
|
/**
|
|
@@ -94,11 +129,14 @@ export declare function syncLabels(client: GitHubClient, repo: string, canonical
|
|
|
94
129
|
interface SecretsOptions {
|
|
95
130
|
repo: string;
|
|
96
131
|
}
|
|
132
|
+
/** The GitHub implementation of the `secrets` capability, covering repository, environment and organization secrets. */
|
|
97
133
|
export declare class GitHubSecrets implements Secrets {
|
|
98
134
|
private readonly client;
|
|
99
135
|
private readonly opts;
|
|
100
136
|
private readonly orgClient?;
|
|
137
|
+
/** Capability key, always `"secrets"`. */
|
|
101
138
|
readonly key: "secrets";
|
|
139
|
+
/** Provider name, always `"github"`. */
|
|
102
140
|
readonly providerName = "github";
|
|
103
141
|
/**
|
|
104
142
|
* `client` handles repo and environment scopes; `orgClient`, when given, handles
|
|
@@ -109,6 +147,7 @@ export declare class GitHubSecrets implements Secrets {
|
|
|
109
147
|
private clientFor;
|
|
110
148
|
listSecrets(scope: SecretScope): Promise<string[]>;
|
|
111
149
|
setSecret(scope: SecretScope, name: string, value: string): Promise<void>;
|
|
150
|
+
/** Deletes the named secret in the given scope. */
|
|
112
151
|
deleteSecret(scope: SecretScope, name: string): Promise<void>;
|
|
113
152
|
}
|
|
114
153
|
interface SourceOptions {
|
|
@@ -122,9 +161,15 @@ interface SourceOptions {
|
|
|
122
161
|
baseUrl?: string;
|
|
123
162
|
fetch?: typeof fetch;
|
|
124
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* The GitHub implementation of the `source` capability: repo settings, rulesets, branch protection, security
|
|
166
|
+
* features and local workflow files.
|
|
167
|
+
*/
|
|
125
168
|
export declare class GitHubSource implements Source {
|
|
126
169
|
private readonly client;
|
|
170
|
+
/** Capability key, always `"source"`. */
|
|
127
171
|
readonly key: "source";
|
|
172
|
+
/** Provider name, always `"github"`. */
|
|
128
173
|
readonly providerName = "github";
|
|
129
174
|
private readonly owner;
|
|
130
175
|
private readonly name;
|
|
@@ -139,22 +184,35 @@ export declare class GitHubSource implements Source {
|
|
|
139
184
|
whoami(): Promise<{
|
|
140
185
|
login: string;
|
|
141
186
|
}>;
|
|
187
|
+
/** Returns the repo's owner, name and default branch. */
|
|
142
188
|
getRepo(): Promise<RepoRef>;
|
|
189
|
+
/** Lists the repo's rulesets. */
|
|
143
190
|
listRulesets(): Promise<Ruleset[]>;
|
|
191
|
+
/** Creates a ruleset from the given payload. */
|
|
144
192
|
createRuleset(payload: Record<string, unknown>): Promise<Ruleset>;
|
|
193
|
+
/** Updates the ruleset with the given id from the payload. */
|
|
145
194
|
updateRuleset(id: number, payload: Record<string, unknown>): Promise<Ruleset>;
|
|
195
|
+
/** Updates the repo's settings. */
|
|
146
196
|
updateRepoSettings(settings: RepoSettings): Promise<void>;
|
|
147
197
|
protectBranch(branch: string, payload: Record<string, unknown>): Promise<void>;
|
|
198
|
+
/** Enables Dependabot vulnerability alerts. */
|
|
148
199
|
enableVulnerabilityAlerts(): Promise<void>;
|
|
200
|
+
/** Enables Dependabot automated security fixes. */
|
|
149
201
|
enableAutomatedSecurityFixes(): Promise<void>;
|
|
202
|
+
/** Enables secret scanning. */
|
|
150
203
|
enableSecretScanning(): Promise<void>;
|
|
151
204
|
enableCodeScanning(): Promise<string>;
|
|
152
205
|
disableDefaultCodeScanning(): Promise<void>;
|
|
153
206
|
enableDependencyGraph(): Promise<void>;
|
|
207
|
+
/** Enables private vulnerability reporting. */
|
|
154
208
|
enablePrivateVulnerabilityReporting(): Promise<void>;
|
|
209
|
+
/** Lists the `.yml` and `.yaml` files in `.github/workflows`, sorted by name; empty when the folder is missing. */
|
|
155
210
|
listWorkflowFiles(): Promise<string[]>;
|
|
211
|
+
/** Reads a workflow file's text, or `null` when it does not exist. */
|
|
156
212
|
readWorkflowFile(name: string): Promise<string | null>;
|
|
213
|
+
/** Writes a workflow file, creating `.github/workflows` first when needed. */
|
|
157
214
|
writeWorkflowFile(name: string, contents: string): Promise<void>;
|
|
215
|
+
/** Removes a workflow file; a file that is already gone is not an error. */
|
|
158
216
|
removeWorkflowFile(name: string): Promise<void>;
|
|
159
217
|
writeRepoFile(path: string, contents: string): Promise<void>;
|
|
160
218
|
syncLabels(canonical: ReadonlyArray<LabelDef>, stale: ReadonlyArray<string>): Promise<string>;
|
|
@@ -202,22 +260,32 @@ export declare class GitHubSource implements Source {
|
|
|
202
260
|
listPullRequestCommits(number: number, repo?: string): Promise<string[]>;
|
|
203
261
|
configurePages(config: PagesConfig, token: string): Promise<void>;
|
|
204
262
|
}
|
|
263
|
+
/** A team entry with the permission spelled out. */
|
|
205
264
|
interface NormalizedTeamEntry {
|
|
265
|
+
/** The team's slug. */
|
|
206
266
|
slug: string;
|
|
267
|
+
/** The permission the team gets on the repo. */
|
|
207
268
|
permission: TeamPermission;
|
|
208
269
|
}
|
|
270
|
+
/** Turns a team entry into slug and permission form; a bare slug gets `push`. */
|
|
209
271
|
export declare function normalizeTeamEntry(entry: TeamEntry): NormalizedTeamEntry;
|
|
272
|
+
/** Grants each team access to the repo and reports the outcome; throws when every team fails. */
|
|
210
273
|
export declare function syncTeams(client: GitHubClient, repo: string, teams: TeamEntry[]): Promise<string>;
|
|
211
274
|
/**
|
|
212
275
|
* Encrypt `value` for the given GitHub-provided base64 public key.
|
|
213
276
|
* Returns the base64 ciphertext to send as `encrypted_value`.
|
|
214
277
|
*/
|
|
215
278
|
export declare function encryptSecret(publicKeyBase64: string, value: string): Promise<string>;
|
|
279
|
+
/** Options for `verifyToken`. */
|
|
216
280
|
interface VerifyTokenOptions {
|
|
281
|
+
/** Overrides the API base URL, for tests. */
|
|
217
282
|
baseUrl?: string;
|
|
283
|
+
/** Overrides `fetch`, for tests. */
|
|
218
284
|
fetch?: typeof fetch;
|
|
219
285
|
}
|
|
286
|
+
/** Checks a token against `GET /user` and returns who it belongs to, or why it failed. */
|
|
220
287
|
export declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult$1>;
|
|
288
|
+
/** Options for the GitHub plugin. */
|
|
221
289
|
export interface GitHubPluginOptions extends ResolveTokenInput {
|
|
222
290
|
/** "owner/name" — e.g., "theholocron/holocron". Required. */
|
|
223
291
|
repo: string;
|
|
@@ -226,7 +294,9 @@ export interface GitHubPluginOptions extends ResolveTokenInput {
|
|
|
226
294
|
repoRoot?: string;
|
|
227
295
|
/** Lifecycle slot → label name. Used by the `issues` capability. */
|
|
228
296
|
labels?: {
|
|
297
|
+
/** Label that marks an issue as in progress. */
|
|
229
298
|
inProgress: string;
|
|
299
|
+
/** Label that marks an issue as in review. */
|
|
230
300
|
inReview: string;
|
|
231
301
|
};
|
|
232
302
|
/** Override base URL for tests. Defaults to https://api.github.com. */
|
|
@@ -234,17 +304,28 @@ export interface GitHubPluginOptions extends ResolveTokenInput {
|
|
|
234
304
|
/** Override `fetch` for tests. Defaults to global `fetch`. */
|
|
235
305
|
fetch?: typeof fetch;
|
|
236
306
|
}
|
|
307
|
+
/** What the capability factories receive: the plugin options, a client, the repo and its root. */
|
|
237
308
|
export interface PluginContext {
|
|
309
|
+
/** The plugin options. */
|
|
238
310
|
options: GitHubPluginOptions;
|
|
311
|
+
/** The GitHub client the capability uses. */
|
|
239
312
|
client: GitHubClient;
|
|
313
|
+
/** The repo as `owner/name`. */
|
|
240
314
|
repo: string;
|
|
315
|
+
/** Absolute path to the working repo root. */
|
|
241
316
|
repoRoot: string;
|
|
242
317
|
}
|
|
318
|
+
/** Builds the `source` capability; the optional clients cover org-level and user-sync access. */
|
|
243
319
|
export declare function source(ctx: PluginContext, orgClient?: GitHubClient, userSyncClient?: GitHubClient): Source;
|
|
320
|
+
/** Builds the `secrets` capability; the optional client handles organization secrets. */
|
|
244
321
|
export declare function secrets(ctx: PluginContext, orgClient?: GitHubClient): Secrets;
|
|
322
|
+
/** Builds the `environments` capability. */
|
|
245
323
|
export declare function environments(ctx: PluginContext): Environments;
|
|
324
|
+
/** Builds the `ci` capability. */
|
|
246
325
|
export declare function ci(ctx: PluginContext): Ci;
|
|
326
|
+
/** Builds the `issues` capability, passing the lifecycle labels when configured. */
|
|
247
327
|
export declare function issues(ctx: PluginContext): Issues;
|
|
328
|
+
/** Creates the plugin, resolving a token per capability when it is first used. */
|
|
248
329
|
export declare function createPlugin(options: GitHubPluginOptions): {
|
|
249
330
|
name: string;
|
|
250
331
|
probes: {
|
package/dist/index.mjs
CHANGED
|
@@ -7,52 +7,68 @@ import { findRootSync } from "@theholocron/fs-utils";
|
|
|
7
7
|
import { ProviderApiError as ProviderApiError$1 } from "@theholocron/http-client";
|
|
8
8
|
import { errorMessage } from "@theholocron/misc-utils";
|
|
9
9
|
// src/auth.ts
|
|
10
|
+
/** Resolves the token for read-only GitHub access (`HOLOCRON_READ_TOKEN`, keyring key `github.read`). */
|
|
10
11
|
const resolveReadToken = createFeatureResolver({
|
|
11
12
|
envName: "HOLOCRON_READ_TOKEN",
|
|
12
13
|
keyringKey: "github.read"
|
|
13
14
|
});
|
|
15
|
+
/** Resolves the token for issue operations (`HOLOCRON_ISSUES_TOKEN`, keyring key `github.issues`). */
|
|
14
16
|
const resolveIssuesToken = createFeatureResolver({
|
|
15
17
|
envName: "HOLOCRON_ISSUES_TOKEN",
|
|
16
18
|
keyringKey: "github.issues"
|
|
17
19
|
});
|
|
20
|
+
/** Resolves the token for syncing repo files and settings (`HOLOCRON_SYNC_TOKEN`, keyring key `github.sync`). */
|
|
18
21
|
const resolveSyncToken = createFeatureResolver({
|
|
19
22
|
envName: "HOLOCRON_SYNC_TOKEN",
|
|
20
23
|
keyringKey: "github.sync"
|
|
21
24
|
});
|
|
25
|
+
/** Resolves the token for release operations (`HOLOCRON_RELEASE_TOKEN`, keyring key `github.release`). */
|
|
22
26
|
const resolveReleaseToken = createFeatureResolver({
|
|
23
27
|
envName: "HOLOCRON_RELEASE_TOKEN",
|
|
24
28
|
keyringKey: "github.release"
|
|
25
29
|
});
|
|
30
|
+
/** Resolves the repo-scoped admin token (`HOLOCRON_ADMIN_TOKEN`, keyring key `github.admin`). */
|
|
26
31
|
const resolveAdminToken = createFeatureResolver({
|
|
27
32
|
envName: "HOLOCRON_ADMIN_TOKEN",
|
|
28
33
|
keyringKey: "github.admin"
|
|
29
34
|
});
|
|
35
|
+
/** Resolves the org-level secrets token (`HOLOCRON_SECRETS_TOKEN`, keyring key `github.secrets`). */
|
|
30
36
|
const resolveSecretsToken = createFeatureResolver({
|
|
31
37
|
envName: "HOLOCRON_SECRETS_TOKEN",
|
|
32
38
|
keyringKey: "github.secrets"
|
|
33
39
|
});
|
|
40
|
+
/** Resolves the token for deployment operations (`HOLOCRON_DEPLOY_TOKEN`, keyring key `github.deploy`). */
|
|
34
41
|
const resolveDeployToken = createFeatureResolver({
|
|
35
42
|
envName: "HOLOCRON_DEPLOY_TOKEN",
|
|
36
43
|
keyringKey: "github.deploy"
|
|
37
44
|
});
|
|
45
|
+
/**
|
|
46
|
+
* Resolves the token for the user-sync files in the org's private config repo (`HOLOCRON_USER_SYNC_TOKEN`, keyring
|
|
47
|
+
* key `github.user-sync`).
|
|
48
|
+
*/
|
|
38
49
|
const resolveUserSyncToken = createFeatureResolver({
|
|
39
50
|
envName: "HOLOCRON_USER_SYNC_TOKEN",
|
|
40
51
|
keyringKey: "github.user-sync"
|
|
41
52
|
});
|
|
53
|
+
/** Resolves the org-level token (`HOLOCRON_ORG_TOKEN`, keyring key `github.org`). */
|
|
42
54
|
const resolveOrgToken = createFeatureResolver({
|
|
43
55
|
envName: "HOLOCRON_ORG_TOKEN",
|
|
44
56
|
keyringKey: "github.org"
|
|
45
57
|
});
|
|
46
58
|
// src/capabilities/ci.ts
|
|
59
|
+
/** The GitHub implementation of the `ci` capability, backed by GitHub Actions workflow runs. */
|
|
47
60
|
var GitHubCi = class {
|
|
48
61
|
client;
|
|
49
62
|
opts;
|
|
63
|
+
/** Capability key, always `"ci"`. */
|
|
50
64
|
key = "ci";
|
|
65
|
+
/** Provider name, always `"github"`. */
|
|
51
66
|
providerName = "github";
|
|
52
67
|
constructor(client, opts) {
|
|
53
68
|
this.client = client;
|
|
54
69
|
this.opts = opts;
|
|
55
70
|
}
|
|
71
|
+
/** Lists workflow runs for the repo, optionally filtered by branch, status and limit. */
|
|
56
72
|
async listRuns(filter) {
|
|
57
73
|
return (await this.client.workflows.listRuns(this.opts.repo, {
|
|
58
74
|
branch: filter?.branch,
|
|
@@ -60,6 +76,7 @@ var GitHubCi = class {
|
|
|
60
76
|
status: filter?.status
|
|
61
77
|
})).map((r) => this.mapRun(r));
|
|
62
78
|
}
|
|
79
|
+
/** Fetches one workflow run by id. */
|
|
63
80
|
async getRun(id) {
|
|
64
81
|
const raw = await this.client.workflows.getRun(this.opts.repo, id);
|
|
65
82
|
return this.mapRun(raw);
|
|
@@ -88,15 +105,19 @@ var GitHubCi = class {
|
|
|
88
105
|
}
|
|
89
106
|
};
|
|
90
107
|
// src/capabilities/environments.ts
|
|
108
|
+
/** The GitHub implementation of the `environments` capability, managing a repo's deployment environments. */
|
|
91
109
|
var GitHubEnvironments = class {
|
|
92
110
|
client;
|
|
93
111
|
opts;
|
|
112
|
+
/** Capability key, always `"environments"`. */
|
|
94
113
|
key = "environments";
|
|
114
|
+
/** Provider name, always `"github"`. */
|
|
95
115
|
providerName = "github";
|
|
96
116
|
constructor(client, opts) {
|
|
97
117
|
this.client = client;
|
|
98
118
|
this.opts = opts;
|
|
99
119
|
}
|
|
120
|
+
/** Lists the repo's environments with their wait timer, self-review rule and required reviewers. */
|
|
100
121
|
async listEnvironments() {
|
|
101
122
|
return (await this.client.environments.listEnvironments(this.opts.repo)).map((e) => ({
|
|
102
123
|
name: e.name,
|
|
@@ -105,6 +126,7 @@ var GitHubEnvironments = class {
|
|
|
105
126
|
reviewers: this.flattenReviewers(e.protection_rules)
|
|
106
127
|
}));
|
|
107
128
|
}
|
|
129
|
+
/** Creates or updates an environment, sending only the settings the given environment defines. */
|
|
108
130
|
async upsertEnvironment(env) {
|
|
109
131
|
const body = {};
|
|
110
132
|
if (env.waitTimer !== void 0) body.wait_timer = env.waitTimer;
|
|
@@ -115,6 +137,7 @@ var GitHubEnvironments = class {
|
|
|
115
137
|
}));
|
|
116
138
|
await this.client.environments.upsertEnvironment(this.opts.repo, env.name, body);
|
|
117
139
|
}
|
|
140
|
+
/** Deletes the named environment. */
|
|
118
141
|
async deleteEnvironment(name) {
|
|
119
142
|
await this.client.environments.deleteEnvironment(this.opts.repo, name);
|
|
120
143
|
}
|
|
@@ -129,9 +152,12 @@ var GitHubEnvironments = class {
|
|
|
129
152
|
}
|
|
130
153
|
};
|
|
131
154
|
// src/capabilities/issues.ts
|
|
155
|
+
/** The GitHub implementation of the `issues` capability, backed by GitHub Issues and status labels. */
|
|
132
156
|
var GitHubIssues = class {
|
|
133
157
|
client;
|
|
158
|
+
/** Capability key, always `"issues"`. */
|
|
134
159
|
key = "issues";
|
|
160
|
+
/** Provider name, always `"github"`. */
|
|
135
161
|
providerName = "github";
|
|
136
162
|
owner;
|
|
137
163
|
repoName;
|
|
@@ -153,6 +179,7 @@ var GitHubIssues = class {
|
|
|
153
179
|
...raw.email ? { emailAddress: raw.email } : {}
|
|
154
180
|
};
|
|
155
181
|
}
|
|
182
|
+
/** Searches the repo's issues, newest update first, leaving out pull requests. */
|
|
156
183
|
async search(filter) {
|
|
157
184
|
const params = {
|
|
158
185
|
state: filter.openOnly ? "open" : "all",
|
|
@@ -172,11 +199,13 @@ var GitHubIssues = class {
|
|
|
172
199
|
assignee: params.assignee
|
|
173
200
|
})).filter((i) => !i.pull_request).map((i) => this.mapIssue(i));
|
|
174
201
|
}
|
|
202
|
+
/** Fetches one issue by its key. */
|
|
175
203
|
async get(key) {
|
|
176
204
|
const number = parseIssueNumber(key, this.owner, this.repoName);
|
|
177
205
|
const raw = await this.client.issues.getIssue(this.repo, number);
|
|
178
206
|
return this.mapIssue(raw);
|
|
179
207
|
}
|
|
208
|
+
/** Creates an issue and returns its key as `#<number>`; the milestone is resolved from its title. */
|
|
180
209
|
async create(input) {
|
|
181
210
|
const body = { title: input.summary };
|
|
182
211
|
if (input.body) body.body = input.body;
|
|
@@ -224,10 +253,12 @@ var GitHubIssues = class {
|
|
|
224
253
|
via: `label set to ${targetLabel}`
|
|
225
254
|
};
|
|
226
255
|
}
|
|
256
|
+
/** Adds a comment to the issue with the given key. */
|
|
227
257
|
async comment(key, body) {
|
|
228
258
|
const number = parseIssueNumber(key, this.owner, this.repoName);
|
|
229
259
|
await this.client.issues.createComment(this.repo, number, body);
|
|
230
260
|
}
|
|
261
|
+
/** Checks the authenticated user, the repo and the label-backed lifecycle slots, and reports what resolves. */
|
|
231
262
|
async doctor() {
|
|
232
263
|
const me = await this.getMyself();
|
|
233
264
|
const repo = await this.client.repos.getRepo(this.repo);
|
|
@@ -377,11 +408,14 @@ async function encryptSecret(publicKeyBase64, value) {
|
|
|
377
408
|
return sodium.to_base64(ciphertext, sodium.base64_variants.ORIGINAL);
|
|
378
409
|
}
|
|
379
410
|
// src/capabilities/secrets.ts
|
|
411
|
+
/** The GitHub implementation of the `secrets` capability, covering repository, environment and organization secrets. */
|
|
380
412
|
var GitHubSecrets = class {
|
|
381
413
|
client;
|
|
382
414
|
opts;
|
|
383
415
|
orgClient;
|
|
416
|
+
/** Capability key, always `"secrets"`. */
|
|
384
417
|
key = "secrets";
|
|
418
|
+
/** Provider name, always `"github"`. */
|
|
385
419
|
providerName = "github";
|
|
386
420
|
/**
|
|
387
421
|
* `client` handles repo and environment scopes; `orgClient`, when given, handles
|
|
@@ -410,6 +444,7 @@ var GitHubSecrets = class {
|
|
|
410
444
|
if (scope.kind === "organization") body.visibility = "all";
|
|
411
445
|
await client.secrets.putSecret(this.opts.repo, ghScope, name, body);
|
|
412
446
|
}
|
|
447
|
+
/** Deletes the named secret in the given scope. */
|
|
413
448
|
async deleteSecret(scope, name) {
|
|
414
449
|
await this.clientFor(scope).secrets.deleteSecret(this.opts.repo, toGHScope(scope), name);
|
|
415
450
|
}
|
|
@@ -640,6 +675,7 @@ async function readSecurity(client, repo) {
|
|
|
640
675
|
return Object.fromEntries(Object.entries(found).filter(([, v]) => v !== void 0));
|
|
641
676
|
}
|
|
642
677
|
// src/capabilities/teams.ts
|
|
678
|
+
/** Turns a team entry into slug and permission form; a bare slug gets `push`. */
|
|
643
679
|
function normalizeTeamEntry(entry) {
|
|
644
680
|
if (typeof entry === "string") return {
|
|
645
681
|
slug: entry,
|
|
@@ -647,6 +683,7 @@ function normalizeTeamEntry(entry) {
|
|
|
647
683
|
};
|
|
648
684
|
return entry;
|
|
649
685
|
}
|
|
686
|
+
/** Grants each team access to the repo and reports the outcome; throws when every team fails. */
|
|
650
687
|
async function syncTeams(client, repo, teams) {
|
|
651
688
|
const [org = "", name = ""] = repo.split("/", 2);
|
|
652
689
|
const normalized = teams.map(normalizeTeamEntry);
|
|
@@ -776,9 +813,15 @@ function toPullRequest(raw) {
|
|
|
776
813
|
url: raw.html_url
|
|
777
814
|
};
|
|
778
815
|
}
|
|
816
|
+
/**
|
|
817
|
+
* The GitHub implementation of the `source` capability: repo settings, rulesets, branch protection, security
|
|
818
|
+
* features and local workflow files.
|
|
819
|
+
*/
|
|
779
820
|
var GitHubSource = class {
|
|
780
821
|
client;
|
|
822
|
+
/** Capability key, always `"source"`. */
|
|
781
823
|
key = "source";
|
|
824
|
+
/** Provider name, always `"github"`. */
|
|
782
825
|
providerName = "github";
|
|
783
826
|
owner;
|
|
784
827
|
name;
|
|
@@ -808,6 +851,7 @@ var GitHubSource = class {
|
|
|
808
851
|
async whoami() {
|
|
809
852
|
return { login: (await this.client.user.getCurrentUser()).login };
|
|
810
853
|
}
|
|
854
|
+
/** Returns the repo's owner, name and default branch. */
|
|
811
855
|
async getRepo() {
|
|
812
856
|
const data = await this.client.repos.getRepo(this.repo);
|
|
813
857
|
return {
|
|
@@ -816,27 +860,34 @@ var GitHubSource = class {
|
|
|
816
860
|
defaultBranch: data.default_branch
|
|
817
861
|
};
|
|
818
862
|
}
|
|
863
|
+
/** Lists the repo's rulesets. */
|
|
819
864
|
async listRulesets() {
|
|
820
865
|
return this.client.rulesets.listRulesets(this.repo);
|
|
821
866
|
}
|
|
867
|
+
/** Creates a ruleset from the given payload. */
|
|
822
868
|
async createRuleset(payload) {
|
|
823
869
|
return this.client.rulesets.createRuleset(this.repo, payload);
|
|
824
870
|
}
|
|
871
|
+
/** Updates the ruleset with the given id from the payload. */
|
|
825
872
|
async updateRuleset(id, payload) {
|
|
826
873
|
return this.client.rulesets.updateRuleset(this.repo, id, payload);
|
|
827
874
|
}
|
|
875
|
+
/** Updates the repo's settings. */
|
|
828
876
|
async updateRepoSettings(settings) {
|
|
829
877
|
await this.client.repos.updateRepo(this.repo, settings);
|
|
830
878
|
}
|
|
831
879
|
async protectBranch(branch, payload) {
|
|
832
880
|
await this.client.branches.protectBranch(this.repo, branch, payload);
|
|
833
881
|
}
|
|
882
|
+
/** Enables Dependabot vulnerability alerts. */
|
|
834
883
|
async enableVulnerabilityAlerts() {
|
|
835
884
|
await this.client.security.enableVulnerabilityAlerts(this.repo);
|
|
836
885
|
}
|
|
886
|
+
/** Enables Dependabot automated security fixes. */
|
|
837
887
|
async enableAutomatedSecurityFixes() {
|
|
838
888
|
await this.client.security.enableAutomatedSecurityFixes(this.repo);
|
|
839
889
|
}
|
|
890
|
+
/** Enables secret scanning. */
|
|
840
891
|
async enableSecretScanning() {
|
|
841
892
|
await this.client.security.enableSecretScanning(this.repo);
|
|
842
893
|
}
|
|
@@ -849,9 +900,11 @@ var GitHubSource = class {
|
|
|
849
900
|
async enableDependencyGraph() {
|
|
850
901
|
await this.client.security.enableDependencyGraph(this.repo);
|
|
851
902
|
}
|
|
903
|
+
/** Enables private vulnerability reporting. */
|
|
852
904
|
async enablePrivateVulnerabilityReporting() {
|
|
853
905
|
await this.client.security.enablePrivateVulnerabilityReporting(this.repo);
|
|
854
906
|
}
|
|
907
|
+
/** Lists the `.yml` and `.yaml` files in `.github/workflows`, sorted by name; empty when the folder is missing. */
|
|
855
908
|
async listWorkflowFiles() {
|
|
856
909
|
try {
|
|
857
910
|
return (await readdir(this.workflowDir)).filter((e) => e.endsWith(".yml") || e.endsWith(".yaml")).sort();
|
|
@@ -860,6 +913,7 @@ var GitHubSource = class {
|
|
|
860
913
|
throw err;
|
|
861
914
|
}
|
|
862
915
|
}
|
|
916
|
+
/** Reads a workflow file's text, or `null` when it does not exist. */
|
|
863
917
|
async readWorkflowFile(name) {
|
|
864
918
|
try {
|
|
865
919
|
return await readFile(join(this.workflowDir, name), "utf8");
|
|
@@ -868,10 +922,12 @@ var GitHubSource = class {
|
|
|
868
922
|
throw err;
|
|
869
923
|
}
|
|
870
924
|
}
|
|
925
|
+
/** Writes a workflow file, creating `.github/workflows` first when needed. */
|
|
871
926
|
async writeWorkflowFile(name, contents) {
|
|
872
927
|
await ensureDir(this.workflowDir);
|
|
873
928
|
await writeFile(join(this.workflowDir, name), contents, "utf8");
|
|
874
929
|
}
|
|
930
|
+
/** Removes a workflow file; a file that is already gone is not an error. */
|
|
875
931
|
async removeWorkflowFile(name) {
|
|
876
932
|
try {
|
|
877
933
|
await rm(join(this.workflowDir, name));
|
|
@@ -1026,6 +1082,7 @@ async function ensureDir(path) {
|
|
|
1026
1082
|
}
|
|
1027
1083
|
}
|
|
1028
1084
|
// src/verify-token.ts
|
|
1085
|
+
/** Checks a token against `GET /user` and returns who it belongs to, or why it failed. */
|
|
1029
1086
|
async function verifyToken(token, opts = {}) {
|
|
1030
1087
|
const client = createGitHubClient({
|
|
1031
1088
|
token,
|
|
@@ -1047,6 +1104,7 @@ async function verifyToken(token, opts = {}) {
|
|
|
1047
1104
|
}
|
|
1048
1105
|
}
|
|
1049
1106
|
// src/index.ts
|
|
1107
|
+
/** Builds the `source` capability; the optional clients cover org-level and user-sync access. */
|
|
1050
1108
|
function source(ctx, orgClient, userSyncClient) {
|
|
1051
1109
|
return new GitHubSource(ctx.client, {
|
|
1052
1110
|
repo: ctx.repo,
|
|
@@ -1057,20 +1115,25 @@ function source(ctx, orgClient, userSyncClient) {
|
|
|
1057
1115
|
fetch: ctx.options.fetch
|
|
1058
1116
|
});
|
|
1059
1117
|
}
|
|
1118
|
+
/** Builds the `secrets` capability; the optional client handles organization secrets. */
|
|
1060
1119
|
function secrets(ctx, orgClient) {
|
|
1061
1120
|
return new GitHubSecrets(ctx.client, { repo: ctx.repo }, orgClient);
|
|
1062
1121
|
}
|
|
1122
|
+
/** Builds the `environments` capability. */
|
|
1063
1123
|
function environments(ctx) {
|
|
1064
1124
|
return new GitHubEnvironments(ctx.client, { repo: ctx.repo });
|
|
1065
1125
|
}
|
|
1126
|
+
/** Builds the `ci` capability. */
|
|
1066
1127
|
function ci(ctx) {
|
|
1067
1128
|
return new GitHubCi(ctx.client, { repo: ctx.repo });
|
|
1068
1129
|
}
|
|
1130
|
+
/** Builds the `issues` capability, passing the lifecycle labels when configured. */
|
|
1069
1131
|
function issues(ctx) {
|
|
1070
1132
|
const opts = { repo: ctx.repo };
|
|
1071
1133
|
if (ctx.options.labels !== void 0) opts.labels = ctx.options.labels;
|
|
1072
1134
|
return new GitHubIssues(ctx.client, opts);
|
|
1073
1135
|
}
|
|
1136
|
+
/** Creates the plugin, resolving a token per capability when it is first used. */
|
|
1074
1137
|
function createPlugin(options) {
|
|
1075
1138
|
function makeCtx(resolver) {
|
|
1076
1139
|
const token = resolver(options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theholocron/holocron-plugin-github",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.279",
|
|
4
4
|
"description": "Holocron plugin for GitHub. Implements source, ci, secrets, environments, and issues capabilities against the GitHub REST API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ci",
|
|
@@ -44,21 +44,21 @@
|
|
|
44
44
|
"tsx": "4.23.15",
|
|
45
45
|
"typescript": "^5.9.3",
|
|
46
46
|
"vitest": "^5.0.5",
|
|
47
|
-
"@theholocron/cli": "5.0.0-alpha.278",
|
|
48
|
-
"@theholocron/eslint-config": "^8.9.0-alpha.4",
|
|
49
47
|
"@theholocron/fs-utils": "^1.16.1-alpha.3",
|
|
50
|
-
"@theholocron/
|
|
48
|
+
"@theholocron/eslint-config": "^8.9.0-alpha.4",
|
|
49
|
+
"@theholocron/cli": "5.0.0-alpha.279",
|
|
50
|
+
"@theholocron/http-client": "^1.58.0-alpha.3",
|
|
51
|
+
"@theholocron/tsdown-config": "^8.9.0-alpha.4",
|
|
51
52
|
"@theholocron/tsconfig": "^8.9.0-alpha.4",
|
|
52
|
-
"@theholocron/misc-utils": "^1.16.1-alpha.3",
|
|
53
53
|
"@theholocron/vitest-config": "^8.9.0-alpha.4",
|
|
54
|
-
"@theholocron/
|
|
55
|
-
"@theholocron/
|
|
54
|
+
"@theholocron/misc-utils": "^1.16.1-alpha.3",
|
|
55
|
+
"@theholocron/github-client": "^1.58.0-alpha.3"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@theholocron/fs-utils": "^1.16.0",
|
|
59
59
|
"@theholocron/github-client": "^1.58.0",
|
|
60
60
|
"@theholocron/misc-utils": "^1.16.0",
|
|
61
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
61
|
+
"@theholocron/cli": "5.0.0-alpha.279"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22"
|