@databricks-solutions/lakebase-scm-utils 0.2.48 → 0.2.49

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 (51) hide show
  1. package/dist/ci-secrets-CnGrdQV-.d.cts +84 -0
  2. package/dist/ci-secrets-CnGrdQV-.d.ts +84 -0
  3. package/dist/scripts/index.cjs +2177 -2052
  4. package/dist/scripts/index.d.cts +2 -1
  5. package/dist/scripts/index.d.ts +2 -1
  6. package/dist/scripts/index.js +253 -134
  7. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
  8. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
  9. package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
  10. package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
  11. package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
  12. package/dist/scripts/lakebase/detect-language.cli.js +2 -2
  13. package/dist/scripts/lakebase/doctor.cli.cjs +2 -2
  14. package/dist/scripts/lakebase/doctor.cli.js +2 -2
  15. package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
  16. package/dist/scripts/lakebase/get-connection.cli.js +2 -2
  17. package/dist/scripts/lakebase/index.cjs +2163 -2050
  18. package/dist/scripts/lakebase/index.d.cts +8 -0
  19. package/dist/scripts/lakebase/index.d.ts +8 -0
  20. package/dist/scripts/lakebase/index.js +243 -130
  21. package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
  22. package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
  23. package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
  24. package/dist/scripts/lakebase/new-migration.cli.js +2 -2
  25. package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
  26. package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
  27. package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
  28. package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
  29. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
  30. package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
  31. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
  32. package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
  33. package/dist/scripts/lakebase/scm-merge.cli.cjs +2216 -1994
  34. package/dist/scripts/lakebase/scm-merge.cli.js +296 -74
  35. package/dist/scripts/lakebase/scm-prepare-pr.cli.cjs +479 -86
  36. package/dist/scripts/lakebase/scm-prepare-pr.cli.js +479 -86
  37. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
  38. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
  39. package/dist/scripts/lakebase/sync-ci-secrets.cli.cjs +56 -30
  40. package/dist/scripts/lakebase/sync-ci-secrets.cli.js +56 -30
  41. package/dist/scripts/util/index.cjs +142 -25
  42. package/dist/scripts/util/index.d.cts +2 -27
  43. package/dist/scripts/util/index.d.ts +2 -27
  44. package/dist/scripts/util/index.js +136 -25
  45. package/package.json +1 -1
  46. package/scripts/lakebase/create-project.ts +2 -2
  47. package/scripts/lakebase/scm-merge.ts +21 -0
  48. package/scripts/lakebase/scm-prepare-pr.ts +10 -1
  49. package/scripts/lakebase/sync-ci-secrets.cli.ts +2 -2
  50. package/scripts/util/ci-secrets.ts +212 -26
  51. package/templates/project/common/scripts/create-token-and-sync-secrets.sh +9 -86
@@ -1457,7 +1457,7 @@ var require_light = __commonJS({
1457
1457
 
1458
1458
  // scripts/lakebase/scm-prepare-pr.cli.ts
1459
1459
  init_esm_shims();
1460
- import * as path4 from "path";
1460
+ import * as path5 from "path";
1461
1461
 
1462
1462
  // scripts/util/cli-entry.ts
1463
1463
  init_esm_shims();
@@ -1643,16 +1643,246 @@ async function getOwnerRepo(cwd) {
1643
1643
  }
1644
1644
  }
1645
1645
 
1646
- // scripts/lakebase/scm-git-base.ts
1646
+ // scripts/util/ci-secrets.ts
1647
1647
  init_esm_shims();
1648
- async function resolveGitBase(parentBranch, cwd) {
1649
- if (parentBranch && await gitBranchExists({ cwd, branch: parentBranch })) {
1650
- return parentBranch;
1648
+ import * as path3 from "path";
1649
+
1650
+ // scripts/lakebase/databricks-cli.ts
1651
+ init_esm_shims();
1652
+ import { execFile, execFileSync as execFileSync2 } from "child_process";
1653
+ import { promisify } from "util";
1654
+ import { join as join2 } from "path";
1655
+
1656
+ // scripts/lakebase/kit-config.ts
1657
+ init_esm_shims();
1658
+ function intFromEnv(name, fallback) {
1659
+ const raw = process.env[name];
1660
+ if (!raw) return fallback;
1661
+ const parsed = Number.parseInt(raw, 10);
1662
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
1663
+ return parsed;
1664
+ }
1665
+ var DAY_MS = 24 * 60 * 60 * 1e3;
1666
+ var KIT_TIMEOUTS = {
1667
+ cliDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_DEFAULT_MS", 3e4),
1668
+ cliCreateProject: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_PROJECT_MS", 18e4),
1669
+ cliCreateBranch: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_BRANCH_MS", 6e4),
1670
+ cliCreateEndpoint: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_ENDPOINT_MS", 6e4),
1671
+ readyWait: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_WAIT_MS", 12e4),
1672
+ readyPoll: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_POLL_MS", 5e3),
1673
+ pgConnect: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_CONNECT_MS", 1e4),
1674
+ pgStatement: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_STATEMENT_MS", 15e3),
1675
+ gitDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_DEFAULT_MS", 5e3),
1676
+ gitCheckout: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_CHECKOUT_MS", 1e4),
1677
+ gitNetwork: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_NETWORK_MS", 15e3),
1678
+ gitPush: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_PUSH_MS", 3e4),
1679
+ cliLong: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_LONG_MS", 6e4),
1680
+ cmdShort: intFromEnv("LAKEBASE_KIT_TIMEOUT_CMD_SHORT_MS", 5e3),
1681
+ initializrCacheTtl: intFromEnv("LAKEBASE_KIT_INITIALIZR_CACHE_TTL_MS", 10 * 60 * 1e3),
1682
+ featureBranchTtlMs: intFromEnv("LAKEBASE_KIT_FEATURE_BRANCH_TTL_MS", 30 * DAY_MS),
1683
+ testBranchTtlMs: intFromEnv("LAKEBASE_KIT_TEST_BRANCH_TTL_MS", 14 * DAY_MS),
1684
+ uatBranchTtlMs: intFromEnv("LAKEBASE_KIT_UAT_BRANCH_TTL_MS", 14 * DAY_MS),
1685
+ perfBranchTtlMs: intFromEnv("LAKEBASE_KIT_PERF_BRANCH_TTL_MS", 7 * DAY_MS)
1686
+ };
1687
+ function urlFromEnv(name, fallback) {
1688
+ const raw = process.env[name];
1689
+ if (!raw) return fallback;
1690
+ return raw.replace(/\/+$/, "");
1691
+ }
1692
+ var KIT_REGISTRIES = {
1693
+ mavenCentral: urlFromEnv("LAKEBASE_KIT_REGISTRY_MAVEN_CENTRAL", "https://repo1.maven.org/maven2"),
1694
+ springInitializr: urlFromEnv("LAKEBASE_KIT_REGISTRY_SPRING_INITIALIZR", "https://start.spring.io")
1695
+ };
1696
+
1697
+ // scripts/lakebase/databricks-profile.ts
1698
+ init_esm_shims();
1699
+ import * as fs from "fs";
1700
+ import { execFileSync } from "child_process";
1701
+ function normalizeHost(host) {
1702
+ return host.trim().replace(/\/+$/, "").toLowerCase();
1703
+ }
1704
+ function selectProfileForHost(profilesJson, host) {
1705
+ const target = normalizeHost(host);
1706
+ if (!target) return void 0;
1707
+ const start = profilesJson.indexOf("{");
1708
+ if (start < 0) return void 0;
1709
+ let parsed;
1710
+ try {
1711
+ parsed = JSON.parse(profilesJson.slice(start));
1712
+ } catch {
1713
+ return void 0;
1651
1714
  }
1652
- return resolveDefaultBranch({ cwd });
1715
+ const profiles = parsed.profiles;
1716
+ if (!Array.isArray(profiles)) return void 0;
1717
+ const names = profiles.filter((p) => {
1718
+ if (!p || typeof p !== "object") return false;
1719
+ const rec = p;
1720
+ return typeof rec.name === "string" && typeof rec.host === "string" && rec.valid === true && normalizeHost(rec.host) === target;
1721
+ }).map((p) => p.name);
1722
+ const distinct = Array.from(new Set(names));
1723
+ return distinct.length === 1 ? distinct[0] : void 0;
1724
+ }
1725
+ function resolveProfileForHostSync(host, timeoutMs = KIT_TIMEOUTS.cliDefault) {
1726
+ if (!normalizeHost(host)) return void 0;
1727
+ let out;
1728
+ try {
1729
+ out = execFileSync("databricks", ["auth", "profiles", "-o", "json"], {
1730
+ encoding: "utf8",
1731
+ stdio: ["ignore", "pipe", "pipe"],
1732
+ timeout: timeoutMs
1733
+ });
1734
+ } catch {
1735
+ return void 0;
1736
+ }
1737
+ return selectProfileForHost(out, host);
1653
1738
  }
1654
1739
 
1655
- // scripts/github/pr.ts
1740
+ // scripts/lakebase/env-file.ts
1741
+ init_esm_shims();
1742
+ import * as fs2 from "fs";
1743
+ import * as path2 from "path";
1744
+ function readEnvVar(envPath, key) {
1745
+ if (!fs2.existsSync(envPath)) return void 0;
1746
+ let value;
1747
+ for (const line of fs2.readFileSync(envPath, "utf-8").split("\n")) {
1748
+ const trimmed = line.trimStart();
1749
+ if (trimmed.startsWith("#") || !trimmed.startsWith(`${key}=`)) continue;
1750
+ value = trimmed.slice(key.length + 1).trim().replace(/^["']|["']$/g, "");
1751
+ }
1752
+ return value && value.length > 0 ? value : void 0;
1753
+ }
1754
+
1755
+ // scripts/lakebase/databricks-cli.ts
1756
+ var execFileP = promisify(execFile);
1757
+ var DatabricksCliError = class extends Error {
1758
+ constructor(message, profile, stderr) {
1759
+ super(message);
1760
+ this.profile = profile;
1761
+ this.stderr = stderr;
1762
+ this.name = "DatabricksCliError";
1763
+ }
1764
+ profile;
1765
+ stderr;
1766
+ };
1767
+ var DatabricksAuthError = class extends DatabricksCliError {
1768
+ constructor(profile, detail) {
1769
+ const login = `databricks auth login${profile ? ` --profile ${profile}` : ""}`;
1770
+ super(
1771
+ `Databricks authentication failed${profile ? ` for profile "${profile}"` : ""}: the cached token is missing or expired. Re-authenticate, then re-run:
1772
+ ${login}
1773
+ ${detail}`,
1774
+ profile,
1775
+ detail
1776
+ );
1777
+ this.name = "DatabricksAuthError";
1778
+ }
1779
+ };
1780
+ var profileByHost = /* @__PURE__ */ new Map();
1781
+ var profileByEnvFile = /* @__PURE__ */ new Map();
1782
+ var hostByEnvFile = /* @__PURE__ */ new Map();
1783
+ function envFileHost(cwd) {
1784
+ if (hostByEnvFile.has(cwd)) return hostByEnvFile.get(cwd);
1785
+ const v = readEnvVar(join2(cwd, ".env"), "DATABRICKS_HOST");
1786
+ hostByEnvFile.set(cwd, v);
1787
+ return v;
1788
+ }
1789
+ function effectiveHost(opts) {
1790
+ const base = opts.env ?? process.env;
1791
+ const cwd = opts.cwd ?? process.cwd();
1792
+ const h = opts.host ?? base.DATABRICKS_HOST ?? envFileHost(cwd);
1793
+ return h?.trim() || void 0;
1794
+ }
1795
+ function isAuthFailure(text) {
1796
+ return /refresh token is invalid|auth login|could not be retrieved because|not authenticated|no valid.*(credential|token)|invalid.*(access token|credential)|\b401\b|unauthorized/i.test(
1797
+ text
1798
+ );
1799
+ }
1800
+ function resolveProfile(opts) {
1801
+ const base = opts.env ?? process.env;
1802
+ if (opts.profile) return opts.profile;
1803
+ const envProfile = base.DATABRICKS_CONFIG_PROFILE?.trim();
1804
+ if (envProfile) return envProfile;
1805
+ const cwd = opts.cwd ?? process.cwd();
1806
+ let fromEnvFile;
1807
+ if (profileByEnvFile.has(cwd)) {
1808
+ fromEnvFile = profileByEnvFile.get(cwd);
1809
+ } else {
1810
+ fromEnvFile = readEnvVar(join2(cwd, ".env"), "DATABRICKS_CONFIG_PROFILE");
1811
+ profileByEnvFile.set(cwd, fromEnvFile);
1812
+ }
1813
+ if (fromEnvFile) return fromEnvFile;
1814
+ const host = effectiveHost(opts);
1815
+ if (!host) return void 0;
1816
+ if (profileByHost.has(host)) return profileByHost.get(host);
1817
+ const resolved = resolveProfileForHostSync(host, opts.timeout);
1818
+ profileByHost.set(host, resolved);
1819
+ return resolved;
1820
+ }
1821
+ function buildInvocation(args, opts) {
1822
+ const base = opts.env ?? process.env;
1823
+ const trimmedHost = effectiveHost(opts)?.replace(/\/+$/, "");
1824
+ const env = { ...base };
1825
+ if (trimmedHost) env.DATABRICKS_HOST = trimmedHost;
1826
+ delete env.DATABRICKS_WORKSPACE_ID;
1827
+ const profile = resolveProfile(opts);
1828
+ const argv = profile && !opts.noProfile && !args.includes("--profile") ? [...args, "--profile", profile] : args;
1829
+ return { argv, env, profile };
1830
+ }
1831
+ function classifyDatabricksError(err, argv, profile) {
1832
+ const e = err;
1833
+ const asText = (v) => typeof v === "string" ? v : Buffer.isBuffer(v) ? v.toString("utf8") : "";
1834
+ const stderr = asText(e.stderr).trim();
1835
+ const stdout = asText(e.stdout).trim();
1836
+ const haystack = `${e.message ?? ""}
1837
+ ${stderr}
1838
+ ${stdout}`;
1839
+ if (isAuthFailure(haystack)) {
1840
+ return new DatabricksAuthError(profile, stderr || stdout || (e.message ?? ""));
1841
+ }
1842
+ const killed = e.killed === true;
1843
+ const signal = e.signal ?? void 0;
1844
+ const detail = stderr ? `
1845
+ stderr: ${stderr}` : stdout ? `
1846
+ stdout: ${stdout}` : killed || signal ? `
1847
+ (no output; the CLI was killed${signal ? ` by ${signal}` : ""}, likely a TIMEOUT; raise the budget via the matching LAKEBASE_KIT_TIMEOUT_* env var)` : e.code !== void 0 ? `
1848
+ (no stderr/stdout; exit ${e.code})` : "";
1849
+ return new DatabricksCliError(
1850
+ `databricks ${argv.join(" ")} failed: ${e.message}${detail}`,
1851
+ profile,
1852
+ stderr || stdout
1853
+ );
1854
+ }
1855
+ async function runDatabricks(args, opts = {}) {
1856
+ const { argv, env, profile } = buildInvocation(args, opts);
1857
+ const timeout = opts.timeout ?? KIT_TIMEOUTS.cliDefault;
1858
+ try {
1859
+ if (opts.input !== void 0) {
1860
+ return await execDatabricksWithStdin(argv, opts.input, env, timeout);
1861
+ }
1862
+ const { stdout } = await execFileP("databricks", argv, { env, timeout });
1863
+ return stdout.toString();
1864
+ } catch (err) {
1865
+ throw classifyDatabricksError(err, argv, profile);
1866
+ }
1867
+ }
1868
+ function execDatabricksWithStdin(argv, input, env, timeout) {
1869
+ return new Promise((resolve2, reject) => {
1870
+ const child = execFile("databricks", argv, { env, timeout }, (err, stdout, stderr) => {
1871
+ if (err) {
1872
+ err.stdout = String(stdout ?? "");
1873
+ err.stderr = String(stderr ?? "");
1874
+ reject(err);
1875
+ return;
1876
+ }
1877
+ resolve2(String(stdout ?? ""));
1878
+ });
1879
+ child.stdin?.on("error", () => {
1880
+ });
1881
+ child.stdin?.end(input);
1882
+ });
1883
+ }
1884
+
1885
+ // scripts/github/secrets.ts
1656
1886
  init_esm_shims();
1657
1887
 
1658
1888
  // node_modules/octokit/dist-bundle/index.js
@@ -2717,7 +2947,7 @@ paginateRest.VERSION = VERSION5;
2717
2947
 
2718
2948
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
2719
2949
  init_esm_shims();
2720
- var generateMessage = (path5, cursorValue) => `The cursor at "${path5.join(
2950
+ var generateMessage = (path6, cursorValue) => `The cursor at "${path6.join(
2721
2951
  ","
2722
2952
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
2723
2953
  var MissingCursorChange = class extends Error {
@@ -2758,9 +2988,9 @@ function findPaginatedResourcePath(responseData) {
2758
2988
  }
2759
2989
  return paginatedResourcePath;
2760
2990
  }
2761
- var deepFindPathToProperty = (object, searchProp, path5 = []) => {
2991
+ var deepFindPathToProperty = (object, searchProp, path6 = []) => {
2762
2992
  for (const key of Object.keys(object)) {
2763
- const currentPath = [...path5, key];
2993
+ const currentPath = [...path6, key];
2764
2994
  const currentValue = object[key];
2765
2995
  if (isObject(currentValue)) {
2766
2996
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -2778,12 +3008,12 @@ var deepFindPathToProperty = (object, searchProp, path5 = []) => {
2778
3008
  }
2779
3009
  return [];
2780
3010
  };
2781
- var get = (object, path5) => {
2782
- return path5.reduce((current, nextProperty) => current[nextProperty], object);
3011
+ var get = (object, path6) => {
3012
+ return path6.reduce((current, nextProperty) => current[nextProperty], object);
2783
3013
  };
2784
- var set = (object, path5, mutator) => {
2785
- const lastProperty = path5[path5.length - 1];
2786
- const parentPath = [...path5].slice(0, -1);
3014
+ var set = (object, path6, mutator) => {
3015
+ const lastProperty = path6[path6.length - 1];
3016
+ const parentPath = [...path6].slice(0, -1);
2787
3017
  const parent = get(object, parentPath);
2788
3018
  if (typeof mutator === "function") {
2789
3019
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -2835,22 +3065,22 @@ var mergeResponses = (response1, response2) => {
2835
3065
  if (Object.keys(response1).length === 0) {
2836
3066
  return Object.assign(response1, response2);
2837
3067
  }
2838
- const path5 = findPaginatedResourcePath(response1);
2839
- const nodesPath = [...path5, "nodes"];
3068
+ const path6 = findPaginatedResourcePath(response1);
3069
+ const nodesPath = [...path6, "nodes"];
2840
3070
  const newNodes = get(response2, nodesPath);
2841
3071
  if (newNodes) {
2842
3072
  set(response1, nodesPath, (values) => {
2843
3073
  return [...values, ...newNodes];
2844
3074
  });
2845
3075
  }
2846
- const edgesPath = [...path5, "edges"];
3076
+ const edgesPath = [...path6, "edges"];
2847
3077
  const newEdges = get(response2, edgesPath);
2848
3078
  if (newEdges) {
2849
3079
  set(response1, edgesPath, (values) => {
2850
3080
  return [...values, ...newEdges];
2851
3081
  });
2852
3082
  }
2853
- const pageInfoPath = [...path5, "pageInfo"];
3083
+ const pageInfoPath = [...path6, "pageInfo"];
2854
3084
  set(response1, pageInfoPath, get(response2, pageInfoPath));
2855
3085
  return response1;
2856
3086
  };
@@ -5271,7 +5501,7 @@ var triggers_notification_paths_default = [
5271
5501
  ];
5272
5502
  function routeMatcher(paths) {
5273
5503
  const regexes = paths.map(
5274
- (path5) => path5.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5504
+ (path6) => path6.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5275
5505
  );
5276
5506
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
5277
5507
  return new RegExp(regex2, "i");
@@ -8175,9 +8405,12 @@ function onSecondaryRateLimit(retryAfter, options, octokit2) {
8175
8405
  var App2 = App.defaults({ Octokit: Octokit2 });
8176
8406
  var OAuthApp2 = OAuthApp.defaults({ Octokit: Octokit2 });
8177
8407
 
8408
+ // scripts/github/secrets.ts
8409
+ import sodium from "tweetsodium";
8410
+
8178
8411
  // scripts/github/auth.ts
8179
8412
  init_esm_shims();
8180
- import { execFileSync } from "child_process";
8413
+ import { execFileSync as execFileSync3 } from "child_process";
8181
8414
  var GITHUB_SCOPES = ["repo", "workflow", "delete_repo"];
8182
8415
  async function resolveGitHubToken(scopes = GITHUB_SCOPES) {
8183
8416
  const fromEnv = process.env.GITHUB_TOKEN?.trim();
@@ -8205,7 +8438,7 @@ async function tryVsCodeSession(opts = {}) {
8205
8438
  }
8206
8439
  function tryGhAuthToken() {
8207
8440
  try {
8208
- const raw = execFileSync("gh", ["auth", "token"], {
8441
+ const raw = execFileSync3("gh", ["auth", "token"], {
8209
8442
  encoding: "utf8",
8210
8443
  stdio: ["ignore", "pipe", "pipe"],
8211
8444
  timeout: 5e3
@@ -8217,71 +8450,230 @@ function tryGhAuthToken() {
8217
8450
  }
8218
8451
  }
8219
8452
 
8220
- // scripts/lakebase/branch-delete.ts
8221
- init_esm_shims();
8222
-
8223
- // scripts/lakebase/branch-utils.ts
8224
- init_esm_shims();
8453
+ // scripts/github/secrets.ts
8454
+ var GitHubSecretsError = class extends Error {
8455
+ status;
8456
+ constructor(message, status) {
8457
+ super(message);
8458
+ this.name = "GitHubSecretsError";
8459
+ this.status = status;
8460
+ }
8461
+ };
8462
+ async function getOctokit() {
8463
+ const token = await resolveGitHubToken();
8464
+ return new Octokit2({ auth: token });
8465
+ }
8466
+ function wrap(err, context) {
8467
+ if (err instanceof RequestError) {
8468
+ throw new GitHubSecretsError(`${context}: ${err.message}`, err.status);
8469
+ }
8470
+ if (err instanceof Error) {
8471
+ throw new GitHubSecretsError(`${context}: ${err.message}`);
8472
+ }
8473
+ throw new GitHubSecretsError(context);
8474
+ }
8475
+ function encryptSecret(publicKey, secretValue) {
8476
+ const keyBytes = Buffer.from(publicKey, "base64");
8477
+ const messageBytes = Buffer.from(secretValue);
8478
+ const encryptedBytes = sodium.seal(messageBytes, keyBytes);
8479
+ return Buffer.from(encryptedBytes).toString("base64");
8480
+ }
8481
+ async function setRepoSecret(ownerRepo, secretName, secretValue) {
8482
+ try {
8483
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8484
+ const octokit2 = await getOctokit();
8485
+ const { data: keyData } = await octokit2.rest.actions.getRepoPublicKey({ owner, repo });
8486
+ const encryptedValue = encryptSecret(keyData.key, secretValue);
8487
+ await octokit2.rest.actions.createOrUpdateRepoSecret({
8488
+ owner,
8489
+ repo,
8490
+ secret_name: secretName,
8491
+ encrypted_value: encryptedValue,
8492
+ key_id: keyData.key_id
8493
+ });
8494
+ } catch (err) {
8495
+ if (err instanceof GitHubSecretsError) throw err;
8496
+ wrap(err, `Failed to set secret ${secretName} on ${ownerRepo}`);
8497
+ }
8498
+ }
8499
+ async function setRepoSecrets(ownerRepo, secrets) {
8500
+ for (const [name, value] of Object.entries(secrets)) {
8501
+ if (!value) {
8502
+ throw new GitHubSecretsError(`Missing value for secret ${name}`);
8503
+ }
8504
+ }
8505
+ for (const [name, value] of Object.entries(secrets)) {
8506
+ await setRepoSecret(ownerRepo, name, value);
8507
+ }
8508
+ }
8509
+ async function listSecretNames(ownerRepo) {
8510
+ try {
8511
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8512
+ const octokit2 = await getOctokit();
8513
+ const { data } = await octokit2.rest.actions.listRepoSecrets({ owner, repo });
8514
+ return data.secrets.map((s) => s.name);
8515
+ } catch {
8516
+ return [];
8517
+ }
8518
+ }
8225
8519
 
8226
- // scripts/lakebase/databricks-cli.ts
8227
- init_esm_shims();
8228
- import { execFile, execFileSync as execFileSync3 } from "child_process";
8229
- import { promisify } from "util";
8230
- import { join as join2 } from "path";
8520
+ // scripts/util/ci-secrets.ts
8521
+ var REQUIRED_CI_SECRETS = ["DATABRICKS_HOST", "LAKEBASE_PROJECT_ID", "DATABRICKS_TOKEN"];
8522
+ var CI_TOKEN_LIFETIME_SECONDS = 7776e3;
8523
+ var CI_TOKEN_REMINT_MARGIN_SECONDS = 86400;
8524
+ function ciTokenComment(ownerRepo) {
8525
+ const repoName = ownerRepo.includes("/") ? ownerRepo.slice(ownerRepo.lastIndexOf("/") + 1) : ownerRepo;
8526
+ return `GitHub Actions (${repoName})`;
8527
+ }
8528
+ async function missingCiSecrets(ownerRepo) {
8529
+ const present = new Set(await listSecretNames(ownerRepo));
8530
+ return REQUIRED_CI_SECRETS.filter((n) => !present.has(n));
8531
+ }
8532
+ async function mintCiToken(args) {
8533
+ try {
8534
+ const raw = await runDatabricks(
8535
+ ["tokens", "create", "--comment", args.comment, "--lifetime-seconds", String(args.lifetimeSeconds), "-o", "json"],
8536
+ { host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
8537
+ );
8538
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
8539
+ const token = parsed.token_value || parsed.token || "";
8540
+ if (token) return token;
8541
+ } catch {
8542
+ }
8543
+ try {
8544
+ const raw = await runDatabricks(["auth", "token", "-o", "json"], {
8545
+ host: args.databricksHost,
8546
+ cwd: args.projectDir,
8547
+ timeout: 3e4
8548
+ });
8549
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
8550
+ return parsed.access_token || "";
8551
+ } catch {
8552
+ return "";
8553
+ }
8554
+ }
8555
+ async function syncCiSecrets(args) {
8556
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
8557
+ if (!ownerRepo) {
8558
+ throw new Error("Could not resolve GitHub repository from git remote");
8559
+ }
8560
+ if (!args.databricksHost) {
8561
+ throw new Error("syncCiSecrets: databricksHost is required");
8562
+ }
8563
+ if (!args.lakebaseProjectId) {
8564
+ throw new Error("syncCiSecrets: lakebaseProjectId is required");
8565
+ }
8566
+ const lifetime = args.lifetimeSeconds ?? CI_TOKEN_LIFETIME_SECONDS;
8567
+ const comment = args.comment ?? ciTokenComment(ownerRepo);
8568
+ const secrets = {
8569
+ DATABRICKS_HOST: args.databricksHost,
8570
+ LAKEBASE_PROJECT_ID: args.lakebaseProjectId
8571
+ };
8572
+ const token = await mintCiToken({
8573
+ databricksHost: args.databricksHost,
8574
+ projectDir: args.projectDir,
8575
+ comment,
8576
+ lifetimeSeconds: lifetime
8577
+ });
8578
+ if (token) secrets.DATABRICKS_TOKEN = token;
8579
+ await setRepoSecrets(ownerRepo, secrets);
8580
+ }
8581
+ async function ciTokenExpiry(args) {
8582
+ const comment = ciTokenComment(args.ownerRepo);
8583
+ let raw;
8584
+ try {
8585
+ raw = await runDatabricks(["tokens", "list", "-o", "json"], {
8586
+ host: args.databricksHost,
8587
+ cwd: args.projectDir,
8588
+ timeout: 3e4
8589
+ });
8590
+ } catch {
8591
+ return null;
8592
+ }
8593
+ let infos;
8594
+ try {
8595
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("["))));
8596
+ infos = Array.isArray(parsed) ? parsed : [];
8597
+ } catch {
8598
+ return null;
8599
+ }
8600
+ const expiries = infos.filter((t) => t.comment === comment).map((t) => t.expiry_time === -1 ? Number.POSITIVE_INFINITY : Number(t.expiry_time)).filter((n) => Number.isFinite(n) || n === Number.POSITIVE_INFINITY);
8601
+ if (expiries.length === 0) return null;
8602
+ return Math.max(...expiries);
8603
+ }
8604
+ async function ensureCiSecretsFresh(args) {
8605
+ const now = args.now ?? Date.now;
8606
+ const marginMs = (args.marginSeconds ?? CI_TOKEN_REMINT_MARGIN_SECONDS) * 1e3;
8607
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
8608
+ if (!ownerRepo) {
8609
+ throw new Error("Could not resolve GitHub repository from git remote");
8610
+ }
8611
+ const sync = () => syncCiSecrets({
8612
+ projectDir: args.projectDir,
8613
+ databricksHost: args.databricksHost,
8614
+ lakebaseProjectId: args.lakebaseProjectId,
8615
+ ownerRepo
8616
+ });
8617
+ const missing = await missingCiSecrets(ownerRepo);
8618
+ if (missing.length > 0) {
8619
+ await sync();
8620
+ return { action: "provisioned", reason: `CI secret(s) were missing (${missing.join(", ")}); provisioned.` };
8621
+ }
8622
+ const expiry = await ciTokenExpiry({ projectDir: args.projectDir, databricksHost: args.databricksHost, ownerRepo });
8623
+ if (expiry === null) {
8624
+ await sync();
8625
+ return { action: "reminted", reason: "no live CI token found (expired or minted under a different identity); re-minted." };
8626
+ }
8627
+ if (expiry !== Number.POSITIVE_INFINITY && expiry < now() + marginMs) {
8628
+ await sync();
8629
+ const hrs = Math.max(0, Math.round((expiry - now()) / 36e5));
8630
+ return { action: "reminted", reason: `CI token expires in ~${hrs}h (within the re-mint margin); re-minted.` };
8631
+ }
8632
+ return { action: "ok", reason: "CI token is current." };
8633
+ }
8634
+ async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
8635
+ const envPath = path3.join(projectDir, ".env");
8636
+ const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
8637
+ const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
8638
+ if (!databricksHost || !lakebaseProjectId) {
8639
+ return {
8640
+ action: "skipped",
8641
+ reason: "CI-auth preflight skipped: .env is missing DATABRICKS_HOST / LAKEBASE_PROJECT_ID."
8642
+ };
8643
+ }
8644
+ try {
8645
+ return await ensureCiSecretsFresh({
8646
+ projectDir,
8647
+ databricksHost,
8648
+ lakebaseProjectId,
8649
+ ownerRepo: opts?.ownerRepo,
8650
+ marginSeconds: opts?.marginSeconds
8651
+ });
8652
+ } catch (err) {
8653
+ return {
8654
+ action: "failed",
8655
+ reason: `CI-auth preflight could not re-mint (${err instanceof Error ? err.message : String(err)}); if CI fails on auth, run lakebase-sync-ci-secrets.`
8656
+ };
8657
+ }
8658
+ }
8231
8659
 
8232
- // scripts/lakebase/kit-config.ts
8660
+ // scripts/lakebase/scm-git-base.ts
8233
8661
  init_esm_shims();
8234
- function intFromEnv(name, fallback) {
8235
- const raw = process.env[name];
8236
- if (!raw) return fallback;
8237
- const parsed = Number.parseInt(raw, 10);
8238
- if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
8239
- return parsed;
8240
- }
8241
- var DAY_MS = 24 * 60 * 60 * 1e3;
8242
- var KIT_TIMEOUTS = {
8243
- cliDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_DEFAULT_MS", 3e4),
8244
- cliCreateProject: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_PROJECT_MS", 18e4),
8245
- cliCreateBranch: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_BRANCH_MS", 6e4),
8246
- cliCreateEndpoint: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_ENDPOINT_MS", 6e4),
8247
- readyWait: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_WAIT_MS", 12e4),
8248
- readyPoll: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_POLL_MS", 5e3),
8249
- pgConnect: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_CONNECT_MS", 1e4),
8250
- pgStatement: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_STATEMENT_MS", 15e3),
8251
- gitDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_DEFAULT_MS", 5e3),
8252
- gitCheckout: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_CHECKOUT_MS", 1e4),
8253
- gitNetwork: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_NETWORK_MS", 15e3),
8254
- gitPush: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_PUSH_MS", 3e4),
8255
- cliLong: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_LONG_MS", 6e4),
8256
- cmdShort: intFromEnv("LAKEBASE_KIT_TIMEOUT_CMD_SHORT_MS", 5e3),
8257
- initializrCacheTtl: intFromEnv("LAKEBASE_KIT_INITIALIZR_CACHE_TTL_MS", 10 * 60 * 1e3),
8258
- featureBranchTtlMs: intFromEnv("LAKEBASE_KIT_FEATURE_BRANCH_TTL_MS", 30 * DAY_MS),
8259
- testBranchTtlMs: intFromEnv("LAKEBASE_KIT_TEST_BRANCH_TTL_MS", 14 * DAY_MS),
8260
- uatBranchTtlMs: intFromEnv("LAKEBASE_KIT_UAT_BRANCH_TTL_MS", 14 * DAY_MS),
8261
- perfBranchTtlMs: intFromEnv("LAKEBASE_KIT_PERF_BRANCH_TTL_MS", 7 * DAY_MS)
8262
- };
8263
- function urlFromEnv(name, fallback) {
8264
- const raw = process.env[name];
8265
- if (!raw) return fallback;
8266
- return raw.replace(/\/+$/, "");
8662
+ async function resolveGitBase(parentBranch, cwd) {
8663
+ if (parentBranch && await gitBranchExists({ cwd, branch: parentBranch })) {
8664
+ return parentBranch;
8665
+ }
8666
+ return resolveDefaultBranch({ cwd });
8267
8667
  }
8268
- var KIT_REGISTRIES = {
8269
- mavenCentral: urlFromEnv("LAKEBASE_KIT_REGISTRY_MAVEN_CENTRAL", "https://repo1.maven.org/maven2"),
8270
- springInitializr: urlFromEnv("LAKEBASE_KIT_REGISTRY_SPRING_INITIALIZR", "https://start.spring.io")
8271
- };
8272
8668
 
8273
- // scripts/lakebase/databricks-profile.ts
8669
+ // scripts/github/pr.ts
8274
8670
  init_esm_shims();
8275
- import * as fs from "fs";
8276
- import { execFileSync as execFileSync2 } from "child_process";
8277
8671
 
8278
- // scripts/lakebase/env-file.ts
8672
+ // scripts/lakebase/branch-delete.ts
8279
8673
  init_esm_shims();
8280
- import * as fs2 from "fs";
8281
- import * as path2 from "path";
8282
8674
 
8283
- // scripts/lakebase/databricks-cli.ts
8284
- var execFileP = promisify(execFile);
8675
+ // scripts/lakebase/branch-utils.ts
8676
+ init_esm_shims();
8285
8677
 
8286
8678
  // scripts/lakebase/branch-id.ts
8287
8679
  init_esm_shims();
@@ -8302,7 +8694,7 @@ async function octokit() {
8302
8694
  const token = await resolveGitHubToken();
8303
8695
  return new Octokit2({ auth: token });
8304
8696
  }
8305
- function wrap(err, context) {
8697
+ function wrap2(err, context) {
8306
8698
  if (err instanceof RequestError) {
8307
8699
  throw new GitHubPullRequestError(`${context}: ${err.message}`, err.status);
8308
8700
  }
@@ -8330,7 +8722,7 @@ async function createPullRequest(args) {
8330
8722
  });
8331
8723
  return data.html_url || "";
8332
8724
  } catch (err) {
8333
- wrap(err, "Failed to create pull request");
8725
+ wrap2(err, "Failed to create pull request");
8334
8726
  }
8335
8727
  }
8336
8728
  async function getPullRequest(ownerRepo, headBranch) {
@@ -8425,7 +8817,7 @@ var RUNTIME_ARTIFACT_IGNORE = [
8425
8817
  // scripts/lakebase/scm-workflow-state.ts
8426
8818
  init_esm_shims();
8427
8819
  import * as fs3 from "fs";
8428
- import * as path3 from "path";
8820
+ import * as path4 from "path";
8429
8821
  import { execFileSync as execFileSync4 } from "child_process";
8430
8822
  function isGitTracked(projectDir, rel) {
8431
8823
  try {
@@ -8444,7 +8836,7 @@ function ensureWorkflowStateUntracked(projectDir) {
8444
8836
  } catch {
8445
8837
  }
8446
8838
  try {
8447
- const gitignore = path3.join(projectDir, ".gitignore");
8839
+ const gitignore = path4.join(projectDir, ".gitignore");
8448
8840
  const existing = fs3.existsSync(gitignore) ? fs3.readFileSync(gitignore, "utf8") : "";
8449
8841
  if (!existing.split("\n").some((l) => l.trim() === rel)) {
8450
8842
  const sep2 = existing === "" || existing.endsWith("\n") ? "" : "\n";
@@ -8472,7 +8864,7 @@ var STATE_INDEX = SCM_STATES.reduce(
8472
8864
  );
8473
8865
  var STATE_FILE_REL = ".lakebase/workflow-state.json";
8474
8866
  function stateFilePath(projectDir) {
8475
- return path3.join(projectDir, STATE_FILE_REL);
8867
+ return path4.join(projectDir, STATE_FILE_REL);
8476
8868
  }
8477
8869
  function readWorkflowState(projectDir) {
8478
8870
  const p = stateFilePath(projectDir);
@@ -8506,7 +8898,7 @@ function writeWorkflowState(projectDir, state) {
8506
8898
  ${summary}`);
8507
8899
  }
8508
8900
  ensureWorkflowStateUntracked(projectDir);
8509
- const dir = path3.join(projectDir, ".lakebase");
8901
+ const dir = path4.join(projectDir, ".lakebase");
8510
8902
  fs3.mkdirSync(dir, { recursive: true });
8511
8903
  const target = stateFilePath(projectDir);
8512
8904
  const tmp = `${target}.tmp`;
@@ -8743,6 +9135,7 @@ async function preparePr(args) {
8743
9135
  "no-github-remote"
8744
9136
  );
8745
9137
  }
9138
+ const ciFreshness = await ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo });
8746
9139
  const now = (args.now ?? (() => /* @__PURE__ */ new Date()))();
8747
9140
  let prUrl = args.prUrlOverride ?? "";
8748
9141
  let prCreated = false;
@@ -8787,7 +9180,7 @@ async function preparePr(args) {
8787
9180
  pushed_at: now.toISOString()
8788
9181
  };
8789
9182
  writeWorkflowState(args.projectDir, next);
8790
- return { state: next, prUrl, prCreated };
9183
+ return { state: next, prUrl, prCreated, ciFreshness };
8791
9184
  }
8792
9185
  async function ensureAheadOfParent(cwd, branch, parent) {
8793
9186
  try {
@@ -8935,7 +9328,7 @@ async function runScmPreparePrCli(argv) {
8935
9328
  `);
8936
9329
  return 0;
8937
9330
  }
8938
- const projectDir = path4.resolve(args.projectDir ?? process.cwd());
9331
+ const projectDir = path5.resolve(args.projectDir ?? process.cwd());
8939
9332
  try {
8940
9333
  const result = await preparePr({
8941
9334
  projectDir,