@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
|
@@ -78982,6 +78982,7 @@ __export(lakebase_exports, {
|
|
|
78982
78982
|
catalogExists: () => catalogExists,
|
|
78983
78983
|
catalogExplorerUrl: () => catalogExplorerUrl,
|
|
78984
78984
|
checkDatabricksAuth: () => checkDatabricksAuth,
|
|
78985
|
+
checkGitHubPreflight: () => checkGitHubPreflight,
|
|
78985
78986
|
checkGitHubWorkflowScope: () => checkGitHubWorkflowScope,
|
|
78986
78987
|
checkoutPaired: () => checkoutPaired,
|
|
78987
78988
|
claimFeatureBranch: () => claimFeatureBranch,
|
|
@@ -78995,6 +78996,7 @@ __export(lakebase_exports, {
|
|
|
78995
78996
|
createPairedBranch: () => createPairedBranch,
|
|
78996
78997
|
createPerfPairedBranch: () => createPerfPairedBranch,
|
|
78997
78998
|
createProject: () => createProject,
|
|
78999
|
+
createRollbackLedger: () => createRollbackLedger,
|
|
78998
79000
|
createTestPairedBranch: () => createTestPairedBranch,
|
|
78999
79001
|
createUatPairedBranch: () => createUatPairedBranch,
|
|
79000
79002
|
cutBackup: () => cutBackup,
|
|
@@ -79164,6 +79166,7 @@ __export(lakebase_exports, {
|
|
|
79164
79166
|
waitForBranchReady: () => waitForBranchReady,
|
|
79165
79167
|
waitForCi: () => waitForCi,
|
|
79166
79168
|
warmAndVerifyKit: () => warmAndVerifyKit,
|
|
79169
|
+
withCreateRollback: () => withCreateRollback,
|
|
79167
79170
|
withLakebaseRollback: () => withLakebaseRollback,
|
|
79168
79171
|
workflowStateFileExists: () => workflowStateFileExists,
|
|
79169
79172
|
writeEnvFile: () => writeEnvFile,
|
|
@@ -80008,9 +80011,46 @@ function dbcli2(args, host, timeout = KIT_TIMEOUTS.cliDefault) {
|
|
|
80008
80011
|
}
|
|
80009
80012
|
|
|
80010
80013
|
// scripts/lakebase/branch-create.ts
|
|
80014
|
+
function snapshotPath(instance, snapshot) {
|
|
80015
|
+
return snapshot.includes("/") ? snapshot : `${projectPath(instance)}/snapshots/${snapshot}`;
|
|
80016
|
+
}
|
|
80017
|
+
function applyExpiration(spec, ttl, noExpiry) {
|
|
80018
|
+
if (ttl && noExpiry === true) {
|
|
80019
|
+
throw new LakebaseBranchError(
|
|
80020
|
+
`Cannot set both ttl ("${ttl}") and noExpiry: true on the same branch \u2013 they are mutually exclusive. Pass one or the other.`
|
|
80021
|
+
);
|
|
80022
|
+
}
|
|
80023
|
+
if (ttl) spec.ttl = ttl;
|
|
80024
|
+
else if (noExpiry ?? true) spec.no_expiry = true;
|
|
80025
|
+
}
|
|
80011
80026
|
async function createBranch(args) {
|
|
80012
80027
|
const sanitized = sanitizeBranchName(args.branch);
|
|
80013
80028
|
const lookup = { instance: args.instance, host: args.host };
|
|
80029
|
+
if (args.fromSnapshot) {
|
|
80030
|
+
if (args.parentBranch || args.sourceBranchTime || args.sourceBranchLsn) {
|
|
80031
|
+
throw new LakebaseBranchError(
|
|
80032
|
+
`fromSnapshot is mutually exclusive with parentBranch / sourceBranchTime / sourceBranchLsn (the Lakebase API rejects source_snapshot combined with any source_branch field).`
|
|
80033
|
+
);
|
|
80034
|
+
}
|
|
80035
|
+
const existing2 = await getBranchByName(sanitized, lookup);
|
|
80036
|
+
if (existing2) return existing2;
|
|
80037
|
+
const spec = { source_snapshot: snapshotPath(args.instance, args.fromSnapshot) };
|
|
80038
|
+
applyExpiration(spec, args.ttl, args.noExpiry);
|
|
80039
|
+
try {
|
|
80040
|
+
await createWithTtlRecovery(args.instance, sanitized, spec, args.host);
|
|
80041
|
+
} catch (err) {
|
|
80042
|
+
if (err instanceof LakebaseBranchTtlTooLongError) throw err;
|
|
80043
|
+
const landed = await getBranchByName(sanitized, lookup);
|
|
80044
|
+
if (!landed) throw err;
|
|
80045
|
+
}
|
|
80046
|
+
return waitForBranchReady({
|
|
80047
|
+
instance: args.instance,
|
|
80048
|
+
host: args.host,
|
|
80049
|
+
branch: sanitized,
|
|
80050
|
+
timeoutMs: args.readyTimeoutMs ?? KIT_TIMEOUTS.readyWait,
|
|
80051
|
+
pollIntervalMs: args.pollIntervalMs ?? KIT_TIMEOUTS.readyPoll
|
|
80052
|
+
});
|
|
80053
|
+
}
|
|
80014
80054
|
let sourceBranchPath;
|
|
80015
80055
|
if (args.parentBranch) {
|
|
80016
80056
|
if (looksLikeBranchUid(args.parentBranch)) {
|
|
@@ -80058,19 +80098,15 @@ async function createBranch(args) {
|
|
|
80058
80098
|
assertSourceMatches(existing, sourceBranchPath, sanitized);
|
|
80059
80099
|
return existing;
|
|
80060
80100
|
}
|
|
80061
|
-
if (args.
|
|
80101
|
+
if (args.sourceBranchTime && args.sourceBranchLsn) {
|
|
80062
80102
|
throw new LakebaseBranchError(
|
|
80063
|
-
`
|
|
80103
|
+
`sourceBranchTime and sourceBranchLsn are mutually exclusive \u2013 pass at most one point-in-time.`
|
|
80064
80104
|
);
|
|
80065
80105
|
}
|
|
80066
|
-
const specObj = {
|
|
80067
|
-
|
|
80068
|
-
|
|
80069
|
-
|
|
80070
|
-
specObj.ttl = args.ttl;
|
|
80071
|
-
} else if (args.noExpiry ?? true) {
|
|
80072
|
-
specObj.no_expiry = true;
|
|
80073
|
-
}
|
|
80106
|
+
const specObj = { source_branch: sourceBranchPath };
|
|
80107
|
+
if (args.sourceBranchTime) specObj.source_branch_time = args.sourceBranchTime;
|
|
80108
|
+
else if (args.sourceBranchLsn) specObj.source_branch_lsn = args.sourceBranchLsn;
|
|
80109
|
+
applyExpiration(specObj, args.ttl, args.noExpiry);
|
|
80074
80110
|
try {
|
|
80075
80111
|
await createWithTtlRecovery(args.instance, sanitized, specObj, args.host);
|
|
80076
80112
|
} catch (err) {
|
|
@@ -81607,8 +81643,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
|
81607
81643
|
var cached;
|
|
81608
81644
|
function substrateSelfVersion() {
|
|
81609
81645
|
if (cached !== void 0) return cached;
|
|
81610
|
-
if ("0.3.
|
|
81611
|
-
cached = "0.3.
|
|
81646
|
+
if ("0.3.11".length > 0) {
|
|
81647
|
+
cached = "0.3.11";
|
|
81612
81648
|
return cached;
|
|
81613
81649
|
}
|
|
81614
81650
|
cached = "unknown";
|
|
@@ -81655,22 +81691,24 @@ async function getConnection(args) {
|
|
|
81655
81691
|
const endpointPath2 = `projects/${args.instance}/branches/${branchId}/endpoints/${endpointName}`;
|
|
81656
81692
|
if (args.output === "dsn") {
|
|
81657
81693
|
const host2 = await resolveEndpointHost(args.instance, branchId);
|
|
81658
|
-
const { token, email: email2 } = await mintCredential(endpointPath2);
|
|
81659
|
-
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password:
|
|
81694
|
+
const { token: token2, email: email2 } = await mintCredential(endpointPath2);
|
|
81695
|
+
const url = buildPostgresUrl({ host: host2, port: POSTGRES_PORT, database, user: email2, password: token2 });
|
|
81660
81696
|
return { url, host: host2, port: POSTGRES_PORT, database, user: email2, endpointPath: endpointPath2 };
|
|
81661
81697
|
}
|
|
81662
81698
|
const host = await resolveEndpointHost(args.instance, branchId);
|
|
81663
|
-
const email = await resolveCurrentUser();
|
|
81664
81699
|
process.env.PGAPPNAME = connectionApplicationName();
|
|
81665
|
-
|
|
81666
|
-
|
|
81667
|
-
|
|
81668
|
-
|
|
81669
|
-
|
|
81670
|
-
|
|
81671
|
-
|
|
81672
|
-
|
|
81673
|
-
|
|
81700
|
+
if (args.workspaceClient !== void 0) {
|
|
81701
|
+
const email2 = await resolveCurrentUser();
|
|
81702
|
+
return createLakebasePool({
|
|
81703
|
+
endpoint: endpointPath2,
|
|
81704
|
+
host,
|
|
81705
|
+
database,
|
|
81706
|
+
user: email2,
|
|
81707
|
+
workspaceClient: args.workspaceClient
|
|
81708
|
+
});
|
|
81709
|
+
}
|
|
81710
|
+
const { token, email } = await mintCredential(endpointPath2);
|
|
81711
|
+
return createLakebasePool({ host, database, user: email, password: token });
|
|
81674
81712
|
}
|
|
81675
81713
|
async function resolveEndpointHost(instance, branch) {
|
|
81676
81714
|
const branchId = await resolveBranchId({ instance, branch });
|
|
@@ -90186,6 +90224,26 @@ async function createRepo(name, opts = {}) {
|
|
|
90186
90224
|
wrap2(err, `Failed to create repository "${name}"`);
|
|
90187
90225
|
}
|
|
90188
90226
|
}
|
|
90227
|
+
async function deleteRepo(name) {
|
|
90228
|
+
try {
|
|
90229
|
+
const { owner, repo } = parseOwnerRepo(name);
|
|
90230
|
+
const ctx = await newContext();
|
|
90231
|
+
await ctx.octokit.rest.repos.delete({ owner, repo });
|
|
90232
|
+
} catch (err) {
|
|
90233
|
+
wrap2(err, `Failed to delete repository "${name}"`);
|
|
90234
|
+
}
|
|
90235
|
+
}
|
|
90236
|
+
async function repoExists(name) {
|
|
90237
|
+
try {
|
|
90238
|
+
const { owner, repo } = parseOwnerRepo(name);
|
|
90239
|
+
const ctx = await newContext();
|
|
90240
|
+
await ctx.octokit.rest.repos.get({ owner, repo });
|
|
90241
|
+
return true;
|
|
90242
|
+
} catch (err) {
|
|
90243
|
+
if (err instanceof RequestError && err.status === 404) return false;
|
|
90244
|
+
wrap2(err, `Failed to check repository "${name}"`);
|
|
90245
|
+
}
|
|
90246
|
+
}
|
|
90189
90247
|
async function getActionsEnabled(ownerRepo) {
|
|
90190
90248
|
try {
|
|
90191
90249
|
const { owner, repo } = parseOwnerRepo(ownerRepo);
|
|
@@ -90254,6 +90312,70 @@ async function checkGitHubWorkflowScope(probe = () => checkGitHubScopes(["workfl
|
|
|
90254
90312
|
return { ok: true };
|
|
90255
90313
|
}
|
|
90256
90314
|
}
|
|
90315
|
+
async function checkGitHubPreflight(input) {
|
|
90316
|
+
const warnings = [];
|
|
90317
|
+
const hard = input.hardScopes ?? ["repo", "workflow"];
|
|
90318
|
+
const advisory = input.advisoryScopes ?? ["delete_repo"];
|
|
90319
|
+
const currentUserProbe = input.currentUser ?? getCurrentUser;
|
|
90320
|
+
const scopesProbe = input.scopes ?? ((req) => checkGitHubScopes(req));
|
|
90321
|
+
const repoExistsProbe = input.repoExists ?? repoExists;
|
|
90322
|
+
let activeUser;
|
|
90323
|
+
try {
|
|
90324
|
+
activeUser = await currentUserProbe();
|
|
90325
|
+
} catch (err) {
|
|
90326
|
+
return {
|
|
90327
|
+
ok: false,
|
|
90328
|
+
warnings,
|
|
90329
|
+
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.`
|
|
90330
|
+
};
|
|
90331
|
+
}
|
|
90332
|
+
if (activeUser.toLowerCase() !== input.owner.toLowerCase()) {
|
|
90333
|
+
warnings.push(
|
|
90334
|
+
`Signed in to GitHub as "${activeUser}" but creating under "${input.owner}" (an org or another account); ensure "${activeUser}" can create repositories there.`
|
|
90335
|
+
);
|
|
90336
|
+
}
|
|
90337
|
+
try {
|
|
90338
|
+
const { granted, missing } = await scopesProbe([...hard, ...advisory]);
|
|
90339
|
+
if (granted !== null) {
|
|
90340
|
+
const missingHard = missing.filter((s2) => hard.includes(s2));
|
|
90341
|
+
const missingAdvisory = missing.filter((s2) => advisory.includes(s2));
|
|
90342
|
+
if (missingHard.length > 0) {
|
|
90343
|
+
return {
|
|
90344
|
+
ok: false,
|
|
90345
|
+
warnings,
|
|
90346
|
+
activeUser,
|
|
90347
|
+
reason: `GitHub token missing required scope(s): ${missingHard.join(", ")} (grants [${granted.join(", ") || "none"}]). Fix: gh auth refresh -h github.com -s ${[...hard].join(",")}`
|
|
90348
|
+
};
|
|
90349
|
+
}
|
|
90350
|
+
if (missingAdvisory.length > 0) {
|
|
90351
|
+
warnings.push(
|
|
90352
|
+
`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`
|
|
90353
|
+
);
|
|
90354
|
+
}
|
|
90355
|
+
} else {
|
|
90356
|
+
warnings.push(
|
|
90357
|
+
"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."
|
|
90358
|
+
);
|
|
90359
|
+
}
|
|
90360
|
+
} catch {
|
|
90361
|
+
warnings.push("Could not read GitHub token scopes (probe error); skipping the scope pre-check.");
|
|
90362
|
+
}
|
|
90363
|
+
try {
|
|
90364
|
+
if (await repoExistsProbe(`${input.owner}/${input.repoName}`)) {
|
|
90365
|
+
return {
|
|
90366
|
+
ok: false,
|
|
90367
|
+
warnings,
|
|
90368
|
+
activeUser,
|
|
90369
|
+
reason: `GitHub repo "${input.owner}/${input.repoName}" already exists. Pick a different project name, or delete the existing repo first.`
|
|
90370
|
+
};
|
|
90371
|
+
}
|
|
90372
|
+
} catch {
|
|
90373
|
+
warnings.push(
|
|
90374
|
+
`Could not check whether "${input.owner}/${input.repoName}" already exists (probe error); the create will fail clearly if it does.`
|
|
90375
|
+
);
|
|
90376
|
+
}
|
|
90377
|
+
return { ok: true, warnings, activeUser };
|
|
90378
|
+
}
|
|
90257
90379
|
function githubWorkflowScopePrereqMessage(reason) {
|
|
90258
90380
|
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 ? `
|
|
90259
90381
|
(${reason})` : "");
|
|
@@ -90319,6 +90441,53 @@ async function withLakebaseRollback(opts, fn) {
|
|
|
90319
90441
|
throw wrapped;
|
|
90320
90442
|
}
|
|
90321
90443
|
}
|
|
90444
|
+
function createRollbackLedger() {
|
|
90445
|
+
const steps = [];
|
|
90446
|
+
return {
|
|
90447
|
+
register: (label, undo) => {
|
|
90448
|
+
steps.push({ label, undo });
|
|
90449
|
+
},
|
|
90450
|
+
steps: () => steps
|
|
90451
|
+
};
|
|
90452
|
+
}
|
|
90453
|
+
async function withCreateRollback(ledger, opts, fn) {
|
|
90454
|
+
try {
|
|
90455
|
+
return await fn();
|
|
90456
|
+
} catch (err) {
|
|
90457
|
+
const report = opts.report ?? (() => {
|
|
90458
|
+
});
|
|
90459
|
+
const steps = [...ledger.steps()].reverse();
|
|
90460
|
+
const rolledBack = [];
|
|
90461
|
+
const failed = [];
|
|
90462
|
+
if (steps.length > 0) report(`Create failed; rolling back ${steps.length} created resource(s)...`);
|
|
90463
|
+
for (const s2 of steps) {
|
|
90464
|
+
try {
|
|
90465
|
+
report(` rolling back: ${s2.label}`);
|
|
90466
|
+
await s2.undo();
|
|
90467
|
+
rolledBack.push(s2.label);
|
|
90468
|
+
} catch (e2) {
|
|
90469
|
+
const m2 = e2 instanceof Error ? e2.message : String(e2);
|
|
90470
|
+
if (/not.?found/i.test(m2)) {
|
|
90471
|
+
rolledBack.push(s2.label);
|
|
90472
|
+
continue;
|
|
90473
|
+
}
|
|
90474
|
+
failed.push(`${s2.label} (${m2})`);
|
|
90475
|
+
}
|
|
90476
|
+
}
|
|
90477
|
+
const base = err instanceof Error ? err.message : String(err);
|
|
90478
|
+
const parts = [];
|
|
90479
|
+
if (rolledBack.length) parts.push(`rolled back: ${rolledBack.join(", ")}`);
|
|
90480
|
+
if (failed.length) {
|
|
90481
|
+
parts.push(
|
|
90482
|
+
`COULD NOT roll back: ${failed.join("; ")} , clean these up by hand before retrying the same name`
|
|
90483
|
+
);
|
|
90484
|
+
}
|
|
90485
|
+
const suffix = parts.length ? ` (${parts.join("; ")})` : "";
|
|
90486
|
+
const wrapped = err instanceof Error ? err : new Error(base);
|
|
90487
|
+
wrapped.message = `${base}${suffix}`;
|
|
90488
|
+
throw wrapped;
|
|
90489
|
+
}
|
|
90490
|
+
}
|
|
90322
90491
|
|
|
90323
90492
|
// scripts/lakebase/create-project.ts
|
|
90324
90493
|
init_cjs_shims();
|
|
@@ -90386,27 +90555,34 @@ To finish:
|
|
|
90386
90555
|
this.name = "WorkflowScopeError";
|
|
90387
90556
|
}
|
|
90388
90557
|
};
|
|
90389
|
-
async function
|
|
90390
|
-
await exec2("git add -A", { cwd:
|
|
90391
|
-
await exec2(`git commit -m ${JSON.stringify(
|
|
90392
|
-
cwd:
|
|
90558
|
+
async function commitInitial(projectDir, message) {
|
|
90559
|
+
await exec2("git add -A", { cwd: projectDir });
|
|
90560
|
+
await exec2(`git commit -m ${JSON.stringify(message)}`, {
|
|
90561
|
+
cwd: projectDir,
|
|
90393
90562
|
timeout: 3e4
|
|
90394
90563
|
});
|
|
90395
|
-
|
|
90564
|
+
}
|
|
90565
|
+
async function pushInitial(args) {
|
|
90396
90566
|
const remote = args.remote ?? "origin";
|
|
90397
90567
|
const branch = args.branch ?? "main";
|
|
90398
|
-
|
|
90399
|
-
|
|
90400
|
-
|
|
90401
|
-
|
|
90402
|
-
|
|
90403
|
-
|
|
90404
|
-
|
|
90405
|
-
|
|
90406
|
-
|
|
90568
|
+
const attempts = Math.max(1, args.attempts ?? 1);
|
|
90569
|
+
const sleep2 = args.sleep ?? ((ms) => new Promise((r2) => setTimeout(r2, ms)));
|
|
90570
|
+
const run = args.run ?? ((cmd, cwd) => exec2(cmd, { cwd, timeout: 3e4 }).then(() => void 0));
|
|
90571
|
+
let lastErr;
|
|
90572
|
+
for (let i2 = 1; i2 <= attempts; i2++) {
|
|
90573
|
+
try {
|
|
90574
|
+
await run(`git push -u ${remote} ${branch}`, args.projectDir);
|
|
90575
|
+
return;
|
|
90576
|
+
} catch (err) {
|
|
90577
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
90578
|
+
if (/without `?workflow`? scope|workflow scope/i.test(msg)) {
|
|
90579
|
+
throw new WorkflowScopeError(args.projectDir);
|
|
90580
|
+
}
|
|
90581
|
+
lastErr = err;
|
|
90582
|
+
if (i2 < attempts) await sleep2(args.delayMs ?? 1500);
|
|
90407
90583
|
}
|
|
90408
|
-
throw err;
|
|
90409
90584
|
}
|
|
90585
|
+
throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
|
|
90410
90586
|
}
|
|
90411
90587
|
|
|
90412
90588
|
// scripts/lakebase/scaffold.ts
|
|
@@ -92712,64 +92888,72 @@ async function createProject(input, progress) {
|
|
|
92712
92888
|
throw new Error(databricksAuthPrereqMessage(host, auth7.reason));
|
|
92713
92889
|
}
|
|
92714
92890
|
if (useGithub) {
|
|
92715
|
-
report("Checking GitHub token
|
|
92716
|
-
const
|
|
92717
|
-
|
|
92718
|
-
|
|
92719
|
-
|
|
92720
|
-
|
|
92721
|
-
|
|
92722
|
-
|
|
92723
|
-
|
|
92724
|
-
|
|
92725
|
-
|
|
92726
|
-
}
|
|
92727
|
-
|
|
92728
|
-
|
|
92729
|
-
|
|
92730
|
-
|
|
92731
|
-
|
|
92732
|
-
|
|
92733
|
-
|
|
92734
|
-
|
|
92735
|
-
|
|
92736
|
-
|
|
92737
|
-
probeErr =
|
|
92738
|
-
|
|
92739
|
-
|
|
92740
|
-
|
|
92741
|
-
|
|
92742
|
-
|
|
92743
|
-
|
|
92744
|
-
|
|
92745
|
-
|
|
92746
|
-
|
|
92747
|
-
|
|
92748
|
-
|
|
92891
|
+
report("Checking GitHub account + token requisites...");
|
|
92892
|
+
const gh = await checkGitHubPreflight({ owner: input.githubOwner, repoName: input.projectName });
|
|
92893
|
+
for (const w of gh.warnings) {
|
|
92894
|
+
warnings.push(w);
|
|
92895
|
+
report(`Note: ${w}`);
|
|
92896
|
+
}
|
|
92897
|
+
if (!gh.ok) throw new Error(gh.reason);
|
|
92898
|
+
}
|
|
92899
|
+
const rollback = createRollbackLedger();
|
|
92900
|
+
return await withCreateRollback(
|
|
92901
|
+
rollback,
|
|
92902
|
+
{ report },
|
|
92903
|
+
async () => {
|
|
92904
|
+
if (useGithub) {
|
|
92905
|
+
report("Creating GitHub repository...", fullRepoName);
|
|
92906
|
+
await createRepo(fullRepoName, {
|
|
92907
|
+
private: input.privateRepo !== false,
|
|
92908
|
+
description: `Lakebase project: ${input.projectName}`
|
|
92909
|
+
});
|
|
92910
|
+
rollback.register(`GitHub repo ${fullRepoName}`, () => deleteRepo(fullRepoName));
|
|
92911
|
+
report("Waiting for GitHub repo to be visible...", fullRepoName);
|
|
92912
|
+
const probeDelays = [1e3, 2e3, 3e3, 5e3, 8e3];
|
|
92913
|
+
let probeErr = "";
|
|
92914
|
+
let visible = false;
|
|
92915
|
+
for (const waitMs of probeDelays) {
|
|
92916
|
+
try {
|
|
92917
|
+
await getRepoFullName(fullRepoName);
|
|
92918
|
+
visible = true;
|
|
92919
|
+
break;
|
|
92920
|
+
} catch (err) {
|
|
92921
|
+
probeErr = err instanceof Error ? err.message : String(err);
|
|
92922
|
+
await delay(waitMs);
|
|
92923
|
+
}
|
|
92924
|
+
}
|
|
92925
|
+
if (!visible) {
|
|
92926
|
+
let activeUser = "";
|
|
92927
|
+
try {
|
|
92928
|
+
activeUser = await getCurrentUser();
|
|
92929
|
+
} catch {
|
|
92930
|
+
}
|
|
92931
|
+
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." : "";
|
|
92932
|
+
const userHint = activeUser && activeUser !== input.githubOwner ? `
|
|
92749
92933
|
|
|
92750
92934
|
Note: signed in as "${activeUser}", but the repo was created under "${input.githubOwner}".` : "";
|
|
92751
|
-
|
|
92752
|
-
|
|
92935
|
+
throw new Error(
|
|
92936
|
+
`GitHub repo "${fullRepoName}" was created but isn't visible after ~19s of polling.${samlHint}${userHint}
|
|
92753
92937
|
|
|
92754
92938
|
Last probe error:
|
|
92755
92939
|
${probeErr.split("\n")[0].slice(0, 200)}`
|
|
92756
|
-
|
|
92757
|
-
|
|
92758
|
-
|
|
92759
|
-
|
|
92760
|
-
|
|
92761
|
-
|
|
92762
|
-
|
|
92763
|
-
|
|
92764
|
-
|
|
92765
|
-
|
|
92766
|
-
|
|
92767
|
-
|
|
92768
|
-
|
|
92769
|
-
|
|
92770
|
-
|
|
92771
|
-
|
|
92772
|
-
|
|
92940
|
+
);
|
|
92941
|
+
}
|
|
92942
|
+
report("Cloning repository...", projectDir);
|
|
92943
|
+
await cloneRepo({
|
|
92944
|
+
repoUrl: `https://github.com/${fullRepoName}.git`,
|
|
92945
|
+
parentDir: input.parentDir
|
|
92946
|
+
});
|
|
92947
|
+
rollback.register(`local project dir ${projectDir}`, () => fs20.rmSync(projectDir, { recursive: true, force: true }));
|
|
92948
|
+
} else {
|
|
92949
|
+
report("Creating local project directory...", projectDir);
|
|
92950
|
+
fs20.mkdirSync(projectDir, { recursive: true });
|
|
92951
|
+
await gitInit(projectDir);
|
|
92952
|
+
rollback.register(`local project dir ${projectDir}`, () => fs20.rmSync(projectDir, { recursive: true, force: true }));
|
|
92953
|
+
}
|
|
92954
|
+
report("Creating Lakebase database (provisioning Postgres)...", lakebaseProjectId);
|
|
92955
|
+
await createLakebaseProject({ projectId: lakebaseProjectId, host });
|
|
92956
|
+
rollback.register(`Lakebase project ${lakebaseProjectId}`, () => deleteLakebaseProject({ projectId: lakebaseProjectId, host }));
|
|
92773
92957
|
report("Resolving database endpoint...");
|
|
92774
92958
|
const defaultBranchId = await getDefaultBranchId({
|
|
92775
92959
|
projectId: lakebaseProjectId,
|
|
@@ -92853,6 +93037,10 @@ Last probe error:
|
|
|
92853
93037
|
projectName: input.projectName,
|
|
92854
93038
|
report: (m2) => report(m2)
|
|
92855
93039
|
});
|
|
93040
|
+
rollback.register(
|
|
93041
|
+
`self-hosted runner ${input.projectName}`,
|
|
93042
|
+
() => removeRunner({ fullRepoName, projectName: input.projectName })
|
|
93043
|
+
);
|
|
92856
93044
|
} catch (err) {
|
|
92857
93045
|
const msg = err instanceof Error ? err.message : String(err);
|
|
92858
93046
|
warnings.push(`Runner setup failed: ${msg}`);
|
|
@@ -92921,6 +93109,16 @@ Last probe error:
|
|
|
92921
93109
|
"The Consort toolkit downloads on first use , run `./scripts/lk --refresh`, or just your first `./scripts/lk` command, and it installs then."
|
|
92922
93110
|
);
|
|
92923
93111
|
}
|
|
93112
|
+
if (enableSftdd && useGithub) {
|
|
93113
|
+
report("Warming the Consort toolkit (so the first push doesn't cold-download mid-hook)...");
|
|
93114
|
+
let warm = warmAndVerifyKit(projectDir);
|
|
93115
|
+
if (!warm.ok) warm = warmAndVerifyKit(projectDir);
|
|
93116
|
+
if (!warm.ok) {
|
|
93117
|
+
const m2 = kitWarmWarning(projectDir, warm.reason);
|
|
93118
|
+
warnings.push(m2);
|
|
93119
|
+
report(`Note: ${m2}`);
|
|
93120
|
+
}
|
|
93121
|
+
}
|
|
92924
93122
|
const langLabels = {
|
|
92925
93123
|
java: "Java/Spring Boot",
|
|
92926
93124
|
kotlin: "Kotlin/Spring Boot",
|
|
@@ -92941,12 +93139,25 @@ Last probe error:
|
|
|
92941
93139
|
}
|
|
92942
93140
|
}
|
|
92943
93141
|
report("Creating initial commit...");
|
|
92944
|
-
await
|
|
92945
|
-
|
|
92946
|
-
|
|
92947
|
-
|
|
92948
|
-
|
|
92949
|
-
|
|
93142
|
+
await commitInitial(projectDir, `Initial project scaffold (${langLabel} + Lakebase)`);
|
|
93143
|
+
let pushLanded = !useGithub;
|
|
93144
|
+
if (useGithub) {
|
|
93145
|
+
try {
|
|
93146
|
+
await pushInitial({ projectDir, attempts: 2 });
|
|
93147
|
+
pushLanded = true;
|
|
93148
|
+
} catch (err) {
|
|
93149
|
+
if (err instanceof WorkflowScopeError) throw err;
|
|
93150
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
93151
|
+
const m2 = `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`;
|
|
93152
|
+
warnings.push(m2);
|
|
93153
|
+
report(`WARNING: ${m2}`);
|
|
93154
|
+
}
|
|
93155
|
+
}
|
|
93156
|
+
if ((tiers === 2 || tiers === 3) && !pushLanded) {
|
|
93157
|
+
const m2 = `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`" : ""}.`;
|
|
93158
|
+
warnings.push(m2);
|
|
93159
|
+
report(`WARNING: ${m2}`);
|
|
93160
|
+
} else if (tiers === 2 || tiers === 3) {
|
|
92950
93161
|
report(`Cutting staging tier (tiers=${tiers}) via createLongRunningBranch...`);
|
|
92951
93162
|
try {
|
|
92952
93163
|
await createLongRunningBranch({
|
|
@@ -92997,7 +93208,7 @@ Last probe error:
|
|
|
92997
93208
|
warnings
|
|
92998
93209
|
};
|
|
92999
93210
|
}
|
|
93000
|
-
// end
|
|
93211
|
+
// end withCreateRollback closure
|
|
93001
93212
|
);
|
|
93002
93213
|
}
|
|
93003
93214
|
|
|
@@ -97796,6 +98007,7 @@ function isUcMissingError(msg) {
|
|
|
97796
98007
|
catalogExists,
|
|
97797
98008
|
catalogExplorerUrl,
|
|
97798
98009
|
checkDatabricksAuth,
|
|
98010
|
+
checkGitHubPreflight,
|
|
97799
98011
|
checkGitHubWorkflowScope,
|
|
97800
98012
|
checkoutPaired,
|
|
97801
98013
|
claimFeatureBranch,
|
|
@@ -97809,6 +98021,7 @@ function isUcMissingError(msg) {
|
|
|
97809
98021
|
createPairedBranch,
|
|
97810
98022
|
createPerfPairedBranch,
|
|
97811
98023
|
createProject,
|
|
98024
|
+
createRollbackLedger,
|
|
97812
98025
|
createTestPairedBranch,
|
|
97813
98026
|
createUatPairedBranch,
|
|
97814
98027
|
cutBackup,
|
|
@@ -97978,6 +98191,7 @@ function isUcMissingError(msg) {
|
|
|
97978
98191
|
waitForBranchReady,
|
|
97979
98192
|
waitForCi,
|
|
97980
98193
|
warmAndVerifyKit,
|
|
98194
|
+
withCreateRollback,
|
|
97981
98195
|
withLakebaseRollback,
|
|
97982
98196
|
workflowStateFileExists,
|
|
97983
98197
|
writeEnvFile,
|