@theholocron/holocron-plugin-github 5.0.0-alpha.199 → 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 +14 -3
- package/dist/index.mjs +72 -4
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess, 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;
|
|
@@ -8,6 +8,7 @@ declare const resolveReleaseToken: (input?: ResolveTokenInput) => string;
|
|
|
8
8
|
declare const resolveAdminToken: (input?: ResolveTokenInput) => string;
|
|
9
9
|
declare const resolveSecretsToken: (input?: ResolveTokenInput) => string;
|
|
10
10
|
declare const resolveDeployToken: (input?: ResolveTokenInput) => string;
|
|
11
|
+
declare const resolveUserSyncToken: (input?: ResolveTokenInput) => string;
|
|
11
12
|
declare const resolveOrgToken: (input?: ResolveTokenInput) => string;
|
|
12
13
|
//#endregion
|
|
13
14
|
//#region src/capabilities/ci.d.ts
|
|
@@ -128,6 +129,8 @@ interface SourceOptions {
|
|
|
128
129
|
repoRoot: string;
|
|
129
130
|
/** Secondary client authenticated with HOLOCRON_ORG_TOKEN for org-scoped operations (teams, custom properties). */
|
|
130
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;
|
|
131
134
|
/** Forwarded to a secondary client created for Pages calls (HOLOCRON_DEPLOY_TOKEN). */
|
|
132
135
|
baseUrl?: string;
|
|
133
136
|
fetch?: typeof fetch;
|
|
@@ -142,6 +145,7 @@ declare class GitHubSource implements Source {
|
|
|
142
145
|
private readonly repoRoot;
|
|
143
146
|
private readonly workflowDir;
|
|
144
147
|
private readonly orgClient?;
|
|
148
|
+
private readonly userSyncClient?;
|
|
145
149
|
private readonly baseUrl?;
|
|
146
150
|
private readonly fetchImpl?;
|
|
147
151
|
constructor(client: GitHubClient, opts: SourceOptions);
|
|
@@ -169,6 +173,13 @@ declare class GitHubSource implements Source {
|
|
|
169
173
|
syncLabels(canonical: ReadonlyArray<LabelDef>, stale: ReadonlyArray<string>): Promise<string>;
|
|
170
174
|
syncProperties(values: Record<string, string | string[]>): Promise<string>;
|
|
171
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>;
|
|
172
183
|
syncTopics(topics: string[]): Promise<string>;
|
|
173
184
|
syncDescription(description: string): Promise<string>;
|
|
174
185
|
syncHomepage(homepage: string): Promise<string>;
|
|
@@ -221,7 +232,7 @@ interface PluginContext {
|
|
|
221
232
|
repo: string;
|
|
222
233
|
repoRoot: string;
|
|
223
234
|
}
|
|
224
|
-
declare function source(ctx: PluginContext, orgClient?: GitHubClient): Source;
|
|
235
|
+
declare function source(ctx: PluginContext, orgClient?: GitHubClient, userSyncClient?: GitHubClient): Source;
|
|
225
236
|
declare function secrets(ctx: PluginContext, orgClient?: GitHubClient): Secrets;
|
|
226
237
|
declare function environments(ctx: PluginContext): Environments;
|
|
227
238
|
declare function ci(ctx: PluginContext): Ci;
|
|
@@ -242,4 +253,4 @@ declare function createPlugin(options: GitHubPluginOptions): {
|
|
|
242
253
|
*/
|
|
243
254
|
declare const AUTH_HINT: string;
|
|
244
255
|
//#endregion
|
|
245
|
-
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, 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,6 +1,6 @@
|
|
|
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
6
|
import { findRootSync } from "@theholocron/fs-utils";
|
|
@@ -34,6 +34,10 @@ const resolveDeployToken = createFeatureResolver({
|
|
|
34
34
|
envName: "HOLOCRON_DEPLOY_TOKEN",
|
|
35
35
|
keyringKey: "github.deploy"
|
|
36
36
|
});
|
|
37
|
+
const resolveUserSyncToken = createFeatureResolver({
|
|
38
|
+
envName: "HOLOCRON_USER_SYNC_TOKEN",
|
|
39
|
+
keyringKey: "github.user-sync"
|
|
40
|
+
});
|
|
37
41
|
const resolveOrgToken = createFeatureResolver({
|
|
38
42
|
envName: "HOLOCRON_ORG_TOKEN",
|
|
39
43
|
keyringKey: "github.org"
|
|
@@ -422,6 +426,46 @@ function toGHScope(scope) {
|
|
|
422
426
|
return scope;
|
|
423
427
|
}
|
|
424
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
|
|
425
469
|
//#region src/capabilities/labels.ts
|
|
426
470
|
/**
|
|
427
471
|
* Idempotently synchronise a repo's labels to the canonical set.
|
|
@@ -505,6 +549,7 @@ var GitHubSource = class {
|
|
|
505
549
|
repoRoot;
|
|
506
550
|
workflowDir;
|
|
507
551
|
orgClient;
|
|
552
|
+
userSyncClient;
|
|
508
553
|
baseUrl;
|
|
509
554
|
fetchImpl;
|
|
510
555
|
constructor(client, opts) {
|
|
@@ -519,6 +564,7 @@ var GitHubSource = class {
|
|
|
519
564
|
});
|
|
520
565
|
this.workflowDir = join(this.repoRoot, ".github", "workflows");
|
|
521
566
|
this.orgClient = opts.orgClient;
|
|
567
|
+
this.userSyncClient = opts.userSyncClient;
|
|
522
568
|
this.baseUrl = opts.baseUrl;
|
|
523
569
|
this.fetchImpl = opts.fetch;
|
|
524
570
|
}
|
|
@@ -611,6 +657,18 @@ var GitHubSource = class {
|
|
|
611
657
|
async syncTeams(teams) {
|
|
612
658
|
return syncTeams(this.orgClient ?? this.client, this.repo, teams);
|
|
613
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
|
+
}
|
|
614
672
|
async syncTopics(topics) {
|
|
615
673
|
return syncTopics(this.client, this.repo, topics);
|
|
616
674
|
}
|
|
@@ -693,11 +751,12 @@ async function verifyToken(token, opts = {}) {
|
|
|
693
751
|
}
|
|
694
752
|
//#endregion
|
|
695
753
|
//#region src/index.ts
|
|
696
|
-
function source(ctx, orgClient) {
|
|
754
|
+
function source(ctx, orgClient, userSyncClient) {
|
|
697
755
|
return new GitHubSource(ctx.client, {
|
|
698
756
|
repo: ctx.repo,
|
|
699
757
|
repoRoot: ctx.repoRoot,
|
|
700
758
|
orgClient,
|
|
759
|
+
userSyncClient,
|
|
701
760
|
baseUrl: ctx.options.baseUrl,
|
|
702
761
|
fetch: ctx.options.fetch
|
|
703
762
|
});
|
|
@@ -776,10 +835,19 @@ function createPlugin(options) {
|
|
|
776
835
|
return;
|
|
777
836
|
}
|
|
778
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
|
+
}
|
|
779
847
|
return {
|
|
780
848
|
name: "@theholocron/holocron-plugin-github",
|
|
781
849
|
capabilities: {
|
|
782
|
-
source: () => source(makeCtx(resolveAdminToken), makeOrgClient()),
|
|
850
|
+
source: () => source(makeCtx(resolveAdminToken), makeOrgClient(), makeUserSyncClient()),
|
|
783
851
|
ci: () => ci(makeCtx(resolveReadToken)),
|
|
784
852
|
secrets: () => makeSecrets(),
|
|
785
853
|
environments: () => environments(makeCtx(resolveAdminToken)),
|
|
@@ -793,4 +861,4 @@ function createPlugin(options) {
|
|
|
793
861
|
*/
|
|
794
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>";
|
|
795
863
|
//#endregion
|
|
796
|
-
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, 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",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@theholocron/eslint-config": "^8.8.2",
|
|
38
38
|
"@theholocron/fs-utils": "^1.16.0",
|
|
39
|
-
"@theholocron/github-client": "^1.
|
|
39
|
+
"@theholocron/github-client": "^1.47.1",
|
|
40
40
|
"@theholocron/http-client": "^1.43.1",
|
|
41
41
|
"@theholocron/misc-utils": "^1.16.0",
|
|
42
42
|
"@theholocron/tsconfig": "^8.8.2",
|
|
@@ -52,13 +52,13 @@
|
|
|
52
52
|
"tsx": "4.23.15",
|
|
53
53
|
"typescript": "^5.9.3",
|
|
54
54
|
"vitest": "^4.1.11",
|
|
55
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
55
|
+
"@theholocron/cli": "5.0.0-alpha.200"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@theholocron/fs-utils": "^1.16.0",
|
|
59
|
-
"@theholocron/github-client": "^1.
|
|
59
|
+
"@theholocron/github-client": "^1.47.1",
|
|
60
60
|
"@theholocron/misc-utils": "^1.16.0",
|
|
61
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
61
|
+
"@theholocron/cli": "5.0.0-alpha.200"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22"
|