@theholocron/holocron-plugin-github 5.0.0-alpha.380 → 5.0.0-alpha.382
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 +2 -2
- package/dist/index.mjs +47 -16
- package/package.json +10 -10
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AddedItem, Auth, AuthError, BoardItem, BoardItemInput, BoardState, BoardSummary, BoardTemplate, Ci, CiRun, CiRunFilter, EnsureReport, Environment, Environments, ImportOptions, ImportResult, Issue, IssueRecord, IssueSearchFilter, IssueSelector, Issues, LabelDef, LifecycleResult, LifecycleSlot, MoveReport, PagesConfig, PluginToken, Projects, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, SourceBranch, SourceFile, SourceRepoInfo, SourceRulesetDetail, SourceSecurity, SourceTeamMember, SyncResult, TeamEntry, TeamEntry as TeamEntry$1, TeamPermission, TeamPermission as TeamPermission$1, TrackerDoctorReport, TrackerUser, VerifyTokenFailure, VerifyTokenResult, VerifyTokenResult as VerifyTokenResult$1, VerifyTokenSuccess, createFeatureResolver } from "@theholocron/cli";
|
|
1
|
+
import { AddedItem, Auth, AuthError, BoardItem, BoardItemInput, BoardState, BoardSummary, BoardTemplate, Ci, CiRun, CiRunFilter, EnsureReport, Environment, Environments, ExportInfo, ImportOptions, ImportResult, Issue, IssueRecord, IssueSearchFilter, IssueSelector, Issues, LabelDef, LifecycleResult, LifecycleSlot, MoveReport, PagesConfig, PluginToken, Projects, PullRequest, RepoRef, RepoSettings, ResolveTokenInput, Ruleset, SecretScope, Secrets, Source, SourceBranch, SourceFile, SourceRepoInfo, SourceRulesetDetail, SourceSecurity, SourceTeamMember, SyncResult, 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, GraphQLClient, createGitHubClient } from "@theholocron/github-client";
|
|
3
3
|
/** Resolves the token for read-only GitHub access (`HOLOCRON_READ_TOKEN`, keyring key `github.read`). */
|
|
4
4
|
export declare const resolveReadToken: import("@theholocron/cli").FeatureResolver;
|
|
@@ -105,7 +105,7 @@ export declare class GitHubIssues implements Issues {
|
|
|
105
105
|
/** Checks the authenticated user, the repo and the label-backed lifecycle slots, and reports what resolves. */
|
|
106
106
|
doctor(): Promise<TrackerDoctorReport>;
|
|
107
107
|
/** Reads issues with their comments, priority label, parent and blockers, for `holocron migrate`. */
|
|
108
|
-
export(selector: IssueSelector): Promise<IssueRecord[]>;
|
|
108
|
+
export(selector: IssueSelector, info?: ExportInfo): Promise<IssueRecord[]>;
|
|
109
109
|
/** Makes the records as issues; one already made by an earlier run is skipped. */
|
|
110
110
|
import(records: IssueRecord[], options?: ImportOptions): Promise<ImportResult[]>;
|
|
111
111
|
/** Like `import`, and it also updates what an earlier import or sync made, for `holocron sync issues`. */
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { AuthError, MissingTokenError, ProviderApiError, connectionProbe, createFeatureResolver } from "@theholocron/cli";
|
|
2
|
+
import { AuthError, MissingTokenError, ProviderApiError, connectionProbe, createFeatureResolver, pickByCreation, readKeysLimited, reportProgress } from "@theholocron/cli";
|
|
3
3
|
import { createGitHubClient, createGitHubClient as createGitHubClient$1 } from "@theholocron/github-client";
|
|
4
4
|
import { mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
@@ -209,26 +209,51 @@ function explainSecondaryLimit(err) {
|
|
|
209
209
|
if (err instanceof ProviderApiError && (err.status === 403 || err.status === 429) && String(err.details).includes("secondary rate limit")) return /* @__PURE__ */ new Error("GitHub's secondary rate limit stopped the export. It limits bursts of requests, not the hourly quota, and nothing has been written. Wait a couple of minutes and run the command again.");
|
|
210
210
|
return err;
|
|
211
211
|
}
|
|
212
|
-
/**
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Reads the issues `selector` names, with their comments, priority label, parent and blockers.
|
|
214
|
+
*
|
|
215
|
+
* With `limit`, only that many survivors of the other filters are read, from the `order` end of the creation order. A
|
|
216
|
+
* list of keys is sorted by issue number (which rises with creation in one repository) before anything is fetched, then
|
|
217
|
+
* fetched a few at a time until enough are kept; a listing already carries `created_at`, so it is cut before the
|
|
218
|
+
* per-issue comment and link requests. `info.matched` receives how many the selection matched before the cut.
|
|
219
|
+
*/
|
|
220
|
+
async function exportIssues(client, repo, selector, info = {}) {
|
|
221
|
+
return readIssues(client, repo, selector, info).catch((err) => {
|
|
215
222
|
throw explainSecondaryLimit(err);
|
|
216
223
|
});
|
|
217
224
|
}
|
|
218
|
-
async function readIssues(client, repo, selector) {
|
|
225
|
+
async function readIssues(client, repo, selector, info) {
|
|
219
226
|
const [owner = "", name = ""] = repo.split("/", 2);
|
|
220
|
-
let raw;
|
|
221
|
-
if (selector.keys) raw = await mapLimit(selector.keys, EXPORT_CONCURRENCY, (k) => client.issues.getIssue(repo, parseNumber(k)));
|
|
222
|
-
else if (selector.milestone) {
|
|
223
|
-
const milestone = await findMilestone(client, repo, selector.milestone);
|
|
224
|
-
if (!milestone) throw new Error(`Milestone "${selector.milestone}" not found in ${repo}.`);
|
|
225
|
-
raw = await listAll(client, repo, { milestone: String(milestone.number) });
|
|
226
|
-
} else if (selector.all) raw = await listAll(client, repo, {});
|
|
227
|
-
else throw new Error("export needs keys, a milestone or all");
|
|
228
227
|
const since = selector.since ? Date.parse(selector.since) : void 0;
|
|
229
|
-
const
|
|
228
|
+
const survives = (i) => !i.pull_request && !(selector.openOnly && i.state === "closed") && (since === void 0 || Date.parse(i.updated_at) >= since);
|
|
229
|
+
const { limit, order = "oldest" } = selector;
|
|
230
|
+
let issues;
|
|
231
|
+
if (selector.keys) {
|
|
232
|
+
const fetch = (k) => client.issues.getIssue(repo, parseNumber(k));
|
|
233
|
+
info.matched = selector.keys.length;
|
|
234
|
+
issues = limit === void 0 ? (await mapLimit(selector.keys, EXPORT_CONCURRENCY, fetch)).filter(survives) : await readKeysLimited({
|
|
235
|
+
keys: selector.keys,
|
|
236
|
+
order,
|
|
237
|
+
limit,
|
|
238
|
+
concurrency: EXPORT_CONCURRENCY,
|
|
239
|
+
fetch,
|
|
240
|
+
keep: survives
|
|
241
|
+
});
|
|
242
|
+
} else {
|
|
243
|
+
let raw;
|
|
244
|
+
if (selector.milestone) {
|
|
245
|
+
const milestone = await findMilestone(client, repo, selector.milestone);
|
|
246
|
+
if (!milestone) throw new Error(`Milestone "${selector.milestone}" not found in ${repo}.`);
|
|
247
|
+
raw = await listAll(client, repo, { milestone: String(milestone.number) });
|
|
248
|
+
} else if (selector.all) raw = await listAll(client, repo, {});
|
|
249
|
+
else throw new Error("export needs keys, a milestone or all");
|
|
250
|
+
issues = raw.filter(survives);
|
|
251
|
+
info.matched = issues.length;
|
|
252
|
+
if (limit !== void 0) issues = pickByCreation(issues, (i) => i.created_at ?? i.updated_at, order, limit);
|
|
253
|
+
}
|
|
230
254
|
const records = [];
|
|
231
255
|
for (const issue of issues) {
|
|
256
|
+
reportProgress(info.onProgress, records.length, issues.length);
|
|
232
257
|
const comments = await client.issues.listComments(repo, issue.number);
|
|
233
258
|
const links = (await client.graphql.query(LINK_QUERY, {
|
|
234
259
|
owner,
|
|
@@ -265,6 +290,7 @@ async function readIssues(client, repo, selector) {
|
|
|
265
290
|
...migratedFrom ? { migratedFrom } : {}
|
|
266
291
|
});
|
|
267
292
|
}
|
|
293
|
+
reportProgress(info.onProgress, records.length, issues.length);
|
|
268
294
|
return records;
|
|
269
295
|
}
|
|
270
296
|
/** Makes the records as issues, skipping any whose source address an earlier run already recorded. */
|
|
@@ -275,6 +301,7 @@ async function importIssues(client, repo, records, options = {}) {
|
|
|
275
301
|
if (url) existing.set(url, issue.number);
|
|
276
302
|
}
|
|
277
303
|
const results = [];
|
|
304
|
+
const tick = () => reportProgress(options.onProgress, results.length, records.length);
|
|
278
305
|
for (const record of records) {
|
|
279
306
|
const found = existing.get(record.url);
|
|
280
307
|
if (found !== void 0) {
|
|
@@ -284,6 +311,7 @@ async function importIssues(client, repo, records, options = {}) {
|
|
|
284
311
|
created: false,
|
|
285
312
|
dropped: []
|
|
286
313
|
});
|
|
314
|
+
tick();
|
|
287
315
|
continue;
|
|
288
316
|
}
|
|
289
317
|
const dropped = droppedFor(record);
|
|
@@ -293,6 +321,7 @@ async function importIssues(client, repo, records, options = {}) {
|
|
|
293
321
|
created: true,
|
|
294
322
|
dropped
|
|
295
323
|
});
|
|
324
|
+
tick();
|
|
296
325
|
continue;
|
|
297
326
|
}
|
|
298
327
|
const number = await createFromRecord(client, repo, record, options);
|
|
@@ -302,6 +331,7 @@ async function importIssues(client, repo, records, options = {}) {
|
|
|
302
331
|
created: true,
|
|
303
332
|
dropped
|
|
304
333
|
});
|
|
334
|
+
tick();
|
|
305
335
|
}
|
|
306
336
|
return results;
|
|
307
337
|
}
|
|
@@ -386,6 +416,7 @@ async function syncIssues(client, repo, records, options = {}) {
|
|
|
386
416
|
for (const record of records) try {
|
|
387
417
|
const found = existing.get(record.url);
|
|
388
418
|
results.push(found ? await update(client, repo, found, record, options) : await create(client, repo, record, options));
|
|
419
|
+
reportProgress(options.onProgress, results.length, records.length);
|
|
389
420
|
} catch (err) {
|
|
390
421
|
if (isRateLimited(err)) return results;
|
|
391
422
|
throw err;
|
|
@@ -628,8 +659,8 @@ var GitHubIssues = class {
|
|
|
628
659
|
};
|
|
629
660
|
}
|
|
630
661
|
/** Reads issues with their comments, priority label, parent and blockers, for `holocron migrate`. */
|
|
631
|
-
export(selector) {
|
|
632
|
-
return exportIssues(this.client, this.repo, selector);
|
|
662
|
+
export(selector, info) {
|
|
663
|
+
return exportIssues(this.client, this.repo, selector, info);
|
|
633
664
|
}
|
|
634
665
|
/** Makes the records as issues; one already made by an earlier run is skipped. */
|
|
635
666
|
import(records, 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.382",
|
|
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.1.0",
|
|
47
|
-
"@theholocron/cli": "5.0.0-alpha.
|
|
48
|
-
"@theholocron/
|
|
49
|
-
"@theholocron/
|
|
50
|
-
"@theholocron/
|
|
51
|
-
"@theholocron/eslint-config": "^8.9.0-alpha.12",
|
|
52
|
-
"@theholocron/tsconfig": "^8.9.0-alpha.12",
|
|
47
|
+
"@theholocron/cli": "5.0.0-alpha.382",
|
|
48
|
+
"@theholocron/eslint-config": "^8.9.0-alpha.13",
|
|
49
|
+
"@theholocron/http-client": "^1.58.0-alpha.23",
|
|
50
|
+
"@theholocron/github-client": "^1.58.0-alpha.23",
|
|
53
51
|
"@theholocron/misc-utils": "^1.17.0-alpha.2",
|
|
54
|
-
"@theholocron/
|
|
55
|
-
"@theholocron/
|
|
52
|
+
"@theholocron/tsdown-config": "^8.9.0-alpha.13",
|
|
53
|
+
"@theholocron/fs-utils": "^1.17.0-alpha.2",
|
|
54
|
+
"@theholocron/tsconfig": "^8.9.0-alpha.13",
|
|
55
|
+
"@theholocron/vitest-config": "^8.9.0-alpha.13"
|
|
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.382"
|
|
62
62
|
},
|
|
63
63
|
"engines": {
|
|
64
64
|
"node": ">=22"
|