@databricks-solutions/lakebase-scm-utils 0.3.9 → 0.3.11
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/{pr-e-E4aP4j.d.cts → pr-D-eayWyJ.d.cts} +59 -1
- package/dist/{pr-e-E4aP4j.d.ts → pr-D-eayWyJ.d.ts} +59 -1
- package/dist/scripts/git/index.cjs +30 -14
- package/dist/scripts/git/index.d.cts +32 -1
- package/dist/scripts/git/index.d.ts +32 -1
- package/dist/scripts/git/index.js +28 -14
- package/dist/scripts/github/index.d.cts +2 -60
- package/dist/scripts/github/index.d.ts +2 -60
- package/dist/scripts/index.cjs +301 -98
- package/dist/scripts/index.d.cts +4 -4
- package/dist/scripts/index.d.ts +4 -4
- package/dist/scripts/index.js +296 -98
- package/dist/scripts/lakebase/branch.cli.cjs +55 -10
- package/dist/scripts/lakebase/branch.cli.js +55 -10
- package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +59 -24
- package/dist/scripts/lakebase/ci-resolve-branch.cli.js +59 -24
- package/dist/scripts/lakebase/collapse-heads.cli.cjs +16 -14
- package/dist/scripts/lakebase/collapse-heads.cli.js +16 -14
- package/dist/scripts/lakebase/cut-backup.cli.cjs +43 -10
- package/dist/scripts/lakebase/cut-backup.cli.js +43 -10
- package/dist/scripts/lakebase/cut-tier.cli.cjs +43 -10
- package/dist/scripts/lakebase/cut-tier.cli.js +43 -10
- package/dist/scripts/lakebase/detect-language.cli.cjs +16 -14
- package/dist/scripts/lakebase/detect-language.cli.js +16 -14
- package/dist/scripts/lakebase/doctor.cli.cjs +16 -14
- package/dist/scripts/lakebase/doctor.cli.js +16 -14
- package/dist/scripts/lakebase/get-connection.cli.cjs +16 -14
- package/dist/scripts/lakebase/get-connection.cli.js +16 -14
- package/dist/scripts/lakebase/index.cjs +313 -99
- package/dist/scripts/lakebase/index.d.cts +97 -2
- package/dist/scripts/lakebase/index.d.ts +97 -2
- package/dist/scripts/lakebase/index.js +310 -99
- package/dist/scripts/lakebase/infra-runner.cli.cjs +16 -14
- package/dist/scripts/lakebase/infra-runner.cli.js +16 -14
- package/dist/scripts/lakebase/new-migration.cli.cjs +16 -14
- package/dist/scripts/lakebase/new-migration.cli.js +16 -14
- package/dist/scripts/lakebase/schema-diff.cli.cjs +16 -14
- package/dist/scripts/lakebase/schema-diff.cli.js +16 -14
- package/dist/scripts/lakebase/schema-migrate.cli.cjs +16 -14
- package/dist/scripts/lakebase/schema-migrate.cli.js +16 -14
- package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +59 -24
- package/dist/scripts/lakebase/scm-claim-feature.cli.js +59 -24
- package/dist/scripts/lakebase/scm-doctor.cli.cjs +59 -24
- package/dist/scripts/lakebase/scm-doctor.cli.js +59 -24
- package/dist/scripts/lakebase/scm-merge.cli.cjs +16 -14
- package/dist/scripts/lakebase/scm-merge.cli.js +16 -14
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +16 -14
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +16 -14
- package/dist/scripts/lakebase/scm-recover-orphans.cli.cjs +43 -10
- package/dist/scripts/lakebase/scm-recover-orphans.cli.js +43 -10
- package/dist/scripts/lakebase/snapshot.cli.cjs +418 -0
- package/dist/scripts/lakebase/snapshot.cli.d.cts +1 -0
- package/dist/scripts/lakebase/snapshot.cli.d.ts +1 -0
- package/dist/scripts/lakebase/snapshot.cli.js +395 -0
- package/dist/scripts/util/index.cjs +2 -2
- package/dist/scripts/util/index.js +2 -2
- package/package.json +2 -1
- package/scripts/git/commit-push.ts +60 -14
- package/scripts/lakebase/branch-create.ts +93 -14
- package/scripts/lakebase/branch.cli.ts +15 -0
- package/scripts/lakebase/create-preflight.ts +213 -1
- package/scripts/lakebase/create-project.ts +98 -30
- package/scripts/lakebase/get-connection.ts +29 -12
- package/scripts/lakebase/snapshot.cli.ts +117 -0
- package/scripts/lakebase/snapshot.ts +85 -0
- package/templates/project/common/scripts/run-tests.sh +43 -2
- package/templates/project/python/tests/conftest.py +22 -0
- package/templates/project/common/tests/e2e/__pycache__/conftest.cpython-314.pyc +0 -0
- package/templates/project/python/tests/__pycache__/conftest.cpython-314.pyc +0 -0
|
@@ -2291,9 +2291,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
|
|
|
2291
2291
|
}
|
|
2292
2292
|
|
|
2293
2293
|
// scripts/lakebase/branch-create.ts
|
|
2294
|
+
function snapshotPath(instance, snapshot) {
|
|
2295
|
+
return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
|
|
2296
|
+
}
|
|
2297
|
+
function applyExpiration(spec, ttl, noExpiry) {
|
|
2298
|
+
if (ttl && noExpiry === true) {
|
|
2299
|
+
throw new LakebaseBranchError(
|
|
2300
|
+
`Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2303
|
+
if (ttl) spec.ttl = ttl;
|
|
2304
|
+
else if (noExpiry ?? true) spec.no_expiry = true;
|
|
2305
|
+
}
|
|
2294
2306
|
async function createBranch(args) {
|
|
2295
2307
|
const sanitized = sanitizeBranchName(args.branch);
|
|
2296
2308
|
const lookup = { instance: args.instance, host: args.host };
|
|
2309
|
+
if (args.fromSnapshot) {
|
|
2310
|
+
if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
|
|
2311
|
+
throw new LakebaseBranchError(
|
|
2312
|
+
`fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
const existing2 = await getBranchByName(sanitized, lookup);
|
|
2316
|
+
if (existing2) return existing2;
|
|
2317
|
+
const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
|
|
2318
|
+
applyExpiration(spec, args.ttl, args.noExpiry);
|
|
2319
|
+
try {
|
|
2320
|
+
await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
|
|
2321
|
+
} catch (err) {
|
|
2322
|
+
if (err instanceof LakebaseBranchTtlTooLongError) throw err;
|
|
2323
|
+
const landed = await getBranchByName(sanitized, lookup);
|
|
2324
|
+
if (!landed) throw err;
|
|
2325
|
+
}
|
|
2326
|
+
return waitForBranchReady({
|
|
2327
|
+
instance: args.instance,
|
|
2328
|
+
host: args.host,
|
|
2329
|
+
branch: sanitized,
|
|
2330
|
+
timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
|
|
2331
|
+
pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2297
2334
|
let sourceBranchPath;
|
|
2298
2335
|
if (args.parentBranch) {
|
|
2299
2336
|
if (looksLikeBranchUid(args.parentBranch)) {
|
|
@@ -2341,19 +2378,15 @@ async function createBranch(args) {
|
|
|
2341
2378
|
assertSourceMatches(existing, sourceBranchPath, sanitized);
|
|
2342
2379
|
return existing;
|
|
2343
2380
|
}
|
|
2344
|
-
if (args.
|
|
2381
|
+
if (args.sourceBranchTime && args.sourceBranchLsn) {
|
|
2345
2382
|
throw new LakebaseBranchError(
|
|
2346
|
-
`
|
|
2383
|
+
`sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
|
|
2347
2384
|
);
|
|
2348
2385
|
}
|
|
2349
|
-
const specObj = {
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
specObj.ttl = args.ttl;
|
|
2354
|
-
} else if (args.noExpiry ?? true) {
|
|
2355
|
-
specObj.no_expiry = true;
|
|
2356
|
-
}
|
|
2386
|
+
const specObj = { source_branch: sourceBranchPath };
|
|
2387
|
+
if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
|
|
2388
|
+
else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
|
|
2389
|
+
applyExpiration(specObj, args.ttl, args.noExpiry);
|
|
2357
2390
|
try {
|
|
2358
2391
|
await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
|
|
2359
2392
|
} catch (err) {
|
|
@@ -2521,8 +2554,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
|
2521
2554
|
var cached;
|
|
2522
2555
|
function substrateSelfVersion() {
|
|
2523
2556
|
if (cached !== void 0) return cached;
|
|
2524
|
-
if ("0.3.
|
|
2525
|
-
cached = "0.3.
|
|
2557
|
+
if ("0.3.11".length > 0) {
|
|
2558
|
+
cached = "0.3.11";
|
|
2526
2559
|
return cached;
|
|
2527
2560
|
}
|
|
2528
2561
|
cached = "unknown";
|
|
@@ -2569,22 +2602,24 @@ async function getConnection(args) {
|
|
|
2569
2602
|
const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
|
|
2570
2603
|
if (args.output === "dsn") {
|
|
2571
2604
|
const host2 = await resolveEndpointHost(args.instance, branchId);
|
|
2572
|
-
const { token, email: email2 } = await mintCredential(endpointPath2);
|
|
2573
|
-
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password:
|
|
2605
|
+
const { token: token2, email: email2 } = await mintCredential(endpointPath2);
|
|
2606
|
+
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
|
|
2574
2607
|
return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
|
|
2575
2608
|
}
|
|
2576
2609
|
const host = await resolveEndpointHost(args.instance, branchId);
|
|
2577
|
-
const email = await resolveCurrentUser();
|
|
2578
2610
|
process.env.PGAPPNAME = connectionApplicationName();
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2611
|
+
if (args.workspaceClient !== void 0) {
|
|
2612
|
+
const email2 = await resolveCurrentUser();
|
|
2613
|
+
return createLakebasePool({
|
|
2614
|
+
endpoint: endpointPath2,
|
|
2615
|
+
host,
|
|
2616
|
+
database,
|
|
2617
|
+
user: email2,
|
|
2618
|
+
workspaceClient: args.workspaceClient
|
|
2619
|
+
});
|
|
2620
|
+
}
|
|
2621
|
+
const { token, email } = await mintCredential(endpointPath2);
|
|
2622
|
+
return createLakebasePool({ host, database, user: email, password: token });
|
|
2588
2623
|
}
|
|
2589
2624
|
async function resolveEndpointHost(instance, branch) {
|
|
2590
2625
|
const branchId = await resolveBranchId({ instance, branch });
|
|
@@ -11100,6 +11135,26 @@ async function createRepo(name, opts = {}) {
|
|
|
11100
11135
|
wrap2(err, `Failed to create repository "${name}"`);
|
|
11101
11136
|
}
|
|
11102
11137
|
}
|
|
11138
|
+
async function deleteRepo(name) {
|
|
11139
|
+
try {
|
|
11140
|
+
const { owner, repo } = parseOwnerRepo(name);
|
|
11141
|
+
const ctx = await newContext();
|
|
11142
|
+
await ctx.octokit.rest.repos.delete({ owner, repo });
|
|
11143
|
+
} catch (err) {
|
|
11144
|
+
wrap2(err, `Failed to delete repository "${name}"`);
|
|
11145
|
+
}
|
|
11146
|
+
}
|
|
11147
|
+
async function repoExists(name) {
|
|
11148
|
+
try {
|
|
11149
|
+
const { owner, repo } = parseOwnerRepo(name);
|
|
11150
|
+
const ctx = await newContext();
|
|
11151
|
+
await ctx.octokit.rest.repos.get({ owner, repo });
|
|
11152
|
+
return true;
|
|
11153
|
+
} catch (err) {
|
|
11154
|
+
if (err instanceof RequestError && err.status === 404) return false;
|
|
11155
|
+
wrap2(err, `Failed to check repository "${name}"`);
|
|
11156
|
+
}
|
|
11157
|
+
}
|
|
11103
11158
|
async function getActionsEnabled(ownerRepo) {
|
|
11104
11159
|
try {
|
|
11105
11160
|
const { owner, repo } = parseOwnerRepo(ownerRepo);
|
|
@@ -11168,6 +11223,70 @@ async function checkGitHubWorkflowScope(probe = () => checkGitHubScopes(["workfl
|
|
|
11168
11223
|
return { ok: true };
|
|
11169
11224
|
}
|
|
11170
11225
|
}
|
|
11226
|
+
async function checkGitHubPreflight(input) {
|
|
11227
|
+
const warnings = [];
|
|
11228
|
+
const hard = input.hardScopes ?? ["repo", "workflow"];
|
|
11229
|
+
const advisory = input.advisoryScopes ?? ["delete_repo"];
|
|
11230
|
+
const currentUserProbe = input.currentUser ?? getCurrentUser;
|
|
11231
|
+
const scopesProbe = input.scopes ?? ((req) => checkGitHubScopes(req));
|
|
11232
|
+
const repoExistsProbe = input.repoExists ?? repoExists;
|
|
11233
|
+
let activeUser;
|
|
11234
|
+
try {
|
|
11235
|
+
activeUser = await currentUserProbe();
|
|
11236
|
+
} catch (err) {
|
|
11237
|
+
return {
|
|
11238
|
+
ok: false,
|
|
11239
|
+
warnings,
|
|
11240
|
+
reason: `GitHub authentication failed: ${err instanceof Error ? err.message : String(err)}. Sign in with \`gh auth login\`, or set GITHUB_TOKEN to a valid token, then re-run.`
|
|
11241
|
+
};
|
|
11242
|
+
}
|
|
11243
|
+
if (activeUser.toLowerCase() !== input.owner.toLowerCase()) {
|
|
11244
|
+
warnings.push(
|
|
11245
|
+
`Signed in to GitHub as "${activeUser}" but creating under "${input.owner}" (an org or another account); ensure "${activeUser}" can create repositories there.`
|
|
11246
|
+
);
|
|
11247
|
+
}
|
|
11248
|
+
try {
|
|
11249
|
+
const { granted, missing } = await scopesProbe([...hard, ...advisory]);
|
|
11250
|
+
if (granted !== null) {
|
|
11251
|
+
const missingHard = missing.filter((s) => hard.includes(s));
|
|
11252
|
+
const missingAdvisory = missing.filter((s) => advisory.includes(s));
|
|
11253
|
+
if (missingHard.length > 0) {
|
|
11254
|
+
return {
|
|
11255
|
+
ok: false,
|
|
11256
|
+
warnings,
|
|
11257
|
+
activeUser,
|
|
11258
|
+
reason: `GitHub token missing required scope(s): ${missingHard.join(", ")} (grants [${granted.join(", ") || "none"}]). Fix: gh auth refresh -h github.com -s ${[...hard].join(",")}`
|
|
11259
|
+
};
|
|
11260
|
+
}
|
|
11261
|
+
if (missingAdvisory.length > 0) {
|
|
11262
|
+
warnings.push(
|
|
11263
|
+
`GitHub token missing the ${missingAdvisory.join(", ")} scope \u2014 automatic rollback of the repo on a failed create is unavailable (you would delete it by hand). Grant it with: gh auth refresh -h github.com -s delete_repo`
|
|
11264
|
+
);
|
|
11265
|
+
}
|
|
11266
|
+
} else {
|
|
11267
|
+
warnings.push(
|
|
11268
|
+
"GitHub token scopes are not visible (fine-grained PAT or App token); cannot pre-verify repo/workflow access , the create will surface any gap when it pushes."
|
|
11269
|
+
);
|
|
11270
|
+
}
|
|
11271
|
+
} catch {
|
|
11272
|
+
warnings.push("Could not read GitHub token scopes (probe error); skipping the scope pre-check.");
|
|
11273
|
+
}
|
|
11274
|
+
try {
|
|
11275
|
+
if (await repoExistsProbe(`${input.owner}/${input.repoName}`)) {
|
|
11276
|
+
return {
|
|
11277
|
+
ok: false,
|
|
11278
|
+
warnings,
|
|
11279
|
+
activeUser,
|
|
11280
|
+
reason: `GitHub repo "${input.owner}/${input.repoName}" already exists. Pick a different project name, or delete the existing repo first.`
|
|
11281
|
+
};
|
|
11282
|
+
}
|
|
11283
|
+
} catch {
|
|
11284
|
+
warnings.push(
|
|
11285
|
+
`Could not check whether "${input.owner}/${input.repoName}" already exists (probe error); the create will fail clearly if it does.`
|
|
11286
|
+
);
|
|
11287
|
+
}
|
|
11288
|
+
return { ok: true, warnings, activeUser };
|
|
11289
|
+
}
|
|
11171
11290
|
function githubWorkflowScopePrereqMessage(reason) {
|
|
11172
11291
|
return "The GitHub token lacks the `workflow` OAuth scope, required to push the project's `.github/workflows/*` CI files. (Without this check, scaffolding runs all the way to the final push, is rejected, and rolls back.) Grant the scope, then re-run:\n - gh CLI: gh auth refresh -h github.com -s workflow\n - VS Code: re-sign in to GitHub and approve the workflow scope\n - token: set GITHUB_TOKEN to a PAT that includes the `workflow` scope" + (reason ? `
|
|
11173
11292
|
(${reason})` : "");
|
|
@@ -11233,6 +11352,53 @@ async function withLakebaseRollback(opts, fn) {
|
|
|
11233
11352
|
throw wrapped;
|
|
11234
11353
|
}
|
|
11235
11354
|
}
|
|
11355
|
+
function createRollbackLedger() {
|
|
11356
|
+
const steps = [];
|
|
11357
|
+
return {
|
|
11358
|
+
register: (label, undo) => {
|
|
11359
|
+
steps.push({ label, undo });
|
|
11360
|
+
},
|
|
11361
|
+
steps: () => steps
|
|
11362
|
+
};
|
|
11363
|
+
}
|
|
11364
|
+
async function withCreateRollback(ledger, opts, fn) {
|
|
11365
|
+
try {
|
|
11366
|
+
return await fn();
|
|
11367
|
+
} catch (err) {
|
|
11368
|
+
const report = opts.report ?? (() => {
|
|
11369
|
+
});
|
|
11370
|
+
const steps = [...ledger.steps()].reverse();
|
|
11371
|
+
const rolledBack = [];
|
|
11372
|
+
const failed = [];
|
|
11373
|
+
if (steps.length > 0) report(`Create failed; rolling back ${steps.length} created resource(s)...`);
|
|
11374
|
+
for (const s of steps) {
|
|
11375
|
+
try {
|
|
11376
|
+
report(` rolling back: ${s.label}`);
|
|
11377
|
+
await s.undo();
|
|
11378
|
+
rolledBack.push(s.label);
|
|
11379
|
+
} catch (e) {
|
|
11380
|
+
const m = e instanceof Error ? e.message : String(e);
|
|
11381
|
+
if (/not.?found/i.test(m)) {
|
|
11382
|
+
rolledBack.push(s.label);
|
|
11383
|
+
continue;
|
|
11384
|
+
}
|
|
11385
|
+
failed.push(`${s.label} (${m})`);
|
|
11386
|
+
}
|
|
11387
|
+
}
|
|
11388
|
+
const base = err instanceof Error ? err.message : String(err);
|
|
11389
|
+
const parts = [];
|
|
11390
|
+
if (rolledBack.length) parts.push(`rolled back: ${rolledBack.join(", ")}`);
|
|
11391
|
+
if (failed.length) {
|
|
11392
|
+
parts.push(
|
|
11393
|
+
`COULD NOT roll back: ${failed.join("; ")} , clean these up by hand before retrying the same name`
|
|
11394
|
+
);
|
|
11395
|
+
}
|
|
11396
|
+
const suffix = parts.length ? ` (${parts.join("; ")})` : "";
|
|
11397
|
+
const wrapped = err instanceof Error ? err : new Error(base);
|
|
11398
|
+
wrapped.message = `${base}${suffix}`;
|
|
11399
|
+
throw wrapped;
|
|
11400
|
+
}
|
|
11401
|
+
}
|
|
11236
11402
|
|
|
11237
11403
|
// scripts/lakebase/create-project.ts
|
|
11238
11404
|
init_esm_shims();
|
|
@@ -11300,27 +11466,34 @@ To finish:
|
|
|
11300
11466
|
this.name = "WorkflowScopeError";
|
|
11301
11467
|
}
|
|
11302
11468
|
};
|
|
11303
|
-
async function
|
|
11304
|
-
await exec2("git add -A", { cwd:
|
|
11305
|
-
await exec2(`git commit -m ${JSON.stringify(
|
|
11306
|
-
cwd:
|
|
11469
|
+
async function commitInitial(projectDir, message) {
|
|
11470
|
+
await exec2("git add -A", { cwd: projectDir });
|
|
11471
|
+
await exec2(`git commit -m ${JSON.stringify(message)}`, {
|
|
11472
|
+
cwd: projectDir,
|
|
11307
11473
|
timeout: 3e4
|
|
11308
11474
|
});
|
|
11309
|
-
|
|
11475
|
+
}
|
|
11476
|
+
async function pushInitial(args) {
|
|
11310
11477
|
const remote = args.remote ?? "origin";
|
|
11311
11478
|
const branch = args.branch ?? "main";
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
|
|
11320
|
-
|
|
11479
|
+
const attempts = Math.max(1, args.attempts ?? 1);
|
|
11480
|
+
const sleep2 = args.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
11481
|
+
const run = args.run ?? ((cmd, cwd) => exec2(cmd, { cwd, timeout: 3e4 }).then(() => void 0));
|
|
11482
|
+
let lastErr;
|
|
11483
|
+
for (let i = 1; i <= attempts; i++) {
|
|
11484
|
+
try {
|
|
11485
|
+
await run(`git push -u ${remote} ${branch}`, args.projectDir);
|
|
11486
|
+
return;
|
|
11487
|
+
} catch (err) {
|
|
11488
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11489
|
+
if (/without `?workflow`? scope|workflow scope/i.test(msg)) {
|
|
11490
|
+
throw new WorkflowScopeError(args.projectDir);
|
|
11491
|
+
}
|
|
11492
|
+
lastErr = err;
|
|
11493
|
+
if (i < attempts) await sleep2(args.delayMs ?? 1500);
|
|
11321
11494
|
}
|
|
11322
|
-
throw err;
|
|
11323
11495
|
}
|
|
11496
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
11324
11497
|
}
|
|
11325
11498
|
|
|
11326
11499
|
// scripts/lakebase/scaffold.ts
|
|
@@ -13626,64 +13799,72 @@ async function createProject(input, progress) {
|
|
|
13626
13799
|
throw new Error(databricksAuthPrereqMessage(host, auth7.reason));
|
|
13627
13800
|
}
|
|
13628
13801
|
if (useGithub) {
|
|
13629
|
-
report("Checking GitHub token
|
|
13630
|
-
const
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
}
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
probeErr =
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13802
|
+
report("Checking GitHub account + token requisites...");
|
|
13803
|
+
const gh = await checkGitHubPreflight({ owner: input.githubOwner, repoName: input.projectName });
|
|
13804
|
+
for (const w of gh.warnings) {
|
|
13805
|
+
warnings.push(w);
|
|
13806
|
+
report(`Note: ${w}`);
|
|
13807
|
+
}
|
|
13808
|
+
if (!gh.ok) throw new Error(gh.reason);
|
|
13809
|
+
}
|
|
13810
|
+
const rollback = createRollbackLedger();
|
|
13811
|
+
return await withCreateRollback(
|
|
13812
|
+
rollback,
|
|
13813
|
+
{ report },
|
|
13814
|
+
async () => {
|
|
13815
|
+
if (useGithub) {
|
|
13816
|
+
report("Creating GitHub repository...", fullRepoName);
|
|
13817
|
+
await createRepo(fullRepoName, {
|
|
13818
|
+
private: input.privateRepo !== false,
|
|
13819
|
+
description: `Lakebase project: ${input.projectName}`
|
|
13820
|
+
});
|
|
13821
|
+
rollback.register(`GitHub repo ${fullRepoName}`, () => deleteRepo(fullRepoName));
|
|
13822
|
+
report("Waiting for GitHub repo to be visible...", fullRepoName);
|
|
13823
|
+
const probeDelays = [1e3, 2e3, 3e3, 5e3, 8e3];
|
|
13824
|
+
let probeErr = "";
|
|
13825
|
+
let visible = false;
|
|
13826
|
+
for (const waitMs of probeDelays) {
|
|
13827
|
+
try {
|
|
13828
|
+
await getRepoFullName(fullRepoName);
|
|
13829
|
+
visible = true;
|
|
13830
|
+
break;
|
|
13831
|
+
} catch (err) {
|
|
13832
|
+
probeErr = err instanceof Error ? err.message : String(err);
|
|
13833
|
+
await delay(waitMs);
|
|
13834
|
+
}
|
|
13835
|
+
}
|
|
13836
|
+
if (!visible) {
|
|
13837
|
+
let activeUser = "";
|
|
13838
|
+
try {
|
|
13839
|
+
activeUser = await getCurrentUser();
|
|
13840
|
+
} catch {
|
|
13841
|
+
}
|
|
13842
|
+
const samlHint = /SAML|scope does not match|sso/i.test(probeErr) ? "\n\nThe error mentions SAML \u2013 re-sign in to GitHub and authorize SSO for this org." : "";
|
|
13843
|
+
const userHint = activeUser && activeUser !== input.githubOwner ? `
|
|
13663
13844
|
|
|
13664
13845
|
Note: signed in as "${activeUser}", but the repo was created under "${input.githubOwner}".` : "";
|
|
13665
|
-
|
|
13666
|
-
|
|
13846
|
+
throw new Error(
|
|
13847
|
+
`GitHub repo "${fullRepoName}" was created but isn't visible after ~19s of polling.${samlHint}${userHint}
|
|
13667
13848
|
|
|
13668
13849
|
Last probe error:
|
|
13669
13850
|
${probeErr.split("\n")[0].slice(0, 200)}`
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13851
|
+
);
|
|
13852
|
+
}
|
|
13853
|
+
report("Cloning repository...", projectDir);
|
|
13854
|
+
await cloneRepo({
|
|
13855
|
+
repoUrl: `https://github.com/${fullRepoName}.git`,
|
|
13856
|
+
parentDir: input.parentDir
|
|
13857
|
+
});
|
|
13858
|
+
rollback.register(`local project dir ${projectDir}`, () => fs19.rmSync(projectDir, { recursive: true, force: true }));
|
|
13859
|
+
} else {
|
|
13860
|
+
report("Creating local project directory...", projectDir);
|
|
13861
|
+
fs19.mkdirSync(projectDir, { recursive: true });
|
|
13862
|
+
await gitInit(projectDir);
|
|
13863
|
+
rollback.register(`local project dir ${projectDir}`, () => fs19.rmSync(projectDir, { recursive: true, force: true }));
|
|
13864
|
+
}
|
|
13865
|
+
report("Creating Lakebase database (provisioning Postgres)...", lakebaseProjectId);
|
|
13866
|
+
await createLakebaseProject({ projectId: lakebaseProjectId, host });
|
|
13867
|
+
rollback.register(`Lakebase project ${lakebaseProjectId}`, () => deleteLakebaseProject({ projectId: lakebaseProjectId, host }));
|
|
13687
13868
|
report("Resolving database endpoint...");
|
|
13688
13869
|
const defaultBranchId = await getDefaultBranchId({
|
|
13689
13870
|
projectId: lakebaseProjectId,
|
|
@@ -13767,6 +13948,10 @@ Last probe error:
|
|
|
13767
13948
|
projectName: input.projectName,
|
|
13768
13949
|
report: (m) => report(m)
|
|
13769
13950
|
});
|
|
13951
|
+
rollback.register(
|
|
13952
|
+
`self-hosted runner ${input.projectName}`,
|
|
13953
|
+
() => removeRunner({ fullRepoName, projectName: input.projectName })
|
|
13954
|
+
);
|
|
13770
13955
|
} catch (err) {
|
|
13771
13956
|
const msg = err instanceof Error ? err.message : String(err);
|
|
13772
13957
|
warnings.push(`Runner setup failed: ${msg}`);
|
|
@@ -13835,6 +14020,16 @@ Last probe error:
|
|
|
13835
14020
|
"The Consort toolkit downloads on first use , run `./scripts/lk --refresh`, or just your first `./scripts/lk` command, and it installs then."
|
|
13836
14021
|
);
|
|
13837
14022
|
}
|
|
14023
|
+
if (enableSftdd && useGithub) {
|
|
14024
|
+
report("Warming the Consort toolkit (so the first push doesn't cold-download mid-hook)...");
|
|
14025
|
+
let warm = warmAndVerifyKit(projectDir);
|
|
14026
|
+
if (!warm.ok) warm = warmAndVerifyKit(projectDir);
|
|
14027
|
+
if (!warm.ok) {
|
|
14028
|
+
const m = kitWarmWarning(projectDir, warm.reason);
|
|
14029
|
+
warnings.push(m);
|
|
14030
|
+
report(`Note: ${m}`);
|
|
14031
|
+
}
|
|
14032
|
+
}
|
|
13838
14033
|
const langLabels = {
|
|
13839
14034
|
java: "Java/Spring Boot",
|
|
13840
14035
|
kotlin: "Kotlin/Spring Boot",
|
|
@@ -13855,12 +14050,25 @@ Last probe error:
|
|
|
13855
14050
|
}
|
|
13856
14051
|
}
|
|
13857
14052
|
report("Creating initial commit...");
|
|
13858
|
-
await
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
14053
|
+
await commitInitial(projectDir, `Initial project scaffold (${langLabel} + Lakebase)`);
|
|
14054
|
+
let pushLanded = !useGithub;
|
|
14055
|
+
if (useGithub) {
|
|
14056
|
+
try {
|
|
14057
|
+
await pushInitial({ projectDir, attempts: 2 });
|
|
14058
|
+
pushLanded = true;
|
|
14059
|
+
} catch (err) {
|
|
14060
|
+
if (err instanceof WorkflowScopeError) throw err;
|
|
14061
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
14062
|
+
const m = `Provisioning is complete, but the initial push did not land after a retry: ${msg}. The project on disk is fine , finish it with: cd ${projectDir} && git push -u origin main`;
|
|
14063
|
+
warnings.push(m);
|
|
14064
|
+
report(`WARNING: ${m}`);
|
|
14065
|
+
}
|
|
14066
|
+
}
|
|
14067
|
+
if ((tiers === 2 || tiers === 3) && !pushLanded) {
|
|
14068
|
+
const m = `INCOMPLETE TIERS: you requested ${tiers} tiers, but the initial push hasn't landed, so the tier branches can't fork off origin yet. After you finish the push (above), cut them with \`./scripts/lk lakebase-cut-tier --name staging --fork-from main\`${tiers === 3 ? " and `--name dev --fork-from staging`" : ""}.`;
|
|
14069
|
+
warnings.push(m);
|
|
14070
|
+
report(`WARNING: ${m}`);
|
|
14071
|
+
} else if (tiers === 2 || tiers === 3) {
|
|
13864
14072
|
report(`Cutting staging tier (tiers=${tiers}) via createLongRunningBranch...`);
|
|
13865
14073
|
try {
|
|
13866
14074
|
await createLongRunningBranch({
|
|
@@ -13911,7 +14119,7 @@ Last probe error:
|
|
|
13911
14119
|
warnings
|
|
13912
14120
|
};
|
|
13913
14121
|
}
|
|
13914
|
-
// end
|
|
14122
|
+
// end withCreateRollback closure
|
|
13915
14123
|
);
|
|
13916
14124
|
}
|
|
13917
14125
|
|
|
@@ -18709,6 +18917,7 @@ export {
|
|
|
18709
18917
|
catalogExists,
|
|
18710
18918
|
catalogExplorerUrl,
|
|
18711
18919
|
checkDatabricksAuth,
|
|
18920
|
+
checkGitHubPreflight,
|
|
18712
18921
|
checkGitHubWorkflowScope,
|
|
18713
18922
|
checkoutPaired,
|
|
18714
18923
|
claimFeatureBranch,
|
|
@@ -18722,6 +18931,7 @@ export {
|
|
|
18722
18931
|
createPairedBranch,
|
|
18723
18932
|
createPerfPairedBranch,
|
|
18724
18933
|
createProject,
|
|
18934
|
+
createRollbackLedger,
|
|
18725
18935
|
createTestPairedBranch,
|
|
18726
18936
|
createUatPairedBranch,
|
|
18727
18937
|
cutBackup,
|
|
@@ -18891,6 +19101,7 @@ export {
|
|
|
18891
19101
|
waitForBranchReady,
|
|
18892
19102
|
waitForCi,
|
|
18893
19103
|
warmAndVerifyKit,
|
|
19104
|
+
withCreateRollback,
|
|
18894
19105
|
withLakebaseRollback,
|
|
18895
19106
|
workflowStateFileExists,
|
|
18896
19107
|
writeEnvFile,
|
|
@@ -79290,8 +79290,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
|
79290
79290
|
var cached;
|
|
79291
79291
|
function substrateSelfVersion() {
|
|
79292
79292
|
if (cached !== void 0) return cached;
|
|
79293
|
-
if ("0.3.
|
|
79294
|
-
cached = "0.3.
|
|
79293
|
+
if ("0.3.11".length > 0) {
|
|
79294
|
+
cached = "0.3.11";
|
|
79295
79295
|
return cached;
|
|
79296
79296
|
}
|
|
79297
79297
|
cached = "unknown";
|
|
@@ -79338,22 +79338,24 @@ async function getConnection(args) {
|
|
|
79338
79338
|
const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
|
|
79339
79339
|
if (args.output === "dsn") {
|
|
79340
79340
|
const host2 = await resolveEndpointHost(args.instance, branchId);
|
|
79341
|
-
const { token, email: email2 } = await mintCredential(endpointPath2);
|
|
79342
|
-
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password:
|
|
79341
|
+
const { token: token2, email: email2 } = await mintCredential(endpointPath2);
|
|
79342
|
+
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
|
|
79343
79343
|
return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
|
|
79344
79344
|
}
|
|
79345
79345
|
const host = await resolveEndpointHost(args.instance, branchId);
|
|
79346
|
-
const email = await resolveCurrentUser();
|
|
79347
79346
|
process.env.PGAPPNAME = connectionApplicationName();
|
|
79348
|
-
|
|
79349
|
-
|
|
79350
|
-
|
|
79351
|
-
|
|
79352
|
-
|
|
79353
|
-
|
|
79354
|
-
|
|
79355
|
-
|
|
79356
|
-
|
|
79347
|
+
if (args.workspaceClient !== void 0) {
|
|
79348
|
+
const email2 = await resolveCurrentUser();
|
|
79349
|
+
return createLakebasePool({
|
|
79350
|
+
endpoint: endpointPath2,
|
|
79351
|
+
host,
|
|
79352
|
+
database,
|
|
79353
|
+
user: email2,
|
|
79354
|
+
workspaceClient: args.workspaceClient
|
|
79355
|
+
});
|
|
79356
|
+
}
|
|
79357
|
+
const { token, email } = await mintCredential(endpointPath2);
|
|
79358
|
+
return createLakebasePool({ host, database, user: email, password: token });
|
|
79357
79359
|
}
|
|
79358
79360
|
async function resolveEndpointHost(instance, branch) {
|
|
79359
79361
|
const branchId = await resolveBranchId({ instance, branch });
|
|
@@ -393,8 +393,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
|
393
393
|
var cached;
|
|
394
394
|
function substrateSelfVersion() {
|
|
395
395
|
if (cached !== void 0) return cached;
|
|
396
|
-
if ("0.3.
|
|
397
|
-
cached = "0.3.
|
|
396
|
+
if ("0.3.11".length > 0) {
|
|
397
|
+
cached = "0.3.11";
|
|
398
398
|
return cached;
|
|
399
399
|
}
|
|
400
400
|
cached = "unknown";
|
|
@@ -441,22 +441,24 @@ async function getConnection(args) {
|
|
|
441
441
|
const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
|
|
442
442
|
if (args.output === "dsn") {
|
|
443
443
|
const host2 = await resolveEndpointHost(args.instance, branchId);
|
|
444
|
-
const { token, email: email2 } = await mintCredential(endpointPath2);
|
|
445
|
-
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password:
|
|
444
|
+
const { token: token2, email: email2 } = await mintCredential(endpointPath2);
|
|
445
|
+
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
|
|
446
446
|
return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
|
|
447
447
|
}
|
|
448
448
|
const host = await resolveEndpointHost(args.instance, branchId);
|
|
449
|
-
const email = await resolveCurrentUser();
|
|
450
449
|
process.env.PGAPPNAME = connectionApplicationName();
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
450
|
+
if (args.workspaceClient !== void 0) {
|
|
451
|
+
const email2 = await resolveCurrentUser();
|
|
452
|
+
return createLakebasePool({
|
|
453
|
+
endpoint: endpointPath2,
|
|
454
|
+
host,
|
|
455
|
+
database,
|
|
456
|
+
user: email2,
|
|
457
|
+
workspaceClient: args.workspaceClient
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
const { token, email } = await mintCredential(endpointPath2);
|
|
461
|
+
return createLakebasePool({ host, database, user: email, password: token });
|
|
460
462
|
}
|
|
461
463
|
async function resolveEndpointHost(instance, branch) {
|
|
462
464
|
const branchId = await resolveBranchId({ instance, branch });
|