@theholocron/holocron-plugin-github 5.0.0-alpha.20 → 5.0.0-alpha.200
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 +25 -25
- package/dist/index.mjs +141 -27
- package/package.json +17 -13
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { GitHubClient, GitHubClientOptions, createGitHubClient } from "@theholocron/github-client";
|
|
2
|
-
import { Auth, AuthError, Ci, CiRun, CiRunFilter, Environment, Environments, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, PagesConfig, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, TeamEntry, TeamEntry as TeamEntry$1, TeamPermission, TrackerDoctorReport, TrackerUser, createFeatureResolver } from "@theholocron/cli";
|
|
2
|
+
import { Auth, AuthError, Ci, CiRun, CiRunFilter, Environment, Environments, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, PagesConfig, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, SourceFile, SourceTeamMember, TeamEntry, TeamEntry as TeamEntry$1, TeamPermission, TrackerDoctorReport, TrackerUser, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess, createFeatureResolver } from "@theholocron/cli";
|
|
3
3
|
//#region src/auth.d.ts
|
|
4
4
|
declare const resolveReadToken: (input?: ResolveTokenInput) => string;
|
|
5
5
|
declare const resolveIssuesToken: (input?: ResolveTokenInput) => string;
|
|
6
6
|
declare const resolveSyncToken: (input?: ResolveTokenInput) => string;
|
|
7
7
|
declare const resolveReleaseToken: (input?: ResolveTokenInput) => string;
|
|
8
8
|
declare const resolveAdminToken: (input?: ResolveTokenInput) => string;
|
|
9
|
+
declare const resolveSecretsToken: (input?: ResolveTokenInput) => string;
|
|
9
10
|
declare const resolveDeployToken: (input?: ResolveTokenInput) => string;
|
|
11
|
+
declare const resolveUserSyncToken: (input?: ResolveTokenInput) => string;
|
|
10
12
|
declare const resolveOrgToken: (input?: ResolveTokenInput) => string;
|
|
11
13
|
//#endregion
|
|
12
14
|
//#region src/capabilities/ci.d.ts
|
|
@@ -106,9 +108,16 @@ interface SecretsOptions {
|
|
|
106
108
|
declare class GitHubSecrets implements Secrets {
|
|
107
109
|
private readonly client;
|
|
108
110
|
private readonly opts;
|
|
111
|
+
private readonly orgClient?;
|
|
109
112
|
readonly key: "secrets";
|
|
110
113
|
readonly providerName = "github";
|
|
111
|
-
|
|
114
|
+
/**
|
|
115
|
+
* `client` handles repo and environment scopes; `orgClient`, when given, handles
|
|
116
|
+
* the organization scope. They differ when a dedicated org-only token exists:
|
|
117
|
+
* it can write org secrets but not repo ones, and `github.admin` is the reverse.
|
|
118
|
+
*/
|
|
119
|
+
constructor(client: GitHubClient, opts: SecretsOptions, orgClient?: GitHubClient | undefined);
|
|
120
|
+
private clientFor;
|
|
112
121
|
listSecrets(scope: SecretScope): Promise<string[]>;
|
|
113
122
|
setSecret(scope: SecretScope, name: string, value: string): Promise<void>;
|
|
114
123
|
deleteSecret(scope: SecretScope, name: string): Promise<void>;
|
|
@@ -120,6 +129,8 @@ interface SourceOptions {
|
|
|
120
129
|
repoRoot: string;
|
|
121
130
|
/** Secondary client authenticated with HOLOCRON_ORG_TOKEN for org-scoped operations (teams, custom properties). */
|
|
122
131
|
orgClient?: GitHubClient;
|
|
132
|
+
/** Client for the files that link GitHub accounts to other services (HOLOCRON_USER_SYNC_TOKEN); falls back to the org client. */
|
|
133
|
+
userSyncClient?: GitHubClient;
|
|
123
134
|
/** Forwarded to a secondary client created for Pages calls (HOLOCRON_DEPLOY_TOKEN). */
|
|
124
135
|
baseUrl?: string;
|
|
125
136
|
fetch?: typeof fetch;
|
|
@@ -134,6 +145,7 @@ declare class GitHubSource implements Source {
|
|
|
134
145
|
private readonly repoRoot;
|
|
135
146
|
private readonly workflowDir;
|
|
136
147
|
private readonly orgClient?;
|
|
148
|
+
private readonly userSyncClient?;
|
|
137
149
|
private readonly baseUrl?;
|
|
138
150
|
private readonly fetchImpl?;
|
|
139
151
|
constructor(client: GitHubClient, opts: SourceOptions);
|
|
@@ -161,6 +173,13 @@ declare class GitHubSource implements Source {
|
|
|
161
173
|
syncLabels(canonical: ReadonlyArray<LabelDef>, stale: ReadonlyArray<string>): Promise<string>;
|
|
162
174
|
syncProperties(values: Record<string, string | string[]>): Promise<string>;
|
|
163
175
|
syncTeams(teams: TeamEntry$1[]): Promise<string>;
|
|
176
|
+
teamMembers(teamSlug: string, org?: string): Promise<SourceTeamMember[]>;
|
|
177
|
+
readFile(path: string, repo?: string): Promise<SourceFile | null>;
|
|
178
|
+
writeFile(path: string, content: string, opts: {
|
|
179
|
+
message: string;
|
|
180
|
+
version?: string;
|
|
181
|
+
repo?: string;
|
|
182
|
+
}): Promise<void>;
|
|
164
183
|
syncTopics(topics: string[]): Promise<string>;
|
|
165
184
|
syncDescription(description: string): Promise<string>;
|
|
166
185
|
syncHomepage(homepage: string): Promise<string>;
|
|
@@ -184,30 +203,11 @@ declare function syncTeams(client: GitHubClient, repo: string, teams: TeamEntry[
|
|
|
184
203
|
declare function encryptSecret(publicKeyBase64: string, value: string): Promise<string>;
|
|
185
204
|
//#endregion
|
|
186
205
|
//#region src/verify-token.d.ts
|
|
187
|
-
/**
|
|
188
|
-
* `verifyToken` — plugin-level export used by `holocron auth set` +
|
|
189
|
-
* `holocron auth check`. Hits `GET /user` and translates the response
|
|
190
|
-
* into the normalized `VerifyTokenResult` shape.
|
|
191
|
-
*
|
|
192
|
-
* Kept as a standalone function (not a capability method) so the auth
|
|
193
|
-
* command can call it without initializing the full plugin — plugin
|
|
194
|
-
* construction requires an already-resolved token, which is exactly
|
|
195
|
-
* what we don't have yet at bootstrap time.
|
|
196
|
-
*/
|
|
197
|
-
interface VerifyTokenSuccess {
|
|
198
|
-
ok: true;
|
|
199
|
-
subject: string;
|
|
200
|
-
}
|
|
201
|
-
interface VerifyTokenFailure {
|
|
202
|
-
ok: false;
|
|
203
|
-
message: string;
|
|
204
|
-
}
|
|
205
|
-
type VerifyTokenResult = VerifyTokenSuccess | VerifyTokenFailure;
|
|
206
206
|
interface VerifyTokenOptions {
|
|
207
207
|
baseUrl?: string;
|
|
208
208
|
fetch?: typeof fetch;
|
|
209
209
|
}
|
|
210
|
-
declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult>;
|
|
210
|
+
declare function verifyToken(token: string, opts?: VerifyTokenOptions): Promise<VerifyTokenResult$1>;
|
|
211
211
|
//#endregion
|
|
212
212
|
//#region src/index.d.ts
|
|
213
213
|
interface GitHubPluginOptions extends ResolveTokenInput {
|
|
@@ -232,8 +232,8 @@ interface PluginContext {
|
|
|
232
232
|
repo: string;
|
|
233
233
|
repoRoot: string;
|
|
234
234
|
}
|
|
235
|
-
declare function source(ctx: PluginContext, orgClient?: GitHubClient): Source;
|
|
236
|
-
declare function secrets(ctx: PluginContext): Secrets;
|
|
235
|
+
declare function source(ctx: PluginContext, orgClient?: GitHubClient, userSyncClient?: GitHubClient): Source;
|
|
236
|
+
declare function secrets(ctx: PluginContext, orgClient?: GitHubClient): Secrets;
|
|
237
237
|
declare function environments(ctx: PluginContext): Environments;
|
|
238
238
|
declare function ci(ctx: PluginContext): Ci;
|
|
239
239
|
declare function issues(ctx: PluginContext): Issues;
|
|
@@ -253,4 +253,4 @@ declare function createPlugin(options: GitHubPluginOptions): {
|
|
|
253
253
|
*/
|
|
254
254
|
declare const AUTH_HINT: string;
|
|
255
255
|
//#endregion
|
|
256
|
-
export { AUTH_HINT, type Auth, AuthError, type CanonicalLabel, GitHubCi, type GitHubClientOptions, GitHubEnvironments, GitHubIssues, GitHubPluginOptions, GitHubSecrets, GitHubSource, type NormalizedTeamEntry, PluginContext, type ResolveTokenInput, type TeamEntry, type TeamPermission, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
|
|
256
|
+
export { AUTH_HINT, type Auth, AuthError, type CanonicalLabel, GitHubCi, type GitHubClientOptions, GitHubEnvironments, GitHubIssues, GitHubPluginOptions, GitHubSecrets, GitHubSource, type NormalizedTeamEntry, PluginContext, type ResolveTokenInput, type TeamEntry, type TeamPermission, type VerifyTokenFailure, type VerifyTokenResult, type VerifyTokenSuccess, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSecretsToken, resolveSyncToken, resolveUserSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { createGitHubClient, createGitHubClient as createGitHubClient$1 } from "@theholocron/github-client";
|
|
3
|
-
import { AuthError, createFeatureResolver } from "@theholocron/cli";
|
|
3
|
+
import { AuthError, ProviderApiError, createFeatureResolver } from "@theholocron/cli";
|
|
4
4
|
import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
|
+
import { findRootSync } from "@theholocron/fs-utils";
|
|
7
|
+
import { errorMessage } from "@theholocron/misc-utils";
|
|
6
8
|
//#region src/auth.ts
|
|
7
9
|
const resolveReadToken = createFeatureResolver({
|
|
8
10
|
envName: "HOLOCRON_READ_TOKEN",
|
|
@@ -24,10 +26,18 @@ const resolveAdminToken = createFeatureResolver({
|
|
|
24
26
|
envName: "HOLOCRON_ADMIN_TOKEN",
|
|
25
27
|
keyringKey: "github.admin"
|
|
26
28
|
});
|
|
29
|
+
const resolveSecretsToken = createFeatureResolver({
|
|
30
|
+
envName: "HOLOCRON_SECRETS_TOKEN",
|
|
31
|
+
keyringKey: "github.secrets"
|
|
32
|
+
});
|
|
27
33
|
const resolveDeployToken = createFeatureResolver({
|
|
28
34
|
envName: "HOLOCRON_DEPLOY_TOKEN",
|
|
29
35
|
keyringKey: "github.deploy"
|
|
30
36
|
});
|
|
37
|
+
const resolveUserSyncToken = createFeatureResolver({
|
|
38
|
+
envName: "HOLOCRON_USER_SYNC_TOKEN",
|
|
39
|
+
keyringKey: "github.user-sync"
|
|
40
|
+
});
|
|
31
41
|
const resolveOrgToken = createFeatureResolver({
|
|
32
42
|
envName: "HOLOCRON_ORG_TOKEN",
|
|
33
43
|
keyringKey: "github.org"
|
|
@@ -374,27 +384,38 @@ async function encryptSecret(publicKeyBase64, value) {
|
|
|
374
384
|
var GitHubSecrets = class {
|
|
375
385
|
client;
|
|
376
386
|
opts;
|
|
387
|
+
orgClient;
|
|
377
388
|
key = "secrets";
|
|
378
389
|
providerName = "github";
|
|
379
|
-
|
|
390
|
+
/**
|
|
391
|
+
* `client` handles repo and environment scopes; `orgClient`, when given, handles
|
|
392
|
+
* the organization scope. They differ when a dedicated org-only token exists:
|
|
393
|
+
* it can write org secrets but not repo ones, and `github.admin` is the reverse.
|
|
394
|
+
*/
|
|
395
|
+
constructor(client, opts, orgClient) {
|
|
380
396
|
this.client = client;
|
|
381
397
|
this.opts = opts;
|
|
398
|
+
this.orgClient = orgClient;
|
|
399
|
+
}
|
|
400
|
+
clientFor(scope) {
|
|
401
|
+
return scope.kind === "organization" ? this.orgClient ?? this.client : this.client;
|
|
382
402
|
}
|
|
383
403
|
async listSecrets(scope) {
|
|
384
|
-
return this.
|
|
404
|
+
return this.clientFor(scope).secrets.listSecrets(this.opts.repo, toGHScope(scope));
|
|
385
405
|
}
|
|
386
406
|
async setSecret(scope, name, value) {
|
|
387
407
|
const ghScope = toGHScope(scope);
|
|
388
|
-
const
|
|
408
|
+
const client = this.clientFor(scope);
|
|
409
|
+
const pk = await client.secrets.getPublicKey(this.opts.repo, ghScope);
|
|
389
410
|
const body = {
|
|
390
411
|
encrypted_value: await encryptSecret(pk.key, value),
|
|
391
412
|
key_id: pk.key_id
|
|
392
413
|
};
|
|
393
414
|
if (scope.kind === "organization") body.visibility = "all";
|
|
394
|
-
await
|
|
415
|
+
await client.secrets.putSecret(this.opts.repo, ghScope, name, body);
|
|
395
416
|
}
|
|
396
417
|
async deleteSecret(scope, name) {
|
|
397
|
-
await this.
|
|
418
|
+
await this.clientFor(scope).secrets.deleteSecret(this.opts.repo, toGHScope(scope), name);
|
|
398
419
|
}
|
|
399
420
|
};
|
|
400
421
|
function toGHScope(scope) {
|
|
@@ -405,6 +426,46 @@ function toGHScope(scope) {
|
|
|
405
426
|
return scope;
|
|
406
427
|
}
|
|
407
428
|
//#endregion
|
|
429
|
+
//#region src/capabilities/files.ts
|
|
430
|
+
/** Reads one file; `null` when it does not exist. `version` is the blob sha `writeFile` needs to replace exactly this one. */
|
|
431
|
+
/** A fine-grained token only reaches the repositories and permissions it was given; say which one is missing. */
|
|
432
|
+
function noAccess(repo, action, cause) {
|
|
433
|
+
return new Error(`the token cannot ${action} files in ${repo} (403): give the user-sync token (HOLOCRON_USER_SYNC_TOKEN, or holocron auth set github.user-sync) access to that repository with Contents: ${action === "read" ? "read" : "read and write"}`, { cause });
|
|
434
|
+
}
|
|
435
|
+
async function readRepoFile(client, repo, path) {
|
|
436
|
+
try {
|
|
437
|
+
const file = await client.git.getContents(repo, path);
|
|
438
|
+
if (file.encoding !== "base64") throw new Error(`${repo}/${path}: unexpected encoding \`${file.encoding}\``);
|
|
439
|
+
return {
|
|
440
|
+
content: Buffer.from(file.content, "base64").toString("utf-8"),
|
|
441
|
+
version: file.sha
|
|
442
|
+
};
|
|
443
|
+
} catch (err) {
|
|
444
|
+
if (err instanceof ProviderApiError && err.status === 403) throw noAccess(repo, "read", err);
|
|
445
|
+
if (!(err instanceof ProviderApiError && err.status === 404)) throw err;
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
await client.repos.getRepo(repo);
|
|
449
|
+
} catch (err) {
|
|
450
|
+
if (err instanceof ProviderApiError && err.status === 404) throw new Error(`${repo} was not found: it does not exist, or the token cannot see it`, { cause: err });
|
|
451
|
+
throw err;
|
|
452
|
+
}
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
/** Creates or replaces one file in a commit; GitHub refuses (409) a `version` that has since changed. */
|
|
456
|
+
async function writeRepoFile(client, repo, path, content, opts) {
|
|
457
|
+
try {
|
|
458
|
+
await client.git.putContents(repo, path, {
|
|
459
|
+
message: opts.message,
|
|
460
|
+
content,
|
|
461
|
+
...opts.version ? { sha: opts.version } : {}
|
|
462
|
+
});
|
|
463
|
+
} catch (err) {
|
|
464
|
+
if (err instanceof ProviderApiError && err.status === 403) throw noAccess(repo, "write", err);
|
|
465
|
+
throw err;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
//#endregion
|
|
408
469
|
//#region src/capabilities/labels.ts
|
|
409
470
|
/**
|
|
410
471
|
* Idempotently synchronise a repo's labels to the canonical set.
|
|
@@ -488,6 +549,7 @@ var GitHubSource = class {
|
|
|
488
549
|
repoRoot;
|
|
489
550
|
workflowDir;
|
|
490
551
|
orgClient;
|
|
552
|
+
userSyncClient;
|
|
491
553
|
baseUrl;
|
|
492
554
|
fetchImpl;
|
|
493
555
|
constructor(client, opts) {
|
|
@@ -496,9 +558,13 @@ var GitHubSource = class {
|
|
|
496
558
|
this.owner = owner;
|
|
497
559
|
this.name = name;
|
|
498
560
|
this.repo = opts.repo;
|
|
499
|
-
this.repoRoot = opts.repoRoot
|
|
500
|
-
|
|
561
|
+
this.repoRoot = findRootSync(opts.repoRoot, ".git", {
|
|
562
|
+
fallback: "start",
|
|
563
|
+
realpath: true
|
|
564
|
+
});
|
|
565
|
+
this.workflowDir = join(this.repoRoot, ".github", "workflows");
|
|
501
566
|
this.orgClient = opts.orgClient;
|
|
567
|
+
this.userSyncClient = opts.userSyncClient;
|
|
502
568
|
this.baseUrl = opts.baseUrl;
|
|
503
569
|
this.fetchImpl = opts.fetch;
|
|
504
570
|
}
|
|
@@ -591,6 +657,18 @@ var GitHubSource = class {
|
|
|
591
657
|
async syncTeams(teams) {
|
|
592
658
|
return syncTeams(this.orgClient ?? this.client, this.repo, teams);
|
|
593
659
|
}
|
|
660
|
+
async teamMembers(teamSlug, org = this.owner) {
|
|
661
|
+
return (await (this.orgClient ?? this.client).teams.members(org, teamSlug)).map((m) => ({
|
|
662
|
+
id: String(m.id),
|
|
663
|
+
login: m.login
|
|
664
|
+
}));
|
|
665
|
+
}
|
|
666
|
+
async readFile(path, repo = this.repo) {
|
|
667
|
+
return readRepoFile(this.userSyncClient ?? this.orgClient ?? this.client, repo, path);
|
|
668
|
+
}
|
|
669
|
+
async writeFile(path, content, opts) {
|
|
670
|
+
return writeRepoFile(this.userSyncClient ?? this.orgClient ?? this.client, opts.repo ?? this.repo, path, content, opts);
|
|
671
|
+
}
|
|
594
672
|
async syncTopics(topics) {
|
|
595
673
|
return syncTopics(this.client, this.repo, topics);
|
|
596
674
|
}
|
|
@@ -652,16 +730,6 @@ async function ensureDir(path) {
|
|
|
652
730
|
}
|
|
653
731
|
//#endregion
|
|
654
732
|
//#region src/verify-token.ts
|
|
655
|
-
/**
|
|
656
|
-
* `verifyToken` — plugin-level export used by `holocron auth set` +
|
|
657
|
-
* `holocron auth check`. Hits `GET /user` and translates the response
|
|
658
|
-
* into the normalized `VerifyTokenResult` shape.
|
|
659
|
-
*
|
|
660
|
-
* Kept as a standalone function (not a capability method) so the auth
|
|
661
|
-
* command can call it without initializing the full plugin — plugin
|
|
662
|
-
* construction requires an already-resolved token, which is exactly
|
|
663
|
-
* what we don't have yet at bootstrap time.
|
|
664
|
-
*/
|
|
665
733
|
async function verifyToken(token, opts = {}) {
|
|
666
734
|
const client = createGitHubClient({
|
|
667
735
|
token,
|
|
@@ -677,23 +745,24 @@ async function verifyToken(token, opts = {}) {
|
|
|
677
745
|
} catch (err) {
|
|
678
746
|
return {
|
|
679
747
|
ok: false,
|
|
680
|
-
message:
|
|
748
|
+
message: errorMessage(err)
|
|
681
749
|
};
|
|
682
750
|
}
|
|
683
751
|
}
|
|
684
752
|
//#endregion
|
|
685
753
|
//#region src/index.ts
|
|
686
|
-
function source(ctx, orgClient) {
|
|
754
|
+
function source(ctx, orgClient, userSyncClient) {
|
|
687
755
|
return new GitHubSource(ctx.client, {
|
|
688
756
|
repo: ctx.repo,
|
|
689
757
|
repoRoot: ctx.repoRoot,
|
|
690
758
|
orgClient,
|
|
759
|
+
userSyncClient,
|
|
691
760
|
baseUrl: ctx.options.baseUrl,
|
|
692
761
|
fetch: ctx.options.fetch
|
|
693
762
|
});
|
|
694
763
|
}
|
|
695
|
-
function secrets(ctx) {
|
|
696
|
-
return new GitHubSecrets(ctx.client, { repo: ctx.repo });
|
|
764
|
+
function secrets(ctx, orgClient) {
|
|
765
|
+
return new GitHubSecrets(ctx.client, { repo: ctx.repo }, orgClient);
|
|
697
766
|
}
|
|
698
767
|
function environments(ctx) {
|
|
699
768
|
return new GitHubEnvironments(ctx.client, { repo: ctx.repo });
|
|
@@ -708,10 +777,11 @@ function issues(ctx) {
|
|
|
708
777
|
}
|
|
709
778
|
function createPlugin(options) {
|
|
710
779
|
function makeCtx(resolver) {
|
|
780
|
+
const token = resolver(options);
|
|
711
781
|
return {
|
|
712
782
|
options,
|
|
713
783
|
client: createGitHubClient$1({
|
|
714
|
-
token
|
|
784
|
+
token,
|
|
715
785
|
baseUrl: options.baseUrl,
|
|
716
786
|
fetch: options.fetch
|
|
717
787
|
}),
|
|
@@ -719,10 +789,45 @@ function createPlugin(options) {
|
|
|
719
789
|
repoRoot: options.repoRoot ?? process.cwd()
|
|
720
790
|
};
|
|
721
791
|
}
|
|
792
|
+
/** A token, or undefined when that feature token is simply not configured. */
|
|
793
|
+
function tryResolve(resolver) {
|
|
794
|
+
try {
|
|
795
|
+
return resolver(options);
|
|
796
|
+
} catch (err) {
|
|
797
|
+
if (err instanceof AuthError) return void 0;
|
|
798
|
+
throw err;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Organization secrets need an org-resource-owner token (`github.secrets`);
|
|
803
|
+
* repo and environment secrets need `github.admin`. Each scope prefers its own
|
|
804
|
+
* token and falls back to the other, so a setup with only one of them keeps
|
|
805
|
+
* working, and an explicit `--token` serves both. With neither configured this
|
|
806
|
+
* fails exactly as the admin-token capabilities do.
|
|
807
|
+
*/
|
|
808
|
+
function makeSecrets() {
|
|
809
|
+
const secretsToken = tryResolve(resolveSecretsToken);
|
|
810
|
+
const adminToken = tryResolve(resolveAdminToken);
|
|
811
|
+
if (!secretsToken && !adminToken) resolveAdminToken(options);
|
|
812
|
+
const clientFor = (token) => createGitHubClient$1({
|
|
813
|
+
token,
|
|
814
|
+
baseUrl: options.baseUrl,
|
|
815
|
+
fetch: options.fetch
|
|
816
|
+
});
|
|
817
|
+
const repoClient = clientFor(adminToken ?? secretsToken);
|
|
818
|
+
const orgClient = clientFor(secretsToken ?? adminToken);
|
|
819
|
+
return secrets({
|
|
820
|
+
options,
|
|
821
|
+
client: repoClient,
|
|
822
|
+
repo: options.repo,
|
|
823
|
+
repoRoot: options.repoRoot ?? process.cwd()
|
|
824
|
+
}, orgClient);
|
|
825
|
+
}
|
|
722
826
|
function makeOrgClient() {
|
|
723
827
|
try {
|
|
828
|
+
const token = resolveOrgToken(options);
|
|
724
829
|
return createGitHubClient$1({
|
|
725
|
-
token
|
|
830
|
+
token,
|
|
726
831
|
baseUrl: options.baseUrl,
|
|
727
832
|
fetch: options.fetch
|
|
728
833
|
});
|
|
@@ -730,12 +835,21 @@ function createPlugin(options) {
|
|
|
730
835
|
return;
|
|
731
836
|
}
|
|
732
837
|
}
|
|
838
|
+
/** The token for the user-sync files; undefined when it is not configured, and the org token is used instead. */
|
|
839
|
+
function makeUserSyncClient() {
|
|
840
|
+
const token = tryResolve(resolveUserSyncToken);
|
|
841
|
+
return token ? createGitHubClient$1({
|
|
842
|
+
token,
|
|
843
|
+
baseUrl: options.baseUrl,
|
|
844
|
+
fetch: options.fetch
|
|
845
|
+
}) : void 0;
|
|
846
|
+
}
|
|
733
847
|
return {
|
|
734
848
|
name: "@theholocron/holocron-plugin-github",
|
|
735
849
|
capabilities: {
|
|
736
|
-
source: () => source(makeCtx(resolveAdminToken), makeOrgClient()),
|
|
850
|
+
source: () => source(makeCtx(resolveAdminToken), makeOrgClient(), makeUserSyncClient()),
|
|
737
851
|
ci: () => ci(makeCtx(resolveReadToken)),
|
|
738
|
-
secrets: () =>
|
|
852
|
+
secrets: () => makeSecrets(),
|
|
739
853
|
environments: () => environments(makeCtx(resolveAdminToken)),
|
|
740
854
|
issues: () => issues(makeCtx(resolveIssuesToken))
|
|
741
855
|
}
|
|
@@ -747,4 +861,4 @@ function createPlugin(options) {
|
|
|
747
861
|
*/
|
|
748
862
|
const AUTH_HINT = "generate fine-grained Personal Access Tokens at https://github.com/settings/tokens (one per feature — see docs/tokens.md for required scopes per operation), then run: holocron auth set github.<feature> <PAT>";
|
|
749
863
|
//#endregion
|
|
750
|
-
export { AUTH_HINT, AuthError, GitHubCi, GitHubEnvironments, GitHubIssues, GitHubSecrets, GitHubSource, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
|
|
864
|
+
export { AUTH_HINT, AuthError, GitHubCi, GitHubEnvironments, GitHubIssues, GitHubSecrets, GitHubSource, ci, createFeatureResolver, createGitHubClient, createPlugin, encryptSecret, environments, issues, normalizeTeamEntry, resolveAdminToken, resolveDeployToken, resolveIssuesToken, resolveOrgToken, resolveReadToken, resolveReleaseToken, resolveSecretsToken, resolveSyncToken, resolveUserSyncToken, secrets, source, syncLabels, syncTeams, verifyToken };
|
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.200",
|
|
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",
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
"plugin",
|
|
10
10
|
"source"
|
|
11
11
|
],
|
|
12
|
-
"homepage": "https://github.com/theholocron/holocron/tree/main/
|
|
12
|
+
"homepage": "https://github.com/theholocron/holocron/tree/main/plugins/holocron-plugin-github#readme",
|
|
13
13
|
"bugs": "https://github.com/theholocron/holocron/issues",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
16
|
"url": "git+https://github.com/theholocron/holocron.git",
|
|
17
|
-
"directory": "
|
|
17
|
+
"directory": "plugins/holocron-plugin-github"
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"author": "Newton Koumantzelis",
|
|
@@ -34,12 +34,14 @@
|
|
|
34
34
|
"libsodium-wrappers": "^0.8.4"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@theholocron/eslint-config": "^8.
|
|
38
|
-
"@theholocron/
|
|
39
|
-
"@theholocron/
|
|
40
|
-
"@theholocron/
|
|
41
|
-
"@theholocron/
|
|
42
|
-
"@theholocron/
|
|
37
|
+
"@theholocron/eslint-config": "^8.8.2",
|
|
38
|
+
"@theholocron/fs-utils": "^1.16.0",
|
|
39
|
+
"@theholocron/github-client": "^1.47.1",
|
|
40
|
+
"@theholocron/http-client": "^1.43.1",
|
|
41
|
+
"@theholocron/misc-utils": "^1.16.0",
|
|
42
|
+
"@theholocron/tsconfig": "^8.8.2",
|
|
43
|
+
"@theholocron/tsdown-config": "^8.8.2",
|
|
44
|
+
"@theholocron/vitest-config": "^8.8.2",
|
|
43
45
|
"@types/node": "^26",
|
|
44
46
|
"@vitest/coverage-v8": "^4.1.11",
|
|
45
47
|
"@vitest/eslint-plugin": "^1.6.27",
|
|
@@ -47,14 +49,16 @@
|
|
|
47
49
|
"eslint-plugin-n": "^18.3.0",
|
|
48
50
|
"globals": "^17.11.0",
|
|
49
51
|
"tsdown": "^0.22.14",
|
|
50
|
-
"tsx": "4.23.
|
|
52
|
+
"tsx": "4.23.15",
|
|
51
53
|
"typescript": "^5.9.3",
|
|
52
54
|
"vitest": "^4.1.11",
|
|
53
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
55
|
+
"@theholocron/cli": "5.0.0-alpha.200"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
|
-
"@theholocron/
|
|
57
|
-
"@theholocron/
|
|
58
|
+
"@theholocron/fs-utils": "^1.16.0",
|
|
59
|
+
"@theholocron/github-client": "^1.47.1",
|
|
60
|
+
"@theholocron/misc-utils": "^1.16.0",
|
|
61
|
+
"@theholocron/cli": "5.0.0-alpha.200"
|
|
58
62
|
},
|
|
59
63
|
"engines": {
|
|
60
64
|
"node": ">=22"
|