@databricks-solutions/lakebase-scm-utils 0.2.47 → 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 (52) 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 +2230 -2052
  4. package/dist/scripts/index.d.cts +3 -2
  5. package/dist/scripts/index.d.ts +3 -2
  6. package/dist/scripts/index.js +305 -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 +2216 -2050
  18. package/dist/scripts/lakebase/index.d.cts +37 -11
  19. package/dist/scripts/lakebase/index.d.ts +37 -11
  20. package/dist/scripts/lakebase/index.js +295 -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 +2345 -1994
  34. package/dist/scripts/lakebase/scm-merge.cli.js +425 -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 +112 -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/.gitignore.base +4 -6
  52. package/templates/project/common/scripts/create-token-and-sync-secrets.sh +9 -86
@@ -1469,7 +1469,7 @@ __export(scm_prepare_pr_cli_exports, {
1469
1469
  });
1470
1470
  module.exports = __toCommonJS(scm_prepare_pr_cli_exports);
1471
1471
  init_cjs_shims();
1472
- var path3 = __toESM(require("path"), 1);
1472
+ var path4 = __toESM(require("path"), 1);
1473
1473
 
1474
1474
  // scripts/util/cli-entry.ts
1475
1475
  init_cjs_shims();
@@ -1655,16 +1655,246 @@ async function getOwnerRepo(cwd) {
1655
1655
  }
1656
1656
  }
1657
1657
 
1658
- // scripts/lakebase/scm-git-base.ts
1658
+ // scripts/util/ci-secrets.ts
1659
1659
  init_cjs_shims();
1660
- async function resolveGitBase(parentBranch, cwd) {
1661
- if (parentBranch && await gitBranchExists({ cwd, branch: parentBranch })) {
1662
- return parentBranch;
1660
+ var path2 = __toESM(require("path"), 1);
1661
+
1662
+ // scripts/lakebase/databricks-cli.ts
1663
+ init_cjs_shims();
1664
+ var import_node_child_process2 = require("child_process");
1665
+ var import_node_util = require("util");
1666
+ var import_node_path = require("path");
1667
+
1668
+ // scripts/lakebase/kit-config.ts
1669
+ init_cjs_shims();
1670
+ function intFromEnv(name, fallback) {
1671
+ const raw = process.env[name];
1672
+ if (!raw) return fallback;
1673
+ const parsed = Number.parseInt(raw, 10);
1674
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
1675
+ return parsed;
1676
+ }
1677
+ var DAY_MS = 24 * 60 * 60 * 1e3;
1678
+ var KIT_TIMEOUTS = {
1679
+ cliDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_DEFAULT_MS", 3e4),
1680
+ cliCreateProject: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_PROJECT_MS", 18e4),
1681
+ cliCreateBranch: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_BRANCH_MS", 6e4),
1682
+ cliCreateEndpoint: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_ENDPOINT_MS", 6e4),
1683
+ readyWait: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_WAIT_MS", 12e4),
1684
+ readyPoll: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_POLL_MS", 5e3),
1685
+ pgConnect: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_CONNECT_MS", 1e4),
1686
+ pgStatement: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_STATEMENT_MS", 15e3),
1687
+ gitDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_DEFAULT_MS", 5e3),
1688
+ gitCheckout: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_CHECKOUT_MS", 1e4),
1689
+ gitNetwork: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_NETWORK_MS", 15e3),
1690
+ gitPush: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_PUSH_MS", 3e4),
1691
+ cliLong: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_LONG_MS", 6e4),
1692
+ cmdShort: intFromEnv("LAKEBASE_KIT_TIMEOUT_CMD_SHORT_MS", 5e3),
1693
+ initializrCacheTtl: intFromEnv("LAKEBASE_KIT_INITIALIZR_CACHE_TTL_MS", 10 * 60 * 1e3),
1694
+ featureBranchTtlMs: intFromEnv("LAKEBASE_KIT_FEATURE_BRANCH_TTL_MS", 30 * DAY_MS),
1695
+ testBranchTtlMs: intFromEnv("LAKEBASE_KIT_TEST_BRANCH_TTL_MS", 14 * DAY_MS),
1696
+ uatBranchTtlMs: intFromEnv("LAKEBASE_KIT_UAT_BRANCH_TTL_MS", 14 * DAY_MS),
1697
+ perfBranchTtlMs: intFromEnv("LAKEBASE_KIT_PERF_BRANCH_TTL_MS", 7 * DAY_MS)
1698
+ };
1699
+ function urlFromEnv(name, fallback) {
1700
+ const raw = process.env[name];
1701
+ if (!raw) return fallback;
1702
+ return raw.replace(/\/+$/, "");
1703
+ }
1704
+ var KIT_REGISTRIES = {
1705
+ mavenCentral: urlFromEnv("LAKEBASE_KIT_REGISTRY_MAVEN_CENTRAL", "https://repo1.maven.org/maven2"),
1706
+ springInitializr: urlFromEnv("LAKEBASE_KIT_REGISTRY_SPRING_INITIALIZR", "https://start.spring.io")
1707
+ };
1708
+
1709
+ // scripts/lakebase/databricks-profile.ts
1710
+ init_cjs_shims();
1711
+ var fs = __toESM(require("fs"), 1);
1712
+ var import_node_child_process = require("child_process");
1713
+ function normalizeHost(host) {
1714
+ return host.trim().replace(/\/+$/, "").toLowerCase();
1715
+ }
1716
+ function selectProfileForHost(profilesJson, host) {
1717
+ const target = normalizeHost(host);
1718
+ if (!target) return void 0;
1719
+ const start = profilesJson.indexOf("{");
1720
+ if (start < 0) return void 0;
1721
+ let parsed;
1722
+ try {
1723
+ parsed = JSON.parse(profilesJson.slice(start));
1724
+ } catch {
1725
+ return void 0;
1663
1726
  }
1664
- return resolveDefaultBranch({ cwd });
1727
+ const profiles = parsed.profiles;
1728
+ if (!Array.isArray(profiles)) return void 0;
1729
+ const names = profiles.filter((p) => {
1730
+ if (!p || typeof p !== "object") return false;
1731
+ const rec = p;
1732
+ return typeof rec.name === "string" && typeof rec.host === "string" && rec.valid === true && normalizeHost(rec.host) === target;
1733
+ }).map((p) => p.name);
1734
+ const distinct = Array.from(new Set(names));
1735
+ return distinct.length === 1 ? distinct[0] : void 0;
1736
+ }
1737
+ function resolveProfileForHostSync(host, timeoutMs = KIT_TIMEOUTS.cliDefault) {
1738
+ if (!normalizeHost(host)) return void 0;
1739
+ let out;
1740
+ try {
1741
+ out = (0, import_node_child_process.execFileSync)("databricks", ["auth", "profiles", "-o", "json"], {
1742
+ encoding: "utf8",
1743
+ stdio: ["ignore", "pipe", "pipe"],
1744
+ timeout: timeoutMs
1745
+ });
1746
+ } catch {
1747
+ return void 0;
1748
+ }
1749
+ return selectProfileForHost(out, host);
1665
1750
  }
1666
1751
 
1667
- // scripts/github/pr.ts
1752
+ // scripts/lakebase/env-file.ts
1753
+ init_cjs_shims();
1754
+ var fs2 = __toESM(require("fs"), 1);
1755
+ var path = __toESM(require("path"), 1);
1756
+ function readEnvVar(envPath, key) {
1757
+ if (!fs2.existsSync(envPath)) return void 0;
1758
+ let value;
1759
+ for (const line of fs2.readFileSync(envPath, "utf-8").split("\n")) {
1760
+ const trimmed = line.trimStart();
1761
+ if (trimmed.startsWith("#") || !trimmed.startsWith(`${key}=`)) continue;
1762
+ value = trimmed.slice(key.length + 1).trim().replace(/^["']|["']$/g, "");
1763
+ }
1764
+ return value && value.length > 0 ? value : void 0;
1765
+ }
1766
+
1767
+ // scripts/lakebase/databricks-cli.ts
1768
+ var execFileP = (0, import_node_util.promisify)(import_node_child_process2.execFile);
1769
+ var DatabricksCliError = class extends Error {
1770
+ constructor(message, profile, stderr) {
1771
+ super(message);
1772
+ this.profile = profile;
1773
+ this.stderr = stderr;
1774
+ this.name = "DatabricksCliError";
1775
+ }
1776
+ profile;
1777
+ stderr;
1778
+ };
1779
+ var DatabricksAuthError = class extends DatabricksCliError {
1780
+ constructor(profile, detail) {
1781
+ const login = `databricks auth login${profile ? ` --profile ${profile}` : ""}`;
1782
+ super(
1783
+ `Databricks authentication failed${profile ? ` for profile "${profile}"` : ""}: the cached token is missing or expired. Re-authenticate, then re-run:
1784
+ ${login}
1785
+ ${detail}`,
1786
+ profile,
1787
+ detail
1788
+ );
1789
+ this.name = "DatabricksAuthError";
1790
+ }
1791
+ };
1792
+ var profileByHost = /* @__PURE__ */ new Map();
1793
+ var profileByEnvFile = /* @__PURE__ */ new Map();
1794
+ var hostByEnvFile = /* @__PURE__ */ new Map();
1795
+ function envFileHost(cwd) {
1796
+ if (hostByEnvFile.has(cwd)) return hostByEnvFile.get(cwd);
1797
+ const v = readEnvVar((0, import_node_path.join)(cwd, ".env"), "DATABRICKS_HOST");
1798
+ hostByEnvFile.set(cwd, v);
1799
+ return v;
1800
+ }
1801
+ function effectiveHost(opts) {
1802
+ const base = opts.env ?? process.env;
1803
+ const cwd = opts.cwd ?? process.cwd();
1804
+ const h = opts.host ?? base.DATABRICKS_HOST ?? envFileHost(cwd);
1805
+ return h?.trim() || void 0;
1806
+ }
1807
+ function isAuthFailure(text) {
1808
+ 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(
1809
+ text
1810
+ );
1811
+ }
1812
+ function resolveProfile(opts) {
1813
+ const base = opts.env ?? process.env;
1814
+ if (opts.profile) return opts.profile;
1815
+ const envProfile = base.DATABRICKS_CONFIG_PROFILE?.trim();
1816
+ if (envProfile) return envProfile;
1817
+ const cwd = opts.cwd ?? process.cwd();
1818
+ let fromEnvFile;
1819
+ if (profileByEnvFile.has(cwd)) {
1820
+ fromEnvFile = profileByEnvFile.get(cwd);
1821
+ } else {
1822
+ fromEnvFile = readEnvVar((0, import_node_path.join)(cwd, ".env"), "DATABRICKS_CONFIG_PROFILE");
1823
+ profileByEnvFile.set(cwd, fromEnvFile);
1824
+ }
1825
+ if (fromEnvFile) return fromEnvFile;
1826
+ const host = effectiveHost(opts);
1827
+ if (!host) return void 0;
1828
+ if (profileByHost.has(host)) return profileByHost.get(host);
1829
+ const resolved = resolveProfileForHostSync(host, opts.timeout);
1830
+ profileByHost.set(host, resolved);
1831
+ return resolved;
1832
+ }
1833
+ function buildInvocation(args, opts) {
1834
+ const base = opts.env ?? process.env;
1835
+ const trimmedHost = effectiveHost(opts)?.replace(/\/+$/, "");
1836
+ const env = { ...base };
1837
+ if (trimmedHost) env.DATABRICKS_HOST = trimmedHost;
1838
+ delete env.DATABRICKS_WORKSPACE_ID;
1839
+ const profile = resolveProfile(opts);
1840
+ const argv = profile && !opts.noProfile && !args.includes("--profile") ? [...args, "--profile", profile] : args;
1841
+ return { argv, env, profile };
1842
+ }
1843
+ function classifyDatabricksError(err, argv, profile) {
1844
+ const e = err;
1845
+ const asText = (v) => typeof v === "string" ? v : Buffer.isBuffer(v) ? v.toString("utf8") : "";
1846
+ const stderr = asText(e.stderr).trim();
1847
+ const stdout = asText(e.stdout).trim();
1848
+ const haystack = `${e.message ?? ""}
1849
+ ${stderr}
1850
+ ${stdout}`;
1851
+ if (isAuthFailure(haystack)) {
1852
+ return new DatabricksAuthError(profile, stderr || stdout || (e.message ?? ""));
1853
+ }
1854
+ const killed = e.killed === true;
1855
+ const signal = e.signal ?? void 0;
1856
+ const detail = stderr ? `
1857
+ stderr: ${stderr}` : stdout ? `
1858
+ stdout: ${stdout}` : killed || signal ? `
1859
+ (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 ? `
1860
+ (no stderr/stdout; exit ${e.code})` : "";
1861
+ return new DatabricksCliError(
1862
+ `databricks ${argv.join(" ")} failed: ${e.message}${detail}`,
1863
+ profile,
1864
+ stderr || stdout
1865
+ );
1866
+ }
1867
+ async function runDatabricks(args, opts = {}) {
1868
+ const { argv, env, profile } = buildInvocation(args, opts);
1869
+ const timeout = opts.timeout ?? KIT_TIMEOUTS.cliDefault;
1870
+ try {
1871
+ if (opts.input !== void 0) {
1872
+ return await execDatabricksWithStdin(argv, opts.input, env, timeout);
1873
+ }
1874
+ const { stdout } = await execFileP("databricks", argv, { env, timeout });
1875
+ return stdout.toString();
1876
+ } catch (err) {
1877
+ throw classifyDatabricksError(err, argv, profile);
1878
+ }
1879
+ }
1880
+ function execDatabricksWithStdin(argv, input, env, timeout) {
1881
+ return new Promise((resolve2, reject) => {
1882
+ const child = (0, import_node_child_process2.execFile)("databricks", argv, { env, timeout }, (err, stdout, stderr) => {
1883
+ if (err) {
1884
+ err.stdout = String(stdout ?? "");
1885
+ err.stderr = String(stderr ?? "");
1886
+ reject(err);
1887
+ return;
1888
+ }
1889
+ resolve2(String(stdout ?? ""));
1890
+ });
1891
+ child.stdin?.on("error", () => {
1892
+ });
1893
+ child.stdin?.end(input);
1894
+ });
1895
+ }
1896
+
1897
+ // scripts/github/secrets.ts
1668
1898
  init_cjs_shims();
1669
1899
 
1670
1900
  // node_modules/octokit/dist-bundle/index.js
@@ -2729,7 +2959,7 @@ paginateRest.VERSION = VERSION5;
2729
2959
 
2730
2960
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
2731
2961
  init_cjs_shims();
2732
- var generateMessage = (path4, cursorValue) => `The cursor at "${path4.join(
2962
+ var generateMessage = (path5, cursorValue) => `The cursor at "${path5.join(
2733
2963
  ","
2734
2964
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
2735
2965
  var MissingCursorChange = class extends Error {
@@ -2770,9 +3000,9 @@ function findPaginatedResourcePath(responseData) {
2770
3000
  }
2771
3001
  return paginatedResourcePath;
2772
3002
  }
2773
- var deepFindPathToProperty = (object, searchProp, path4 = []) => {
3003
+ var deepFindPathToProperty = (object, searchProp, path5 = []) => {
2774
3004
  for (const key of Object.keys(object)) {
2775
- const currentPath = [...path4, key];
3005
+ const currentPath = [...path5, key];
2776
3006
  const currentValue = object[key];
2777
3007
  if (isObject(currentValue)) {
2778
3008
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -2790,12 +3020,12 @@ var deepFindPathToProperty = (object, searchProp, path4 = []) => {
2790
3020
  }
2791
3021
  return [];
2792
3022
  };
2793
- var get = (object, path4) => {
2794
- return path4.reduce((current, nextProperty) => current[nextProperty], object);
3023
+ var get = (object, path5) => {
3024
+ return path5.reduce((current, nextProperty) => current[nextProperty], object);
2795
3025
  };
2796
- var set = (object, path4, mutator) => {
2797
- const lastProperty = path4[path4.length - 1];
2798
- const parentPath = [...path4].slice(0, -1);
3026
+ var set = (object, path5, mutator) => {
3027
+ const lastProperty = path5[path5.length - 1];
3028
+ const parentPath = [...path5].slice(0, -1);
2799
3029
  const parent = get(object, parentPath);
2800
3030
  if (typeof mutator === "function") {
2801
3031
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -2847,22 +3077,22 @@ var mergeResponses = (response1, response2) => {
2847
3077
  if (Object.keys(response1).length === 0) {
2848
3078
  return Object.assign(response1, response2);
2849
3079
  }
2850
- const path4 = findPaginatedResourcePath(response1);
2851
- const nodesPath = [...path4, "nodes"];
3080
+ const path5 = findPaginatedResourcePath(response1);
3081
+ const nodesPath = [...path5, "nodes"];
2852
3082
  const newNodes = get(response2, nodesPath);
2853
3083
  if (newNodes) {
2854
3084
  set(response1, nodesPath, (values) => {
2855
3085
  return [...values, ...newNodes];
2856
3086
  });
2857
3087
  }
2858
- const edgesPath = [...path4, "edges"];
3088
+ const edgesPath = [...path5, "edges"];
2859
3089
  const newEdges = get(response2, edgesPath);
2860
3090
  if (newEdges) {
2861
3091
  set(response1, edgesPath, (values) => {
2862
3092
  return [...values, ...newEdges];
2863
3093
  });
2864
3094
  }
2865
- const pageInfoPath = [...path4, "pageInfo"];
3095
+ const pageInfoPath = [...path5, "pageInfo"];
2866
3096
  set(response1, pageInfoPath, get(response2, pageInfoPath));
2867
3097
  return response1;
2868
3098
  };
@@ -5283,7 +5513,7 @@ var triggers_notification_paths_default = [
5283
5513
  ];
5284
5514
  function routeMatcher(paths) {
5285
5515
  const regexes = paths.map(
5286
- (path4) => path4.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5516
+ (path5) => path5.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5287
5517
  );
5288
5518
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
5289
5519
  return new RegExp(regex2, "i");
@@ -8187,9 +8417,12 @@ function onSecondaryRateLimit(retryAfter, options, octokit2) {
8187
8417
  var App2 = App.defaults({ Octokit: Octokit2 });
8188
8418
  var OAuthApp2 = OAuthApp.defaults({ Octokit: Octokit2 });
8189
8419
 
8420
+ // scripts/github/secrets.ts
8421
+ var import_tweetsodium = __toESM(require("tweetsodium"), 1);
8422
+
8190
8423
  // scripts/github/auth.ts
8191
8424
  init_cjs_shims();
8192
- var import_node_child_process = require("child_process");
8425
+ var import_node_child_process3 = require("child_process");
8193
8426
  var GITHUB_SCOPES = ["repo", "workflow", "delete_repo"];
8194
8427
  async function resolveGitHubToken(scopes = GITHUB_SCOPES) {
8195
8428
  const fromEnv = process.env.GITHUB_TOKEN?.trim();
@@ -8217,7 +8450,7 @@ async function tryVsCodeSession(opts = {}) {
8217
8450
  }
8218
8451
  function tryGhAuthToken() {
8219
8452
  try {
8220
- const raw = (0, import_node_child_process.execFileSync)("gh", ["auth", "token"], {
8453
+ const raw = (0, import_node_child_process3.execFileSync)("gh", ["auth", "token"], {
8221
8454
  encoding: "utf8",
8222
8455
  stdio: ["ignore", "pipe", "pipe"],
8223
8456
  timeout: 5e3
@@ -8229,71 +8462,230 @@ function tryGhAuthToken() {
8229
8462
  }
8230
8463
  }
8231
8464
 
8232
- // scripts/lakebase/branch-delete.ts
8233
- init_cjs_shims();
8234
-
8235
- // scripts/lakebase/branch-utils.ts
8236
- init_cjs_shims();
8465
+ // scripts/github/secrets.ts
8466
+ var GitHubSecretsError = class extends Error {
8467
+ status;
8468
+ constructor(message, status) {
8469
+ super(message);
8470
+ this.name = "GitHubSecretsError";
8471
+ this.status = status;
8472
+ }
8473
+ };
8474
+ async function getOctokit() {
8475
+ const token = await resolveGitHubToken();
8476
+ return new Octokit2({ auth: token });
8477
+ }
8478
+ function wrap(err, context) {
8479
+ if (err instanceof RequestError) {
8480
+ throw new GitHubSecretsError(`${context}: ${err.message}`, err.status);
8481
+ }
8482
+ if (err instanceof Error) {
8483
+ throw new GitHubSecretsError(`${context}: ${err.message}`);
8484
+ }
8485
+ throw new GitHubSecretsError(context);
8486
+ }
8487
+ function encryptSecret(publicKey, secretValue) {
8488
+ const keyBytes = Buffer.from(publicKey, "base64");
8489
+ const messageBytes = Buffer.from(secretValue);
8490
+ const encryptedBytes = import_tweetsodium.default.seal(messageBytes, keyBytes);
8491
+ return Buffer.from(encryptedBytes).toString("base64");
8492
+ }
8493
+ async function setRepoSecret(ownerRepo, secretName, secretValue) {
8494
+ try {
8495
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8496
+ const octokit2 = await getOctokit();
8497
+ const { data: keyData } = await octokit2.rest.actions.getRepoPublicKey({ owner, repo });
8498
+ const encryptedValue = encryptSecret(keyData.key, secretValue);
8499
+ await octokit2.rest.actions.createOrUpdateRepoSecret({
8500
+ owner,
8501
+ repo,
8502
+ secret_name: secretName,
8503
+ encrypted_value: encryptedValue,
8504
+ key_id: keyData.key_id
8505
+ });
8506
+ } catch (err) {
8507
+ if (err instanceof GitHubSecretsError) throw err;
8508
+ wrap(err, `Failed to set secret ${secretName} on ${ownerRepo}`);
8509
+ }
8510
+ }
8511
+ async function setRepoSecrets(ownerRepo, secrets) {
8512
+ for (const [name, value] of Object.entries(secrets)) {
8513
+ if (!value) {
8514
+ throw new GitHubSecretsError(`Missing value for secret ${name}`);
8515
+ }
8516
+ }
8517
+ for (const [name, value] of Object.entries(secrets)) {
8518
+ await setRepoSecret(ownerRepo, name, value);
8519
+ }
8520
+ }
8521
+ async function listSecretNames(ownerRepo) {
8522
+ try {
8523
+ const { owner, repo } = parseOwnerRepo(ownerRepo);
8524
+ const octokit2 = await getOctokit();
8525
+ const { data } = await octokit2.rest.actions.listRepoSecrets({ owner, repo });
8526
+ return data.secrets.map((s) => s.name);
8527
+ } catch {
8528
+ return [];
8529
+ }
8530
+ }
8237
8531
 
8238
- // scripts/lakebase/databricks-cli.ts
8239
- init_cjs_shims();
8240
- var import_node_child_process3 = require("child_process");
8241
- var import_node_util = require("util");
8242
- var import_node_path = require("path");
8532
+ // scripts/util/ci-secrets.ts
8533
+ var REQUIRED_CI_SECRETS = ["DATABRICKS_HOST", "LAKEBASE_PROJECT_ID", "DATABRICKS_TOKEN"];
8534
+ var CI_TOKEN_LIFETIME_SECONDS = 7776e3;
8535
+ var CI_TOKEN_REMINT_MARGIN_SECONDS = 86400;
8536
+ function ciTokenComment(ownerRepo) {
8537
+ const repoName = ownerRepo.includes("/") ? ownerRepo.slice(ownerRepo.lastIndexOf("/") + 1) : ownerRepo;
8538
+ return `GitHub Actions (${repoName})`;
8539
+ }
8540
+ async function missingCiSecrets(ownerRepo) {
8541
+ const present = new Set(await listSecretNames(ownerRepo));
8542
+ return REQUIRED_CI_SECRETS.filter((n) => !present.has(n));
8543
+ }
8544
+ async function mintCiToken(args) {
8545
+ try {
8546
+ const raw = await runDatabricks(
8547
+ ["tokens", "create", "--comment", args.comment, "--lifetime-seconds", String(args.lifetimeSeconds), "-o", "json"],
8548
+ { host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
8549
+ );
8550
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
8551
+ const token = parsed.token_value || parsed.token || "";
8552
+ if (token) return token;
8553
+ } catch {
8554
+ }
8555
+ try {
8556
+ const raw = await runDatabricks(["auth", "token", "-o", "json"], {
8557
+ host: args.databricksHost,
8558
+ cwd: args.projectDir,
8559
+ timeout: 3e4
8560
+ });
8561
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
8562
+ return parsed.access_token || "";
8563
+ } catch {
8564
+ return "";
8565
+ }
8566
+ }
8567
+ async function syncCiSecrets(args) {
8568
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
8569
+ if (!ownerRepo) {
8570
+ throw new Error("Could not resolve GitHub repository from git remote");
8571
+ }
8572
+ if (!args.databricksHost) {
8573
+ throw new Error("syncCiSecrets: databricksHost is required");
8574
+ }
8575
+ if (!args.lakebaseProjectId) {
8576
+ throw new Error("syncCiSecrets: lakebaseProjectId is required");
8577
+ }
8578
+ const lifetime = args.lifetimeSeconds ?? CI_TOKEN_LIFETIME_SECONDS;
8579
+ const comment = args.comment ?? ciTokenComment(ownerRepo);
8580
+ const secrets = {
8581
+ DATABRICKS_HOST: args.databricksHost,
8582
+ LAKEBASE_PROJECT_ID: args.lakebaseProjectId
8583
+ };
8584
+ const token = await mintCiToken({
8585
+ databricksHost: args.databricksHost,
8586
+ projectDir: args.projectDir,
8587
+ comment,
8588
+ lifetimeSeconds: lifetime
8589
+ });
8590
+ if (token) secrets.DATABRICKS_TOKEN = token;
8591
+ await setRepoSecrets(ownerRepo, secrets);
8592
+ }
8593
+ async function ciTokenExpiry(args) {
8594
+ const comment = ciTokenComment(args.ownerRepo);
8595
+ let raw;
8596
+ try {
8597
+ raw = await runDatabricks(["tokens", "list", "-o", "json"], {
8598
+ host: args.databricksHost,
8599
+ cwd: args.projectDir,
8600
+ timeout: 3e4
8601
+ });
8602
+ } catch {
8603
+ return null;
8604
+ }
8605
+ let infos;
8606
+ try {
8607
+ const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("["))));
8608
+ infos = Array.isArray(parsed) ? parsed : [];
8609
+ } catch {
8610
+ return null;
8611
+ }
8612
+ 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);
8613
+ if (expiries.length === 0) return null;
8614
+ return Math.max(...expiries);
8615
+ }
8616
+ async function ensureCiSecretsFresh(args) {
8617
+ const now = args.now ?? Date.now;
8618
+ const marginMs = (args.marginSeconds ?? CI_TOKEN_REMINT_MARGIN_SECONDS) * 1e3;
8619
+ const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
8620
+ if (!ownerRepo) {
8621
+ throw new Error("Could not resolve GitHub repository from git remote");
8622
+ }
8623
+ const sync = () => syncCiSecrets({
8624
+ projectDir: args.projectDir,
8625
+ databricksHost: args.databricksHost,
8626
+ lakebaseProjectId: args.lakebaseProjectId,
8627
+ ownerRepo
8628
+ });
8629
+ const missing = await missingCiSecrets(ownerRepo);
8630
+ if (missing.length > 0) {
8631
+ await sync();
8632
+ return { action: "provisioned", reason: `CI secret(s) were missing (${missing.join(", ")}); provisioned.` };
8633
+ }
8634
+ const expiry = await ciTokenExpiry({ projectDir: args.projectDir, databricksHost: args.databricksHost, ownerRepo });
8635
+ if (expiry === null) {
8636
+ await sync();
8637
+ return { action: "reminted", reason: "no live CI token found (expired or minted under a different identity); re-minted." };
8638
+ }
8639
+ if (expiry !== Number.POSITIVE_INFINITY && expiry < now() + marginMs) {
8640
+ await sync();
8641
+ const hrs = Math.max(0, Math.round((expiry - now()) / 36e5));
8642
+ return { action: "reminted", reason: `CI token expires in ~${hrs}h (within the re-mint margin); re-minted.` };
8643
+ }
8644
+ return { action: "ok", reason: "CI token is current." };
8645
+ }
8646
+ async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
8647
+ const envPath = path2.join(projectDir, ".env");
8648
+ const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
8649
+ const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
8650
+ if (!databricksHost || !lakebaseProjectId) {
8651
+ return {
8652
+ action: "skipped",
8653
+ reason: "CI-auth preflight skipped: .env is missing DATABRICKS_HOST / LAKEBASE_PROJECT_ID."
8654
+ };
8655
+ }
8656
+ try {
8657
+ return await ensureCiSecretsFresh({
8658
+ projectDir,
8659
+ databricksHost,
8660
+ lakebaseProjectId,
8661
+ ownerRepo: opts?.ownerRepo,
8662
+ marginSeconds: opts?.marginSeconds
8663
+ });
8664
+ } catch (err) {
8665
+ return {
8666
+ action: "failed",
8667
+ 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.`
8668
+ };
8669
+ }
8670
+ }
8243
8671
 
8244
- // scripts/lakebase/kit-config.ts
8672
+ // scripts/lakebase/scm-git-base.ts
8245
8673
  init_cjs_shims();
8246
- function intFromEnv(name, fallback) {
8247
- const raw = process.env[name];
8248
- if (!raw) return fallback;
8249
- const parsed = Number.parseInt(raw, 10);
8250
- if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
8251
- return parsed;
8252
- }
8253
- var DAY_MS = 24 * 60 * 60 * 1e3;
8254
- var KIT_TIMEOUTS = {
8255
- cliDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_DEFAULT_MS", 3e4),
8256
- cliCreateProject: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_PROJECT_MS", 18e4),
8257
- cliCreateBranch: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_BRANCH_MS", 6e4),
8258
- cliCreateEndpoint: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_CREATE_ENDPOINT_MS", 6e4),
8259
- readyWait: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_WAIT_MS", 12e4),
8260
- readyPoll: intFromEnv("LAKEBASE_KIT_TIMEOUT_READY_POLL_MS", 5e3),
8261
- pgConnect: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_CONNECT_MS", 1e4),
8262
- pgStatement: intFromEnv("LAKEBASE_KIT_TIMEOUT_PG_STATEMENT_MS", 15e3),
8263
- gitDefault: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_DEFAULT_MS", 5e3),
8264
- gitCheckout: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_CHECKOUT_MS", 1e4),
8265
- gitNetwork: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_NETWORK_MS", 15e3),
8266
- gitPush: intFromEnv("LAKEBASE_KIT_TIMEOUT_GIT_PUSH_MS", 3e4),
8267
- cliLong: intFromEnv("LAKEBASE_KIT_TIMEOUT_CLI_LONG_MS", 6e4),
8268
- cmdShort: intFromEnv("LAKEBASE_KIT_TIMEOUT_CMD_SHORT_MS", 5e3),
8269
- initializrCacheTtl: intFromEnv("LAKEBASE_KIT_INITIALIZR_CACHE_TTL_MS", 10 * 60 * 1e3),
8270
- featureBranchTtlMs: intFromEnv("LAKEBASE_KIT_FEATURE_BRANCH_TTL_MS", 30 * DAY_MS),
8271
- testBranchTtlMs: intFromEnv("LAKEBASE_KIT_TEST_BRANCH_TTL_MS", 14 * DAY_MS),
8272
- uatBranchTtlMs: intFromEnv("LAKEBASE_KIT_UAT_BRANCH_TTL_MS", 14 * DAY_MS),
8273
- perfBranchTtlMs: intFromEnv("LAKEBASE_KIT_PERF_BRANCH_TTL_MS", 7 * DAY_MS)
8274
- };
8275
- function urlFromEnv(name, fallback) {
8276
- const raw = process.env[name];
8277
- if (!raw) return fallback;
8278
- return raw.replace(/\/+$/, "");
8674
+ async function resolveGitBase(parentBranch, cwd) {
8675
+ if (parentBranch && await gitBranchExists({ cwd, branch: parentBranch })) {
8676
+ return parentBranch;
8677
+ }
8678
+ return resolveDefaultBranch({ cwd });
8279
8679
  }
8280
- var KIT_REGISTRIES = {
8281
- mavenCentral: urlFromEnv("LAKEBASE_KIT_REGISTRY_MAVEN_CENTRAL", "https://repo1.maven.org/maven2"),
8282
- springInitializr: urlFromEnv("LAKEBASE_KIT_REGISTRY_SPRING_INITIALIZR", "https://start.spring.io")
8283
- };
8284
8680
 
8285
- // scripts/lakebase/databricks-profile.ts
8681
+ // scripts/github/pr.ts
8286
8682
  init_cjs_shims();
8287
- var fs = __toESM(require("fs"), 1);
8288
- var import_node_child_process2 = require("child_process");
8289
8683
 
8290
- // scripts/lakebase/env-file.ts
8684
+ // scripts/lakebase/branch-delete.ts
8291
8685
  init_cjs_shims();
8292
- var fs2 = __toESM(require("fs"), 1);
8293
- var path = __toESM(require("path"), 1);
8294
8686
 
8295
- // scripts/lakebase/databricks-cli.ts
8296
- var execFileP = (0, import_node_util.promisify)(import_node_child_process3.execFile);
8687
+ // scripts/lakebase/branch-utils.ts
8688
+ init_cjs_shims();
8297
8689
 
8298
8690
  // scripts/lakebase/branch-id.ts
8299
8691
  init_cjs_shims();
@@ -8314,7 +8706,7 @@ async function octokit() {
8314
8706
  const token = await resolveGitHubToken();
8315
8707
  return new Octokit2({ auth: token });
8316
8708
  }
8317
- function wrap(err, context) {
8709
+ function wrap2(err, context) {
8318
8710
  if (err instanceof RequestError) {
8319
8711
  throw new GitHubPullRequestError(`${context}: ${err.message}`, err.status);
8320
8712
  }
@@ -8342,7 +8734,7 @@ async function createPullRequest(args) {
8342
8734
  });
8343
8735
  return data.html_url || "";
8344
8736
  } catch (err) {
8345
- wrap(err, "Failed to create pull request");
8737
+ wrap2(err, "Failed to create pull request");
8346
8738
  }
8347
8739
  }
8348
8740
  async function getPullRequest(ownerRepo, headBranch) {
@@ -8437,7 +8829,7 @@ var RUNTIME_ARTIFACT_IGNORE = [
8437
8829
  // scripts/lakebase/scm-workflow-state.ts
8438
8830
  init_cjs_shims();
8439
8831
  var fs3 = __toESM(require("fs"), 1);
8440
- var path2 = __toESM(require("path"), 1);
8832
+ var path3 = __toESM(require("path"), 1);
8441
8833
  var import_node_child_process4 = require("child_process");
8442
8834
  function isGitTracked(projectDir, rel) {
8443
8835
  try {
@@ -8456,7 +8848,7 @@ function ensureWorkflowStateUntracked(projectDir) {
8456
8848
  } catch {
8457
8849
  }
8458
8850
  try {
8459
- const gitignore = path2.join(projectDir, ".gitignore");
8851
+ const gitignore = path3.join(projectDir, ".gitignore");
8460
8852
  const existing = fs3.existsSync(gitignore) ? fs3.readFileSync(gitignore, "utf8") : "";
8461
8853
  if (!existing.split("\n").some((l) => l.trim() === rel)) {
8462
8854
  const sep2 = existing === "" || existing.endsWith("\n") ? "" : "\n";
@@ -8484,7 +8876,7 @@ var STATE_INDEX = SCM_STATES.reduce(
8484
8876
  );
8485
8877
  var STATE_FILE_REL = ".lakebase/workflow-state.json";
8486
8878
  function stateFilePath(projectDir) {
8487
- return path2.join(projectDir, STATE_FILE_REL);
8879
+ return path3.join(projectDir, STATE_FILE_REL);
8488
8880
  }
8489
8881
  function readWorkflowState(projectDir) {
8490
8882
  const p = stateFilePath(projectDir);
@@ -8518,7 +8910,7 @@ function writeWorkflowState(projectDir, state) {
8518
8910
  ${summary}`);
8519
8911
  }
8520
8912
  ensureWorkflowStateUntracked(projectDir);
8521
- const dir = path2.join(projectDir, ".lakebase");
8913
+ const dir = path3.join(projectDir, ".lakebase");
8522
8914
  fs3.mkdirSync(dir, { recursive: true });
8523
8915
  const target = stateFilePath(projectDir);
8524
8916
  const tmp = `${target}.tmp`;
@@ -8755,6 +9147,7 @@ async function preparePr(args) {
8755
9147
  "no-github-remote"
8756
9148
  );
8757
9149
  }
9150
+ const ciFreshness = await ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo });
8758
9151
  const now = (args.now ?? (() => /* @__PURE__ */ new Date()))();
8759
9152
  let prUrl = args.prUrlOverride ?? "";
8760
9153
  let prCreated = false;
@@ -8799,7 +9192,7 @@ async function preparePr(args) {
8799
9192
  pushed_at: now.toISOString()
8800
9193
  };
8801
9194
  writeWorkflowState(args.projectDir, next);
8802
- return { state: next, prUrl, prCreated };
9195
+ return { state: next, prUrl, prCreated, ciFreshness };
8803
9196
  }
8804
9197
  async function ensureAheadOfParent(cwd, branch, parent) {
8805
9198
  try {
@@ -8947,7 +9340,7 @@ async function runScmPreparePrCli(argv) {
8947
9340
  `);
8948
9341
  return 0;
8949
9342
  }
8950
- const projectDir = path3.resolve(args.projectDir ?? process.cwd());
9343
+ const projectDir = path4.resolve(args.projectDir ?? process.cwd());
8951
9344
  try {
8952
9345
  const result = await preparePr({
8953
9346
  projectDir,