@dosu/cli 0.11.0-alpha.3 → 0.11.0-alpha.4
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/bin/dosu.js +128 -21
- package/package.json +1 -1
package/bin/dosu.js
CHANGED
|
@@ -4341,7 +4341,7 @@ function getSupabaseAnonKey() {
|
|
|
4341
4341
|
function getVersionString() {
|
|
4342
4342
|
return `v${VERSION}`;
|
|
4343
4343
|
}
|
|
4344
|
-
var VERSION = "0.11.0-alpha.
|
|
4344
|
+
var VERSION = "0.11.0-alpha.4";
|
|
4345
4345
|
|
|
4346
4346
|
// src/debug/logger.ts
|
|
4347
4347
|
import {
|
|
@@ -7148,6 +7148,7 @@ var init_open = __esm(() => {
|
|
|
7148
7148
|
// src/setup/github-step.ts
|
|
7149
7149
|
var exports_github_step = {};
|
|
7150
7150
|
__export(exports_github_step, {
|
|
7151
|
+
verifyDataSourcesPersist: () => verifyDataSourcesPersist,
|
|
7151
7152
|
stepConnectGitHubRepo: () => stepConnectGitHubRepo,
|
|
7152
7153
|
detectGitRepo: () => detectGitRepo
|
|
7153
7154
|
});
|
|
@@ -7175,24 +7176,32 @@ function detectGitRepo(cwd = process.cwd()) {
|
|
|
7175
7176
|
}
|
|
7176
7177
|
async function fetchListForOrg(trpc, orgID) {
|
|
7177
7178
|
try {
|
|
7178
|
-
|
|
7179
|
+
const repos = await trpc.githubRepository.listForOrg.query({
|
|
7179
7180
|
org_id: orgID
|
|
7180
7181
|
});
|
|
7182
|
+
return sortReposByRecency(repos);
|
|
7181
7183
|
} catch (err) {
|
|
7182
7184
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7183
7185
|
logger.warn("setup", `listForOrg failed: ${msg}`);
|
|
7184
7186
|
return [];
|
|
7185
7187
|
}
|
|
7186
7188
|
}
|
|
7189
|
+
function sortReposByRecency(repos) {
|
|
7190
|
+
return [...repos].sort((a, b3) => {
|
|
7191
|
+
const ta = Date.parse(a.created_at ?? "") || 0;
|
|
7192
|
+
const tb = Date.parse(b3.created_at ?? "") || 0;
|
|
7193
|
+
return tb - ta;
|
|
7194
|
+
});
|
|
7195
|
+
}
|
|
7187
7196
|
function buildPromptOptions(repos) {
|
|
7188
7197
|
return [
|
|
7189
|
-
...repos.map((r) => ({ kind: "repo", label: r.slug, value: r.slug })),
|
|
7190
7198
|
{
|
|
7191
7199
|
kind: "action",
|
|
7192
7200
|
label: "Add repositories...",
|
|
7193
7201
|
value: ADD_REPOSITORIES_VALUE,
|
|
7194
7202
|
hint: "Open GitHub and refresh this list"
|
|
7195
|
-
}
|
|
7203
|
+
},
|
|
7204
|
+
...repos.map((r) => ({ kind: "repo", label: r.slug, value: r.slug }))
|
|
7196
7205
|
];
|
|
7197
7206
|
}
|
|
7198
7207
|
function hasNewVisibleRepository(previousRepos, nextRepos) {
|
|
@@ -7297,14 +7306,59 @@ async function createDeploymentForRepo(trpc, orgID, spaceID, repo) {
|
|
|
7297
7306
|
deployment_id: d3.deployment_id,
|
|
7298
7307
|
data_source_id: dataSource.data_source_id
|
|
7299
7308
|
})));
|
|
7300
|
-
return {
|
|
7309
|
+
return {
|
|
7310
|
+
deployment_id: deployment.deployment_id,
|
|
7311
|
+
data_source_id: dataSource.data_source_id
|
|
7312
|
+
};
|
|
7301
7313
|
} catch (err) {
|
|
7302
7314
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7303
7315
|
logger.error("setup", `Failed to wire up ${repo.slug}: ${msg}`);
|
|
7304
7316
|
return null;
|
|
7305
7317
|
}
|
|
7306
7318
|
}
|
|
7307
|
-
async function
|
|
7319
|
+
async function verifyDataSourcesPersist(trpc, orgID, expectedDataSourceIds, opts = {}) {
|
|
7320
|
+
const expected = new Set(expectedDataSourceIds);
|
|
7321
|
+
if (expected.size === 0) {
|
|
7322
|
+
return { alive: new Set, dropped: new Set };
|
|
7323
|
+
}
|
|
7324
|
+
const timeoutMs = opts.timeoutMs ?? DATA_SOURCE_VERIFY_POLL_TIMEOUT_MS;
|
|
7325
|
+
const intervalMs = opts.intervalMs ?? DATA_SOURCE_VERIFY_POLL_INTERVAL_MS;
|
|
7326
|
+
const startedAt = Date.now();
|
|
7327
|
+
let alive = new Set;
|
|
7328
|
+
let dropped = new Set;
|
|
7329
|
+
let firstIteration = true;
|
|
7330
|
+
while (firstIteration || Date.now() - startedAt < timeoutMs) {
|
|
7331
|
+
firstIteration = false;
|
|
7332
|
+
let listed = [];
|
|
7333
|
+
try {
|
|
7334
|
+
listed = await trpc.dataSource.list.query({
|
|
7335
|
+
org_id: orgID,
|
|
7336
|
+
excluded_provider_slugs: []
|
|
7337
|
+
});
|
|
7338
|
+
} catch (err) {
|
|
7339
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7340
|
+
logger.warn("setup", `dataSource.list during verify failed: ${msg}`);
|
|
7341
|
+
}
|
|
7342
|
+
const presentNow = new Set(listed.map((d3) => d3.data_source_id).filter((id) => Boolean(id)));
|
|
7343
|
+
alive = new Set([...expected].filter((id) => presentNow.has(id)));
|
|
7344
|
+
dropped = new Set([...expected].filter((id) => !presentNow.has(id)));
|
|
7345
|
+
if (dropped.size > 0)
|
|
7346
|
+
return { alive, dropped };
|
|
7347
|
+
if (timeoutMs === 0)
|
|
7348
|
+
break;
|
|
7349
|
+
await sleep2(intervalMs);
|
|
7350
|
+
}
|
|
7351
|
+
return { alive, dropped };
|
|
7352
|
+
}
|
|
7353
|
+
async function deleteOrphanDeployment(trpc, deploymentID, slug) {
|
|
7354
|
+
try {
|
|
7355
|
+
await trpc.workspaces.delete.mutate(deploymentID);
|
|
7356
|
+
} catch (err) {
|
|
7357
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7358
|
+
logger.warn("setup", `Failed to revert orphan deployment for ${slug}: ${msg}`);
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
async function stepConnectGitHubRepo(cfg, detected = detectGitRepo(), opts = {}) {
|
|
7308
7362
|
logger.info("setup", "Step: connect GitHub repo(s)");
|
|
7309
7363
|
if (!cfg.org_id || !cfg.space_id) {
|
|
7310
7364
|
M2.warn("Cannot connect GitHub: your Dosu workspace is missing org/space context. Re-run `dosu setup` from a fresh state.");
|
|
@@ -7327,9 +7381,10 @@ async function stepConnectGitHubRepo(cfg, detected = detectGitRepo()) {
|
|
|
7327
7381
|
${lines}`);
|
|
7328
7382
|
}
|
|
7329
7383
|
const selected = await promptGitHubRepositories({
|
|
7330
|
-
message:
|
|
7384
|
+
message: `Select repositories to connect ${dim(`(${undeployed.length} available)`)}`,
|
|
7331
7385
|
options: buildPromptOptions(undeployed),
|
|
7332
|
-
initialValues: []
|
|
7386
|
+
initialValues: [],
|
|
7387
|
+
maxItems: REPO_MULTISELECT_MAX_ITEMS
|
|
7333
7388
|
});
|
|
7334
7389
|
if (pD(selected)) {
|
|
7335
7390
|
logger.info("setup", "Repository selection cancelled");
|
|
@@ -7360,29 +7415,55 @@ ${lines}`);
|
|
|
7360
7415
|
continue;
|
|
7361
7416
|
const result = await createDeploymentForRepo(trpc, orgID, spaceID, repo);
|
|
7362
7417
|
if (result) {
|
|
7363
|
-
created.push({
|
|
7418
|
+
created.push({
|
|
7419
|
+
deployment_id: result.deployment_id,
|
|
7420
|
+
data_source_id: result.data_source_id,
|
|
7421
|
+
slug
|
|
7422
|
+
});
|
|
7423
|
+
}
|
|
7424
|
+
}
|
|
7425
|
+
const expectedDsIds = created.map((c) => c.data_source_id).filter((id) => Boolean(id));
|
|
7426
|
+
const survivors = await verifyDataSourcesPersist(trpc, orgID, expectedDsIds, opts.verify);
|
|
7427
|
+
const reverted = [];
|
|
7428
|
+
if (survivors.dropped.size > 0) {
|
|
7429
|
+
const droppedEntries = created.filter((c) => c.data_source_id && survivors.dropped.has(c.data_source_id));
|
|
7430
|
+
for (const entry of droppedEntries) {
|
|
7431
|
+
await deleteOrphanDeployment(trpc, entry.deployment_id, entry.slug);
|
|
7432
|
+
reverted.push({ slug: entry.slug, deployment_id: entry.deployment_id });
|
|
7364
7433
|
}
|
|
7365
7434
|
}
|
|
7366
|
-
|
|
7435
|
+
const survived = created.filter((c) => !c.data_source_id || survivors.alive.has(c.data_source_id));
|
|
7436
|
+
if (survived.length === 0) {
|
|
7367
7437
|
s.stop("Failed");
|
|
7368
|
-
|
|
7438
|
+
if (reverted.length > 0) {
|
|
7439
|
+
M2.error(`Couldn't sync any repos — Dosu doesn't have GitHub access to: ${reverted.map((r) => r.slug).join(", ")}.`);
|
|
7440
|
+
} else {
|
|
7441
|
+
M2.error("Could not connect any repos. Check `dosu logs --tail 50` for details.");
|
|
7442
|
+
}
|
|
7369
7443
|
return { advance: false, has_connected_repo: deployed.length > 0 };
|
|
7370
7444
|
}
|
|
7371
|
-
|
|
7372
|
-
|
|
7445
|
+
if (reverted.length > 0) {
|
|
7446
|
+
s.stop(`Connected ${survived.length} repo${survived.length === 1 ? "" : "s"} · ${reverted.length} skipped`);
|
|
7447
|
+
M2.warn(`Dosu couldn't sync ${reverted.length} repo${reverted.length === 1 ? "" : "s"} (GitHub App has no access): ${reverted.map((r) => r.slug).join(", ")}`);
|
|
7448
|
+
} else {
|
|
7449
|
+
s.stop(`Connected ${survived.length} repo${survived.length === 1 ? "" : "s"}`);
|
|
7450
|
+
}
|
|
7451
|
+
for (const { slug, deployment_id } of survived) {
|
|
7373
7452
|
M2.success(`${slug}
|
|
7374
7453
|
${dim(`deployment ${deployment_id}`)}`);
|
|
7375
7454
|
}
|
|
7376
|
-
const primary = (detected &&
|
|
7455
|
+
const primary = (detected && survived.find((c) => c.slug === detected.slug)) ?? survived[0];
|
|
7456
|
+
const survivingDataSourceIds = survived.map((c) => c.data_source_id).filter((id) => Boolean(id));
|
|
7377
7457
|
return {
|
|
7378
7458
|
advance: true,
|
|
7379
7459
|
has_connected_repo: true,
|
|
7380
7460
|
deployment_id: primary.deployment_id,
|
|
7381
|
-
space_id: cfg.space_id
|
|
7461
|
+
space_id: cfg.space_id,
|
|
7462
|
+
created_data_source_ids: survivingDataSourceIds
|
|
7382
7463
|
};
|
|
7383
7464
|
}
|
|
7384
7465
|
}
|
|
7385
|
-
var INSTALLATION_TIMEOUT_MS, REPO_REFRESH_POLL_INTERVAL_MS = 500, REPO_REFRESH_POLL_TIMEOUT_MS = 1e4;
|
|
7466
|
+
var INSTALLATION_TIMEOUT_MS, REPO_REFRESH_POLL_INTERVAL_MS = 500, REPO_REFRESH_POLL_TIMEOUT_MS = 1e4, REPO_MULTISELECT_MAX_ITEMS = 10, DATA_SOURCE_VERIFY_POLL_INTERVAL_MS = 1000, DATA_SOURCE_VERIFY_POLL_TIMEOUT_MS = 1e4;
|
|
7386
7467
|
var init_github_step = __esm(() => {
|
|
7387
7468
|
init_dist6();
|
|
7388
7469
|
init_trpc();
|
|
@@ -7771,7 +7852,7 @@ async function stepImportGitHubDocs(cfg, opts = {}) {
|
|
|
7771
7852
|
return { advance: false };
|
|
7772
7853
|
}
|
|
7773
7854
|
const trpc = createTypedClient(cfg);
|
|
7774
|
-
const files = opts.waitForFreshDocs ? await waitForImportableGithubFiles(trpc, cfg.org_id, cfg.space_id) : await fetchImportableGithubFiles(trpc, cfg.space_id);
|
|
7855
|
+
const files = opts.waitForFreshDocs ? await waitForImportableGithubFiles(trpc, cfg.org_id, cfg.space_id, opts.expectedDataSourceIds) : await fetchImportableGithubFiles(trpc, cfg.space_id);
|
|
7775
7856
|
if (files === null) {
|
|
7776
7857
|
return { advance: false };
|
|
7777
7858
|
}
|
|
@@ -7891,7 +7972,7 @@ Your GitHub docs are ready, and onboarding is complete.`);
|
|
|
7891
7972
|
M2.warn(`Imported ${processed - failed} of ${total} doc${total === 1 ? "" : "s"}; ${failed} failed.
|
|
7892
7973
|
You can review the failed docs later, but onboarding is complete.`);
|
|
7893
7974
|
}
|
|
7894
|
-
async function waitForImportableGithubFiles(trpc, orgID, spaceID) {
|
|
7975
|
+
async function waitForImportableGithubFiles(trpc, orgID, spaceID, expectedDataSourceIds) {
|
|
7895
7976
|
while (true) {
|
|
7896
7977
|
const spinner = Y2();
|
|
7897
7978
|
spinner.start("Scanning repositories for markdown documents...");
|
|
@@ -7905,7 +7986,7 @@ async function waitForImportableGithubFiles(trpc, orgID, spaceID) {
|
|
|
7905
7986
|
return latestFiles;
|
|
7906
7987
|
}
|
|
7907
7988
|
const dataSources = await fetchGitHubDataSources(trpc, orgID);
|
|
7908
|
-
if (dataSources
|
|
7989
|
+
if (isScanComplete(dataSources, expectedDataSourceIds)) {
|
|
7909
7990
|
spinner.stop("No markdown docs found");
|
|
7910
7991
|
return [];
|
|
7911
7992
|
}
|
|
@@ -7928,6 +8009,24 @@ async function waitForImportableGithubFiles(trpc, orgID, spaceID) {
|
|
|
7928
8009
|
}
|
|
7929
8010
|
}
|
|
7930
8011
|
}
|
|
8012
|
+
function isScanComplete(dataSources, expectedDataSourceIds) {
|
|
8013
|
+
if (expectedDataSourceIds && expectedDataSourceIds.length > 0) {
|
|
8014
|
+
const byId = new Map;
|
|
8015
|
+
for (const ds of dataSources) {
|
|
8016
|
+
if (ds.data_source_id)
|
|
8017
|
+
byId.set(ds.data_source_id, ds);
|
|
8018
|
+
}
|
|
8019
|
+
for (const id of expectedDataSourceIds) {
|
|
8020
|
+
const ds = byId.get(id);
|
|
8021
|
+
if (!ds)
|
|
8022
|
+
continue;
|
|
8023
|
+
if (ds.is_indexed !== true)
|
|
8024
|
+
return false;
|
|
8025
|
+
}
|
|
8026
|
+
return true;
|
|
8027
|
+
}
|
|
8028
|
+
return dataSources.length > 0 && dataSources.every((ds) => ds.is_indexed === true);
|
|
8029
|
+
}
|
|
7931
8030
|
async function fetchGitHubDataSources(trpc, orgID) {
|
|
7932
8031
|
try {
|
|
7933
8032
|
const dataSources = await trpc.dataSource.list.query({
|
|
@@ -8275,9 +8374,14 @@ async function runSetup(opts = {}) {
|
|
|
8275
8374
|
const apiClient = new Client(cfg);
|
|
8276
8375
|
let cloudSetupContext = null;
|
|
8277
8376
|
if (cfg.mode !== MODE_OSS) {
|
|
8377
|
+
const s = Y2();
|
|
8378
|
+
s.start("Loading your workspace...");
|
|
8278
8379
|
cloudSetupContext = await resolveCloudSetupContext(cfg);
|
|
8279
|
-
if (!cloudSetupContext)
|
|
8380
|
+
if (!cloudSetupContext) {
|
|
8381
|
+
s.stop("Workspace load failed");
|
|
8280
8382
|
return;
|
|
8383
|
+
}
|
|
8384
|
+
s.stop("Workspace loaded");
|
|
8281
8385
|
}
|
|
8282
8386
|
if (cfg.mode !== MODE_OSS && cloudSetupContext?.kind === "onboarding") {
|
|
8283
8387
|
const ok = await bindOnboardingDeployment(apiClient, cfg, cloudSetupContext.targetOrg ?? null);
|
|
@@ -8320,7 +8424,8 @@ async function runSetup(opts = {}) {
|
|
|
8320
8424
|
}
|
|
8321
8425
|
const { stepImportGitHubDocs: stepImportGitHubDocs2 } = await Promise.resolve().then(() => (init_github_doc_import_step(), exports_github_doc_import_step));
|
|
8322
8426
|
const importResult = await stepImportGitHubDocs2(cfg, {
|
|
8323
|
-
waitForFreshDocs: Boolean(connectResult.deployment_id)
|
|
8427
|
+
waitForFreshDocs: Boolean(connectResult.deployment_id),
|
|
8428
|
+
expectedDataSourceIds: connectResult.created_data_source_ids
|
|
8324
8429
|
});
|
|
8325
8430
|
if (!importResult.advance)
|
|
8326
8431
|
return;
|
|
@@ -8537,6 +8642,8 @@ async function bindOnboardingDeployment(apiClient, cfg, targetOrg) {
|
|
|
8537
8642
|
cfg.org_id = deployment.org_id;
|
|
8538
8643
|
cfg.space_id = deployment.space_id;
|
|
8539
8644
|
logger.info("setup", `Bound onboarding context org=${targetOrg.org_id} deployment=${deployment.deployment_id}`);
|
|
8645
|
+
M2.success(`Organization
|
|
8646
|
+
${dim(targetOrg.name)}`);
|
|
8540
8647
|
return true;
|
|
8541
8648
|
}
|
|
8542
8649
|
async function resolveOnboardingDeployment(apiClient, targetOrg) {
|