@databricks-solutions/lakebase-scm-utils 0.2.44 → 0.2.45

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.
Files changed (39) hide show
  1. package/dist/scripts/index.cjs +795 -758
  2. package/dist/scripts/index.d.cts +1 -1
  3. package/dist/scripts/index.d.ts +1 -1
  4. package/dist/scripts/index.js +794 -758
  5. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
  6. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
  7. package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
  8. package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
  9. package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
  10. package/dist/scripts/lakebase/detect-language.cli.js +2 -2
  11. package/dist/scripts/lakebase/doctor.cli.cjs +3 -3
  12. package/dist/scripts/lakebase/doctor.cli.js +3 -3
  13. package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
  14. package/dist/scripts/lakebase/get-connection.cli.js +2 -2
  15. package/dist/scripts/lakebase/index.cjs +463 -395
  16. package/dist/scripts/lakebase/index.d.cts +33 -1
  17. package/dist/scripts/lakebase/index.d.ts +33 -1
  18. package/dist/scripts/lakebase/index.js +462 -395
  19. package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
  20. package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
  21. package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
  22. package/dist/scripts/lakebase/new-migration.cli.js +2 -2
  23. package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
  24. package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
  25. package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
  26. package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
  27. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
  28. package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
  29. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
  30. package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
  31. package/dist/scripts/lakebase/scm-merge.cli.cjs +2284 -2033
  32. package/dist/scripts/lakebase/scm-merge.cli.js +339 -88
  33. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
  34. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
  35. package/dist/scripts/util/index.cjs +2 -2
  36. package/dist/scripts/util/index.js +2 -2
  37. package/package.json +1 -1
  38. package/scripts/lakebase/doctor.ts +1 -1
  39. package/scripts/lakebase/scm-merge.ts +80 -1
@@ -1457,7 +1457,7 @@ var require_light = __commonJS({
1457
1457
 
1458
1458
  // scripts/lakebase/scm-merge.cli.ts
1459
1459
  init_esm_shims();
1460
- import * as path12 from "path";
1460
+ import * as path13 from "path";
1461
1461
 
1462
1462
  // scripts/util/cli-entry.ts
1463
1463
  init_esm_shims();
@@ -2549,7 +2549,7 @@ paginateRest.VERSION = VERSION5;
2549
2549
 
2550
2550
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
2551
2551
  init_esm_shims();
2552
- var generateMessage = (path13, cursorValue) => `The cursor at "${path13.join(
2552
+ var generateMessage = (path14, cursorValue) => `The cursor at "${path14.join(
2553
2553
  ","
2554
2554
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
2555
2555
  var MissingCursorChange = class extends Error {
@@ -2590,9 +2590,9 @@ function findPaginatedResourcePath(responseData) {
2590
2590
  }
2591
2591
  return paginatedResourcePath;
2592
2592
  }
2593
- var deepFindPathToProperty = (object, searchProp, path13 = []) => {
2593
+ var deepFindPathToProperty = (object, searchProp, path14 = []) => {
2594
2594
  for (const key of Object.keys(object)) {
2595
- const currentPath = [...path13, key];
2595
+ const currentPath = [...path14, key];
2596
2596
  const currentValue = object[key];
2597
2597
  if (isObject(currentValue)) {
2598
2598
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -2610,12 +2610,12 @@ var deepFindPathToProperty = (object, searchProp, path13 = []) => {
2610
2610
  }
2611
2611
  return [];
2612
2612
  };
2613
- var get = (object, path13) => {
2614
- return path13.reduce((current, nextProperty) => current[nextProperty], object);
2613
+ var get = (object, path14) => {
2614
+ return path14.reduce((current, nextProperty) => current[nextProperty], object);
2615
2615
  };
2616
- var set = (object, path13, mutator) => {
2617
- const lastProperty = path13[path13.length - 1];
2618
- const parentPath = [...path13].slice(0, -1);
2616
+ var set = (object, path14, mutator) => {
2617
+ const lastProperty = path14[path14.length - 1];
2618
+ const parentPath = [...path14].slice(0, -1);
2619
2619
  const parent = get(object, parentPath);
2620
2620
  if (typeof mutator === "function") {
2621
2621
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -2667,22 +2667,22 @@ var mergeResponses = (response1, response2) => {
2667
2667
  if (Object.keys(response1).length === 0) {
2668
2668
  return Object.assign(response1, response2);
2669
2669
  }
2670
- const path13 = findPaginatedResourcePath(response1);
2671
- const nodesPath = [...path13, "nodes"];
2670
+ const path14 = findPaginatedResourcePath(response1);
2671
+ const nodesPath = [...path14, "nodes"];
2672
2672
  const newNodes = get(response2, nodesPath);
2673
2673
  if (newNodes) {
2674
2674
  set(response1, nodesPath, (values) => {
2675
2675
  return [...values, ...newNodes];
2676
2676
  });
2677
2677
  }
2678
- const edgesPath = [...path13, "edges"];
2678
+ const edgesPath = [...path14, "edges"];
2679
2679
  const newEdges = get(response2, edgesPath);
2680
2680
  if (newEdges) {
2681
2681
  set(response1, edgesPath, (values) => {
2682
2682
  return [...values, ...newEdges];
2683
2683
  });
2684
2684
  }
2685
- const pageInfoPath = [...path13, "pageInfo"];
2685
+ const pageInfoPath = [...path14, "pageInfo"];
2686
2686
  set(response1, pageInfoPath, get(response2, pageInfoPath));
2687
2687
  return response1;
2688
2688
  };
@@ -5103,7 +5103,7 @@ var triggers_notification_paths_default = [
5103
5103
  ];
5104
5104
  function routeMatcher(paths) {
5105
5105
  const regexes = paths.map(
5106
- (path13) => path13.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5106
+ (path14) => path14.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5107
5107
  );
5108
5108
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
5109
5109
  return new RegExp(regex2, "i");
@@ -8378,9 +8378,9 @@ function asBranchUid(s) {
8378
8378
  }
8379
8379
  return s;
8380
8380
  }
8381
- function branchNameFromResourcePath(path13) {
8382
- if (!path13.includes("/branches/")) return null;
8383
- const leaf = path13.split("/branches/").pop();
8381
+ function branchNameFromResourcePath(path14) {
8382
+ if (!path14.includes("/branches/")) return null;
8383
+ const leaf = path14.split("/branches/").pop();
8384
8384
  if (!leaf) return null;
8385
8385
  try {
8386
8386
  return asBranchName(leaf);
@@ -8785,6 +8785,42 @@ async function pollUntil(args) {
8785
8785
  }
8786
8786
  }
8787
8787
 
8788
+ // scripts/git/sync.ts
8789
+ init_esm_shims();
8790
+
8791
+ // scripts/git/status.ts
8792
+ init_esm_shims();
8793
+ async function hasUpstream(args) {
8794
+ try {
8795
+ await exec2("git rev-parse --abbrev-ref @{u}", { cwd: args.cwd });
8796
+ return true;
8797
+ } catch {
8798
+ return false;
8799
+ }
8800
+ }
8801
+
8802
+ // scripts/git/sync.ts
8803
+ async function currentBranchName(cwd) {
8804
+ try {
8805
+ return await exec2("git rev-parse --abbrev-ref HEAD", { cwd });
8806
+ } catch {
8807
+ return "";
8808
+ }
8809
+ }
8810
+ async function pushCurrentBranchForPr(args) {
8811
+ const remote = args.remote ?? "origin";
8812
+ const branch = await currentBranchName(args.cwd);
8813
+ if (!branch) throw new Error("No current branch");
8814
+ const upstreamSet = await hasUpstream({ cwd: args.cwd });
8815
+ if (!upstreamSet) {
8816
+ await exec2(`git push -u ${remote} ${shq(branch)}`, {
8817
+ cwd: args.cwd
8818
+ });
8819
+ } else {
8820
+ await exec2("git push", { cwd: args.cwd });
8821
+ }
8822
+ }
8823
+
8788
8824
  // scripts/lakebase/scm-git-base.ts
8789
8825
  init_esm_shims();
8790
8826
  async function resolveGitBase(parentBranch, cwd) {
@@ -8794,10 +8830,190 @@ async function resolveGitBase(parentBranch, cwd) {
8794
8830
  return resolveDefaultBranch({ cwd });
8795
8831
  }
8796
8832
 
8797
- // scripts/lakebase/scm-workflow-state.ts
8833
+ // scripts/lakebase/workflow-drift.ts
8798
8834
  init_esm_shims();
8799
8835
  import * as fs3 from "fs";
8800
8836
  import * as path3 from "path";
8837
+ function findKitTemplatesDir(start) {
8838
+ let dir = start;
8839
+ for (let i = 0; i < 6; i++) {
8840
+ const candidate = path3.join(
8841
+ dir,
8842
+ "templates",
8843
+ "project",
8844
+ "common",
8845
+ ".github",
8846
+ "workflows"
8847
+ );
8848
+ if (fs3.existsSync(candidate)) return candidate;
8849
+ const parent = path3.dirname(dir);
8850
+ if (parent === dir) break;
8851
+ dir = parent;
8852
+ }
8853
+ throw new Error(
8854
+ `Could not locate templates/project/common/.github/workflows/ relative to ${start}. Pass explicit kitDir.`
8855
+ );
8856
+ }
8857
+ function unifiedDiff(name, projectContent, templateContent) {
8858
+ if (projectContent === templateContent) return "";
8859
+ const a = projectContent.split("\n");
8860
+ const b = templateContent.split("\n");
8861
+ const out = [`--- project/${name}`, `+++ template/${name}`];
8862
+ const max = Math.max(a.length, b.length);
8863
+ for (let i = 0; i < max; i++) {
8864
+ const av = a[i];
8865
+ const bv = b[i];
8866
+ if (av === bv) continue;
8867
+ if (av !== void 0) out.push(`-${i + 1}: ${av}`);
8868
+ if (bv !== void 0) out.push(`+${i + 1}: ${bv}`);
8869
+ }
8870
+ return out.join("\n");
8871
+ }
8872
+ function detectWorkflowDrift(args) {
8873
+ const projectWorkflowsDir = path3.join(
8874
+ args.projectDir,
8875
+ ".github",
8876
+ "workflows"
8877
+ );
8878
+ const here = path3.dirname(new URL(import.meta.url).pathname);
8879
+ const kitWorkflowsDir = args.kitDir ? path3.join(
8880
+ args.kitDir,
8881
+ "templates",
8882
+ "project",
8883
+ "common",
8884
+ ".github",
8885
+ "workflows"
8886
+ ) : findKitTemplatesDir(here);
8887
+ const templateFiles = fs3.existsSync(kitWorkflowsDir) ? fs3.readdirSync(kitWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
8888
+ const projectFiles = fs3.existsSync(projectWorkflowsDir) ? fs3.readdirSync(projectWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
8889
+ const version = readKitVersion(kitWorkflowsDir);
8890
+ const seen = /* @__PURE__ */ new Set();
8891
+ const files = [];
8892
+ for (const name of templateFiles) {
8893
+ seen.add(name);
8894
+ const projectPath2 = path3.join(projectWorkflowsDir, name);
8895
+ const templatePath = path3.join(kitWorkflowsDir, name);
8896
+ if (!fs3.existsSync(projectPath2)) {
8897
+ files.push({ name, status: "missing" });
8898
+ continue;
8899
+ }
8900
+ const projectContent = fs3.readFileSync(projectPath2, "utf8");
8901
+ const templateContent = applyPlaceholders(fs3.readFileSync(templatePath, "utf8"), version);
8902
+ if (projectContent === templateContent) {
8903
+ files.push({ name, status: "unchanged" });
8904
+ } else {
8905
+ files.push({
8906
+ name,
8907
+ status: "drifted",
8908
+ diff: unifiedDiff(name, projectContent, templateContent)
8909
+ });
8910
+ }
8911
+ }
8912
+ for (const name of projectFiles) {
8913
+ if (seen.has(name)) continue;
8914
+ files.push({ name, status: "extra" });
8915
+ }
8916
+ const order = {
8917
+ drifted: 0,
8918
+ missing: 1,
8919
+ extra: 2,
8920
+ unchanged: 3
8921
+ };
8922
+ files.sort((a, b) => order[a.status] - order[b.status] || a.name.localeCompare(b.name));
8923
+ const hasDrift = files.some((f) => f.status === "drifted" || f.status === "missing");
8924
+ return {
8925
+ overall: hasDrift ? "drift" : "ok",
8926
+ files
8927
+ };
8928
+ }
8929
+ function readKitVersion(kitWorkflowsDir) {
8930
+ let dir = kitWorkflowsDir;
8931
+ for (let i = 0; i < 5; i++) {
8932
+ dir = path3.dirname(dir);
8933
+ }
8934
+ try {
8935
+ const raw = fs3.readFileSync(path3.join(dir, "package.json"), "utf-8");
8936
+ const pkg = JSON.parse(raw);
8937
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
8938
+ } catch {
8939
+ return "unknown";
8940
+ }
8941
+ }
8942
+ function applyPlaceholders(content, version) {
8943
+ return content.replace(/\{\{LAKEBASE_SCM_UTILS_VERSION\}\}/g, version);
8944
+ }
8945
+ function updateWorkflows(args) {
8946
+ const projectWorkflowsDir = path3.join(
8947
+ args.projectDir,
8948
+ ".github",
8949
+ "workflows"
8950
+ );
8951
+ const here = path3.dirname(new URL(import.meta.url).pathname);
8952
+ const kitWorkflowsDir = args.kitDir ? path3.join(
8953
+ args.kitDir,
8954
+ "templates",
8955
+ "project",
8956
+ "common",
8957
+ ".github",
8958
+ "workflows"
8959
+ ) : findKitTemplatesDir(here);
8960
+ const substitute = args.substitute !== false;
8961
+ const dryRun = args.dryRun === true;
8962
+ const pruneExtras = args.pruneExtras === true;
8963
+ const templateFiles = fs3.existsSync(kitWorkflowsDir) ? fs3.readdirSync(kitWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
8964
+ const projectFiles = fs3.existsSync(projectWorkflowsDir) ? fs3.readdirSync(projectWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
8965
+ if (!dryRun && templateFiles.length > 0 && !fs3.existsSync(projectWorkflowsDir)) {
8966
+ fs3.mkdirSync(projectWorkflowsDir, { recursive: true });
8967
+ }
8968
+ const version = substitute ? readKitVersion(kitWorkflowsDir) : "";
8969
+ const seen = /* @__PURE__ */ new Set();
8970
+ const files = [];
8971
+ for (const name of templateFiles) {
8972
+ seen.add(name);
8973
+ const projectPath2 = path3.join(projectWorkflowsDir, name);
8974
+ const templatePath = path3.join(kitWorkflowsDir, name);
8975
+ const templateRaw = fs3.readFileSync(templatePath, "utf-8");
8976
+ const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
8977
+ const existed = fs3.existsSync(projectPath2);
8978
+ const current = existed ? fs3.readFileSync(projectPath2, "utf-8") : "";
8979
+ let outcome;
8980
+ if (!existed) {
8981
+ outcome = "added";
8982
+ } else if (current === desired) {
8983
+ outcome = "unchanged";
8984
+ } else {
8985
+ outcome = "updated";
8986
+ }
8987
+ if (!dryRun && outcome !== "unchanged") {
8988
+ fs3.writeFileSync(projectPath2, desired);
8989
+ }
8990
+ files.push({ name, outcome });
8991
+ }
8992
+ if (pruneExtras) {
8993
+ for (const name of projectFiles) {
8994
+ if (seen.has(name)) continue;
8995
+ const projectPath2 = path3.join(projectWorkflowsDir, name);
8996
+ if (!dryRun) {
8997
+ fs3.unlinkSync(projectPath2);
8998
+ }
8999
+ files.push({ name, outcome: "removed" });
9000
+ }
9001
+ }
9002
+ const order = {
9003
+ added: 0,
9004
+ updated: 1,
9005
+ removed: 2,
9006
+ unchanged: 3
9007
+ };
9008
+ files.sort((a, b) => order[a.outcome] - order[b.outcome] || a.name.localeCompare(b.name));
9009
+ const changed = files.some((f) => f.outcome !== "unchanged");
9010
+ return { files, changed };
9011
+ }
9012
+
9013
+ // scripts/lakebase/scm-workflow-state.ts
9014
+ init_esm_shims();
9015
+ import * as fs4 from "fs";
9016
+ import * as path4 from "path";
8801
9017
  import { execFileSync as execFileSync4 } from "child_process";
8802
9018
  function isGitTracked(projectDir, rel) {
8803
9019
  try {
@@ -8816,11 +9032,11 @@ function ensureWorkflowStateUntracked(projectDir) {
8816
9032
  } catch {
8817
9033
  }
8818
9034
  try {
8819
- const gitignore = path3.join(projectDir, ".gitignore");
8820
- const existing = fs3.existsSync(gitignore) ? fs3.readFileSync(gitignore, "utf8") : "";
9035
+ const gitignore = path4.join(projectDir, ".gitignore");
9036
+ const existing = fs4.existsSync(gitignore) ? fs4.readFileSync(gitignore, "utf8") : "";
8821
9037
  if (!existing.split("\n").some((l) => l.trim() === rel)) {
8822
9038
  const sep2 = existing === "" || existing.endsWith("\n") ? "" : "\n";
8823
- fs3.appendFileSync(
9039
+ fs4.appendFileSync(
8824
9040
  gitignore,
8825
9041
  `${sep2}# Runtime SCM claim state (per working tree): a branch checkout must never restore
8826
9042
  # a stale committed claim over the live one (issue #203 / Finding 28).
@@ -8844,12 +9060,12 @@ var STATE_INDEX = SCM_STATES.reduce(
8844
9060
  );
8845
9061
  var STATE_FILE_REL = ".lakebase/workflow-state.json";
8846
9062
  function stateFilePath(projectDir) {
8847
- return path3.join(projectDir, STATE_FILE_REL);
9063
+ return path4.join(projectDir, STATE_FILE_REL);
8848
9064
  }
8849
9065
  function readWorkflowState(projectDir) {
8850
9066
  const p = stateFilePath(projectDir);
8851
- if (!fs3.existsSync(p)) return null;
8852
- const raw = fs3.readFileSync(p, "utf8");
9067
+ if (!fs4.existsSync(p)) return null;
9068
+ const raw = fs4.readFileSync(p, "utf8");
8853
9069
  let parsed;
8854
9070
  try {
8855
9071
  parsed = JSON.parse(raw);
@@ -8878,14 +9094,14 @@ function writeWorkflowState(projectDir, state) {
8878
9094
  ${summary}`);
8879
9095
  }
8880
9096
  ensureWorkflowStateUntracked(projectDir);
8881
- const dir = path3.join(projectDir, ".lakebase");
8882
- fs3.mkdirSync(dir, { recursive: true });
9097
+ const dir = path4.join(projectDir, ".lakebase");
9098
+ fs4.mkdirSync(dir, { recursive: true });
8883
9099
  const target = stateFilePath(projectDir);
8884
9100
  const tmp = `${target}.tmp`;
8885
9101
  const ordered = orderForOutput(result.value);
8886
- fs3.writeFileSync(tmp, `${JSON.stringify(ordered, null, 2)}
9102
+ fs4.writeFileSync(tmp, `${JSON.stringify(ordered, null, 2)}
8887
9103
  `, "utf8");
8888
- fs3.renameSync(tmp, target);
9104
+ fs4.renameSync(tmp, target);
8889
9105
  }
8890
9106
  function validateWorkflowState(value) {
8891
9107
  const errors = [];
@@ -9087,6 +9303,27 @@ function shaMigratePredicate(mergeCommitSha) {
9087
9303
  return !!run.headSha && run.headSha === mergeCommitSha;
9088
9304
  };
9089
9305
  }
9306
+ async function defaultRefreshPromoteWorkflows(projectDir) {
9307
+ const drift = detectWorkflowDrift({ projectDir });
9308
+ const touched = drift.files.filter((f) => f.status === "drifted").map((f) => f.name);
9309
+ if (touched.length === 0) return { refreshed: false };
9310
+ const result = updateWorkflows({ projectDir });
9311
+ if (!result.changed) return { refreshed: false };
9312
+ await exec2(`git add ${shellEscape(".github/workflows")}`, { cwd: projectDir, timeout: 1e4 });
9313
+ const staged = await exec2("git diff --cached --name-only -- .github/workflows", {
9314
+ cwd: projectDir,
9315
+ timeout: 1e4
9316
+ });
9317
+ if (!staged.trim()) return { refreshed: false };
9318
+ await exec2(
9319
+ `git commit -m ${shellEscape(
9320
+ "chore(ci): refresh scaffolded workflows to pinned substrate (promote uses apply-tier)"
9321
+ )} -- .github/workflows`,
9322
+ { cwd: projectDir, timeout: 15e3 }
9323
+ );
9324
+ await pushCurrentBranchForPr({ cwd: projectDir });
9325
+ return { refreshed: true, detail: `refreshed + pushed ${touched.join(", ") || "workflow(s)"} onto the PR head` };
9326
+ }
9090
9327
  async function mergeFeature(args) {
9091
9328
  const current = readWorkflowState(args.projectDir);
9092
9329
  if (!current) {
@@ -9141,6 +9378,20 @@ async function mergeFeature(args) {
9141
9378
  }
9142
9379
  authVerified = true;
9143
9380
  }
9381
+ const preflightNotes = [];
9382
+ {
9383
+ const refresh = args.refreshWorkflows ?? (() => defaultRefreshPromoteWorkflows(args.projectDir));
9384
+ try {
9385
+ const r = await refresh();
9386
+ if (r.refreshed) {
9387
+ preflightNotes.push(`Refreshed stale CI workflows before merge${r.detail ? ` (${r.detail})` : ""}.`);
9388
+ }
9389
+ } catch (err) {
9390
+ preflightNotes.push(
9391
+ `Workflow self-heal skipped (${err instanceof Error ? err.message : String(err)}); if the promote's migrate-target fails on the tier guard, refresh .github/workflows (merge.yml must call 'lakebase-schema-migrate apply-tier').`
9392
+ );
9393
+ }
9394
+ }
9144
9395
  let paired;
9145
9396
  try {
9146
9397
  paired = await mergePairedPullRequest({
@@ -9155,7 +9406,7 @@ async function mergeFeature(args) {
9155
9406
  "merge-failed"
9156
9407
  );
9157
9408
  }
9158
- const warnings = [...paired.warnings];
9409
+ const warnings = [...preflightNotes, ...paired.warnings];
9159
9410
  let localBranchDeleted = false;
9160
9411
  let headAfter = current.branch;
9161
9412
  if (!args.skipLocalCleanup) {
@@ -9349,8 +9600,8 @@ function shellEscape(s) {
9349
9600
 
9350
9601
  // scripts/lakebase/schema-migrate.ts
9351
9602
  init_esm_shims();
9352
- import * as fs10 from "fs";
9353
- import * as path11 from "path";
9603
+ import * as fs11 from "fs";
9604
+ import * as path12 from "path";
9354
9605
 
9355
9606
  // scripts/lakebase/get-connection.ts
9356
9607
  init_esm_shims();
@@ -9368,25 +9619,25 @@ var CONSORT_VERSION_ENV = "CONSORT_VERSION";
9368
9619
 
9369
9620
  // scripts/lakebase/self-version.ts
9370
9621
  init_esm_shims();
9371
- import * as fs4 from "fs";
9372
- import * as path4 from "path";
9622
+ import * as fs5 from "fs";
9623
+ import * as path5 from "path";
9373
9624
  import { fileURLToPath as fileURLToPath3 } from "url";
9374
9625
  var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
9375
9626
  var cached;
9376
9627
  function substrateSelfVersion() {
9377
9628
  if (cached !== void 0) return cached;
9378
- if ("0.2.44".length > 0) {
9379
- cached = "0.2.44";
9629
+ if ("0.2.45".length > 0) {
9630
+ cached = "0.2.45";
9380
9631
  return cached;
9381
9632
  }
9382
9633
  cached = "unknown";
9383
9634
  try {
9384
- let dir = path4.dirname(fileURLToPath3(import.meta.url));
9635
+ let dir = path5.dirname(fileURLToPath3(import.meta.url));
9385
9636
  for (let i = 0; i < 8; i++) {
9386
- const pkgPath = path4.join(dir, "package.json");
9387
- if (fs4.existsSync(pkgPath)) {
9637
+ const pkgPath = path5.join(dir, "package.json");
9638
+ if (fs5.existsSync(pkgPath)) {
9388
9639
  try {
9389
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf8"));
9640
+ const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf8"));
9390
9641
  if (pkg.name === PKG_NAME && typeof pkg.version === "string" && pkg.version.length > 0) {
9391
9642
  cached = pkg.version;
9392
9643
  return cached;
@@ -9394,7 +9645,7 @@ function substrateSelfVersion() {
9394
9645
  } catch {
9395
9646
  }
9396
9647
  }
9397
- const parent = path4.dirname(dir);
9648
+ const parent = path5.dirname(dir);
9398
9649
  if (parent === dir) break;
9399
9650
  dir = parent;
9400
9651
  }
@@ -9481,22 +9732,22 @@ init_esm_shims();
9481
9732
 
9482
9733
  // scripts/lakebase/adapters/alembic-adapter.ts
9483
9734
  init_esm_shims();
9484
- import * as fs6 from "fs";
9485
- import * as path6 from "path";
9735
+ import * as fs7 from "fs";
9736
+ import * as path7 from "path";
9486
9737
 
9487
9738
  // scripts/lakebase/schema-migrate-runners/alembic.ts
9488
9739
  init_esm_shims();
9489
9740
  import { spawn } from "child_process";
9490
- import * as fs5 from "fs";
9491
- import * as path5 from "path";
9741
+ import * as fs6 from "fs";
9742
+ import * as path6 from "path";
9492
9743
  function resolveAlembicBin(projectDir) {
9493
9744
  const candidates = [
9494
- path5.join(projectDir, ".venv", "bin", "alembic"),
9495
- path5.join(projectDir, "venv", "bin", "alembic")
9745
+ path6.join(projectDir, ".venv", "bin", "alembic"),
9746
+ path6.join(projectDir, "venv", "bin", "alembic")
9496
9747
  ];
9497
9748
  for (const candidate of candidates) {
9498
9749
  try {
9499
- if (fs5.existsSync(candidate)) return candidate;
9750
+ if (fs6.existsSync(candidate)) return candidate;
9500
9751
  } catch {
9501
9752
  }
9502
9753
  }
@@ -9506,7 +9757,7 @@ function spawnAlembic(projectDir, args, dsn) {
9506
9757
  return new Promise((resolve2, reject) => {
9507
9758
  const bin = resolveAlembicBin(projectDir);
9508
9759
  const env = { ...process.env };
9509
- env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path5.delimiter);
9760
+ env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path6.delimiter);
9510
9761
  if (dsn) env.DATABASE_URL = dsn;
9511
9762
  const child = spawn(bin, args, {
9512
9763
  cwd: projectDir,
@@ -9554,10 +9805,10 @@ async function createAlembicRevision(opts) {
9554
9805
  const m = stdout.match(/Generating\s+(\S+\.py)/);
9555
9806
  if (m) return m[1].trim();
9556
9807
  for (const rel of ["migrations/versions", "alembic/versions"]) {
9557
- const dir = path5.join(opts.projectDir, rel);
9558
- if (!fs5.existsSync(dir)) continue;
9559
- const hit = fs5.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
9560
- if (hit) return path5.join(dir, hit);
9808
+ const dir = path6.join(opts.projectDir, rel);
9809
+ if (!fs6.existsSync(dir)) continue;
9810
+ const hit = fs6.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
9811
+ if (hit) return path6.join(dir, hit);
9561
9812
  }
9562
9813
  throw new SchemaMigrationError(
9563
9814
  `alembic revision succeeded but the created file could not be located.
@@ -9692,15 +9943,15 @@ async function buildDsn(args) {
9692
9943
  }
9693
9944
  function findVersionsDir(projectDir) {
9694
9945
  const candidates = [
9695
- path6.join(projectDir, "migrations", "versions"),
9696
- path6.join(projectDir, "alembic", "versions")
9946
+ path7.join(projectDir, "migrations", "versions"),
9947
+ path7.join(projectDir, "alembic", "versions")
9697
9948
  ];
9698
- return candidates.find((p) => fs6.existsSync(p));
9949
+ return candidates.find((p) => fs7.existsSync(p));
9699
9950
  }
9700
9951
  function listAlembicFiles(projectDir) {
9701
9952
  const dir = findVersionsDir(projectDir);
9702
9953
  if (!dir) return [];
9703
- const files = fs6.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
9954
+ const files = fs7.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
9704
9955
  return files.map((filename) => {
9705
9956
  const stem = filename.replace(/\.py$/, "");
9706
9957
  const sep2 = stem.indexOf("_");
@@ -9725,9 +9976,9 @@ var AlembicAdapter = {
9725
9976
  * here. Callers can still force-select via project.yaml#migration_tool.
9726
9977
  */
9727
9978
  detect(projectDir) {
9728
- if (fs6.existsSync(path6.join(projectDir, "alembic.ini"))) return true;
9729
- if (fs6.existsSync(path6.join(projectDir, "migrations", "env.py"))) return true;
9730
- if (fs6.existsSync(path6.join(projectDir, "alembic", "env.py"))) return true;
9979
+ if (fs7.existsSync(path7.join(projectDir, "alembic.ini"))) return true;
9980
+ if (fs7.existsSync(path7.join(projectDir, "migrations", "env.py"))) return true;
9981
+ if (fs7.existsSync(path7.join(projectDir, "alembic", "env.py"))) return true;
9731
9982
  return false;
9732
9983
  },
9733
9984
  async apply(args) {
@@ -9833,7 +10084,7 @@ var AlembicAdapter = {
9833
10084
  autogenerate: !!args.autogenerate,
9834
10085
  dsn
9835
10086
  });
9836
- return { status: "ok", version: revId, filename: path6.basename(created), path: created };
10087
+ return { status: "ok", version: revId, filename: path7.basename(created), path: created };
9837
10088
  } catch (err) {
9838
10089
  return {
9839
10090
  status: "error",
@@ -9850,7 +10101,7 @@ var AlembicAdapter = {
9850
10101
  if (heads.length <= 1) return { status: "noop", headsBefore: heads };
9851
10102
  if (args.dryRun) return { status: "ok", headsBefore: heads };
9852
10103
  const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
9853
- const mergeRevision = path6.basename(created).replace(/\.py$/, "").split("_")[0];
10104
+ const mergeRevision = path7.basename(created).replace(/\.py$/, "").split("_")[0];
9854
10105
  return { status: "ok", headsBefore: heads, mergeRevision, path: created };
9855
10106
  } catch (err) {
9856
10107
  return {
@@ -9865,13 +10116,13 @@ registerSchemaMigrationAdapter(AlembicAdapter);
9865
10116
 
9866
10117
  // scripts/lakebase/adapters/flyway-adapter.ts
9867
10118
  init_esm_shims();
9868
- import * as fs7 from "fs";
9869
- import * as path8 from "path";
10119
+ import * as fs8 from "fs";
10120
+ import * as path9 from "path";
9870
10121
 
9871
10122
  // scripts/lakebase/schema-migrate-runners/flyway.ts
9872
10123
  init_esm_shims();
9873
10124
  import { spawn as spawn2 } from "child_process";
9874
- import * as path7 from "path";
10125
+ import * as path8 from "path";
9875
10126
  function dsnToFlywayEnv(dsn) {
9876
10127
  const u = new URL(dsn);
9877
10128
  const user = decodeURIComponent(u.username);
@@ -9881,7 +10132,7 @@ function dsnToFlywayEnv(dsn) {
9881
10132
  return { url, user, password };
9882
10133
  }
9883
10134
  function migrationsLocation(projectDir) {
9884
- return `filesystem:${path7.join(projectDir, "src", "main", "resources", "db", "migration")}`;
10135
+ return `filesystem:${path8.join(projectDir, "src", "main", "resources", "db", "migration")}`;
9885
10136
  }
9886
10137
  function runFlyway(ctx, args) {
9887
10138
  const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
@@ -9982,7 +10233,7 @@ async function statusFlyway(ctx) {
9982
10233
  if (state === "SUCCESS" || state === "BASELINE") {
9983
10234
  current = m.version;
9984
10235
  } else if (state === "PENDING") {
9985
- const filename = m.filepath ? path7.basename(m.filepath) : `V${m.version}__migration.sql`;
10236
+ const filename = m.filepath ? path8.basename(m.filepath) : `V${m.version}__migration.sql`;
9986
10237
  pending.push({
9987
10238
  version: m.version,
9988
10239
  filename,
@@ -10005,9 +10256,9 @@ async function buildDsn2(args) {
10005
10256
  return result.url;
10006
10257
  }
10007
10258
  function listFlywayFiles(projectDir) {
10008
- const dir = path8.join(projectDir, "src", "main", "resources", "db", "migration");
10009
- if (!fs7.existsSync(dir)) return [];
10010
- const files = fs7.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
10259
+ const dir = path9.join(projectDir, "src", "main", "resources", "db", "migration");
10260
+ if (!fs8.existsSync(dir)) return [];
10261
+ const files = fs8.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
10011
10262
  return files.map((filename) => {
10012
10263
  const m = filename.match(/^V(\d+(?:\.\d+)*)__(.+)\.sql$/);
10013
10264
  const version = m[1];
@@ -10030,7 +10281,7 @@ var FlywayAdapter = {
10030
10281
  id: "flyway",
10031
10282
  languages: ["java", "kotlin"],
10032
10283
  detect(projectDir) {
10033
- return fs7.existsSync(path8.join(projectDir, "pom.xml"));
10284
+ return fs8.existsSync(path9.join(projectDir, "pom.xml"));
10034
10285
  },
10035
10286
  async apply(args) {
10036
10287
  const dsn = await buildDsn2(args);
@@ -10088,14 +10339,14 @@ var FlywayAdapter = {
10088
10339
  // optional-protocol shape makes this additive.
10089
10340
  async newMigration(args) {
10090
10341
  try {
10091
- const dir = path8.join(args.projectDir, "src", "main", "resources", "db", "migration");
10092
- fs7.mkdirSync(dir, { recursive: true });
10342
+ const dir = path9.join(args.projectDir, "src", "main", "resources", "db", "migration");
10343
+ fs8.mkdirSync(dir, { recursive: true });
10093
10344
  const version = migrationTimestamp();
10094
10345
  const slug = migrationSlug2(args.slug);
10095
10346
  const filename = `V${version}__${slug}.sql`;
10096
- const full = path8.join(dir, filename);
10097
- if (fs7.existsSync(full)) throw new Error(`${filename} already exists`);
10098
- fs7.writeFileSync(
10347
+ const full = path9.join(dir, filename);
10348
+ if (fs8.existsSync(full)) throw new Error(`${filename} already exists`);
10349
+ fs8.writeFileSync(
10099
10350
  full,
10100
10351
  `-- V${version}: ${args.slug}
10101
10352
  -- Flyway migration (write your DDL/DML below).
@@ -10118,19 +10369,19 @@ registerSchemaMigrationAdapter(FlywayAdapter);
10118
10369
 
10119
10370
  // scripts/lakebase/adapters/knex-adapter.ts
10120
10371
  init_esm_shims();
10121
- import * as fs9 from "fs";
10122
- import * as path10 from "path";
10372
+ import * as fs10 from "fs";
10373
+ import * as path11 from "path";
10123
10374
 
10124
10375
  // scripts/lakebase/schema-migrate-runners/knex.ts
10125
10376
  init_esm_shims();
10126
10377
  import { spawn as spawn3 } from "child_process";
10127
- import * as fs8 from "fs";
10128
- import * as path9 from "path";
10378
+ import * as fs9 from "fs";
10379
+ import * as path10 from "path";
10129
10380
  var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
10130
10381
  function findKnexfile(projectDir) {
10131
10382
  for (const name of KNEXFILE_VARIANTS) {
10132
- const p = path9.join(projectDir, name);
10133
- if (fs8.existsSync(p)) return p;
10383
+ const p = path10.join(projectDir, name);
10384
+ if (fs9.existsSync(p)) return p;
10134
10385
  }
10135
10386
  return void 0;
10136
10387
  }
@@ -10282,9 +10533,9 @@ async function buildDsn3(args) {
10282
10533
  }
10283
10534
  var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
10284
10535
  function listKnexFiles(projectDir) {
10285
- const dir = path10.join(projectDir, "migrations");
10286
- if (!fs9.existsSync(dir)) return [];
10287
- const files = fs9.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
10536
+ const dir = path11.join(projectDir, "migrations");
10537
+ if (!fs10.existsSync(dir)) return [];
10538
+ const files = fs10.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
10288
10539
  return files.map((filename) => {
10289
10540
  const stem = filename.replace(/\.(js|ts)$/, "");
10290
10541
  const m = stem.match(/^(\d{14})_(.+)$/);
@@ -10304,7 +10555,7 @@ var KnexAdapter = {
10304
10555
  * project.yaml#migration_tool.
10305
10556
  */
10306
10557
  detect(projectDir) {
10307
- return KNEXFILE_VARIANTS2.some((name) => fs9.existsSync(path10.join(projectDir, name)));
10558
+ return KNEXFILE_VARIANTS2.some((name) => fs10.existsSync(path11.join(projectDir, name)));
10308
10559
  },
10309
10560
  async apply(args) {
10310
10561
  const dsn = await buildDsn3(args);
@@ -10377,9 +10628,9 @@ var KnexAdapter = {
10377
10628
  async newMigration(args) {
10378
10629
  try {
10379
10630
  const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
10380
- const stem = path10.basename(created).replace(/\.(js|ts)$/, "");
10631
+ const stem = path11.basename(created).replace(/\.(js|ts)$/, "");
10381
10632
  const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
10382
- return { status: "ok", version, filename: path10.basename(created), path: created };
10633
+ return { status: "ok", version, filename: path11.basename(created), path: created };
10383
10634
  } catch (err) {
10384
10635
  return {
10385
10636
  status: "error",
@@ -10672,7 +10923,7 @@ async function runScmMergeCli(argv) {
10672
10923
  `);
10673
10924
  return 0;
10674
10925
  }
10675
- const projectDir = path12.resolve(args.projectDir ?? process.cwd());
10926
+ const projectDir = path13.resolve(args.projectDir ?? process.cwd());
10676
10927
  const waitMigrate = args.noWaitMigrate ? false : true;
10677
10928
  const verifyMigrateAuth = waitMigrate && !args.noVerifyMigrateAuth ? async () => {
10678
10929
  try {