@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.
- package/dist/ci-secrets-CnGrdQV-.d.cts +84 -0
- package/dist/ci-secrets-CnGrdQV-.d.ts +84 -0
- package/dist/scripts/index.cjs +2230 -2052
- package/dist/scripts/index.d.cts +3 -2
- package/dist/scripts/index.d.ts +3 -2
- package/dist/scripts/index.js +305 -134
- package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2 -2
- package/dist/scripts/lakebase/ci-resolve-branch.cli.js +2 -2
- package/dist/scripts/lakebase/collapse-heads.cli.cjs +2 -2
- package/dist/scripts/lakebase/collapse-heads.cli.js +2 -2
- package/dist/scripts/lakebase/detect-language.cli.cjs +2 -2
- package/dist/scripts/lakebase/detect-language.cli.js +2 -2
- package/dist/scripts/lakebase/doctor.cli.cjs +2 -2
- package/dist/scripts/lakebase/doctor.cli.js +2 -2
- package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
- package/dist/scripts/lakebase/get-connection.cli.js +2 -2
- package/dist/scripts/lakebase/index.cjs +2216 -2050
- package/dist/scripts/lakebase/index.d.cts +37 -11
- package/dist/scripts/lakebase/index.d.ts +37 -11
- package/dist/scripts/lakebase/index.js +295 -130
- package/dist/scripts/lakebase/infra-runner.cli.cjs +2 -2
- package/dist/scripts/lakebase/infra-runner.cli.js +2 -2
- package/dist/scripts/lakebase/new-migration.cli.cjs +2 -2
- package/dist/scripts/lakebase/new-migration.cli.js +2 -2
- package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
- package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
- package/dist/scripts/lakebase/schema-migrate.cli.cjs +2 -2
- package/dist/scripts/lakebase/schema-migrate.cli.js +2 -2
- package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-claim-feature.cli.js +2 -2
- package/dist/scripts/lakebase/scm-doctor.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-doctor.cli.js +2 -2
- package/dist/scripts/lakebase/scm-merge.cli.cjs +2345 -1994
- package/dist/scripts/lakebase/scm-merge.cli.js +425 -74
- package/dist/scripts/lakebase/scm-prepare-pr.cli.cjs +479 -86
- package/dist/scripts/lakebase/scm-prepare-pr.cli.js +479 -86
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2 -2
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +2 -2
- package/dist/scripts/lakebase/sync-ci-secrets.cli.cjs +56 -30
- package/dist/scripts/lakebase/sync-ci-secrets.cli.js +56 -30
- package/dist/scripts/util/index.cjs +142 -25
- package/dist/scripts/util/index.d.cts +2 -27
- package/dist/scripts/util/index.d.ts +2 -27
- package/dist/scripts/util/index.js +136 -25
- package/package.json +1 -1
- package/scripts/lakebase/create-project.ts +2 -2
- package/scripts/lakebase/scm-merge.ts +112 -0
- package/scripts/lakebase/scm-prepare-pr.ts +10 -1
- package/scripts/lakebase/sync-ci-secrets.cli.ts +2 -2
- package/scripts/util/ci-secrets.ts +212 -26
- package/templates/project/common/.gitignore.base +4 -6
- 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-merge.cli.ts
|
|
1459
1459
|
init_esm_shims();
|
|
1460
|
-
import * as
|
|
1460
|
+
import * as path14 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 = (
|
|
2552
|
+
var generateMessage = (path15, cursorValue) => `The cursor at "${path15.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,
|
|
2593
|
+
var deepFindPathToProperty = (object, searchProp, path15 = []) => {
|
|
2594
2594
|
for (const key of Object.keys(object)) {
|
|
2595
|
-
const currentPath = [...
|
|
2595
|
+
const currentPath = [...path15, 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, path14 = []) => {
|
|
|
2610
2610
|
}
|
|
2611
2611
|
return [];
|
|
2612
2612
|
};
|
|
2613
|
-
var get = (object,
|
|
2614
|
-
return
|
|
2613
|
+
var get = (object, path15) => {
|
|
2614
|
+
return path15.reduce((current, nextProperty) => current[nextProperty], object);
|
|
2615
2615
|
};
|
|
2616
|
-
var set = (object,
|
|
2617
|
-
const lastProperty =
|
|
2618
|
-
const parentPath = [...
|
|
2616
|
+
var set = (object, path15, mutator) => {
|
|
2617
|
+
const lastProperty = path15[path15.length - 1];
|
|
2618
|
+
const parentPath = [...path15].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
|
|
2671
|
-
const nodesPath = [...
|
|
2670
|
+
const path15 = findPaginatedResourcePath(response1);
|
|
2671
|
+
const nodesPath = [...path15, "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 = [...
|
|
2678
|
+
const edgesPath = [...path15, "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 = [...
|
|
2685
|
+
const pageInfoPath = [...path15, "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
|
-
(
|
|
5106
|
+
(path15) => path15.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(
|
|
8382
|
-
if (!
|
|
8383
|
-
const leaf =
|
|
8381
|
+
function branchNameFromResourcePath(path15) {
|
|
8382
|
+
if (!path15.includes("/branches/")) return null;
|
|
8383
|
+
const leaf = path15.split("/branches/").pop();
|
|
8384
8384
|
if (!leaf) return null;
|
|
8385
8385
|
try {
|
|
8386
8386
|
return asBranchName(leaf);
|
|
@@ -8609,6 +8609,84 @@ function wrap(err, context) {
|
|
|
8609
8609
|
}
|
|
8610
8610
|
throw new GitHubPullRequestError(context);
|
|
8611
8611
|
}
|
|
8612
|
+
async function getPullRequest(ownerRepo, headBranch) {
|
|
8613
|
+
try {
|
|
8614
|
+
const { owner, repo } = parseOwnerRepo(ownerRepo);
|
|
8615
|
+
const ok = await octokit();
|
|
8616
|
+
const { data: pulls } = await ok.rest.pulls.list({
|
|
8617
|
+
owner,
|
|
8618
|
+
repo,
|
|
8619
|
+
state: "open",
|
|
8620
|
+
head: `${owner}:${headBranch}`,
|
|
8621
|
+
per_page: 1
|
|
8622
|
+
});
|
|
8623
|
+
if (pulls.length === 0) return void 0;
|
|
8624
|
+
const { data: pr } = await ok.rest.pulls.get({
|
|
8625
|
+
owner,
|
|
8626
|
+
repo,
|
|
8627
|
+
pull_number: pulls[0].number
|
|
8628
|
+
});
|
|
8629
|
+
if (pr.state !== "open") return void 0;
|
|
8630
|
+
let checks = [];
|
|
8631
|
+
let ciStatus = "pending";
|
|
8632
|
+
const headSha = pr.head?.sha;
|
|
8633
|
+
if (headSha) {
|
|
8634
|
+
try {
|
|
8635
|
+
const { data: checksData } = await ok.rest.checks.listForRef({
|
|
8636
|
+
owner,
|
|
8637
|
+
repo,
|
|
8638
|
+
ref: headSha
|
|
8639
|
+
});
|
|
8640
|
+
const runs = checksData.check_runs || [];
|
|
8641
|
+
checks = runs.map((c) => ({
|
|
8642
|
+
name: c.name || "unknown",
|
|
8643
|
+
status: (c.status || "").toUpperCase(),
|
|
8644
|
+
conclusion: (c.conclusion || "").toUpperCase(),
|
|
8645
|
+
detailsUrl: c.details_url || void 0
|
|
8646
|
+
}));
|
|
8647
|
+
ciStatus = parseCiStatus(runs);
|
|
8648
|
+
} catch {
|
|
8649
|
+
ciStatus = "pending";
|
|
8650
|
+
}
|
|
8651
|
+
}
|
|
8652
|
+
return {
|
|
8653
|
+
number: pr.number,
|
|
8654
|
+
title: pr.title,
|
|
8655
|
+
url: pr.html_url || "",
|
|
8656
|
+
state: (pr.state || "open").toUpperCase(),
|
|
8657
|
+
isDraft: pr.draft || false,
|
|
8658
|
+
ciStatus,
|
|
8659
|
+
checks,
|
|
8660
|
+
mergeable: pr.mergeable,
|
|
8661
|
+
mergeableState: pr.mergeable_state,
|
|
8662
|
+
headBranch: pr.head?.ref || headBranch,
|
|
8663
|
+
baseBranch: pr.base?.ref || "",
|
|
8664
|
+
body: pr.body || void 0,
|
|
8665
|
+
additions: pr.additions,
|
|
8666
|
+
deletions: pr.deletions,
|
|
8667
|
+
changedFiles: pr.changed_files
|
|
8668
|
+
};
|
|
8669
|
+
} catch {
|
|
8670
|
+
return void 0;
|
|
8671
|
+
}
|
|
8672
|
+
}
|
|
8673
|
+
function parseCiStatus(rawChecks) {
|
|
8674
|
+
if (rawChecks.length === 0) return "pending";
|
|
8675
|
+
const latestByName = /* @__PURE__ */ new Map();
|
|
8676
|
+
for (const c of rawChecks) {
|
|
8677
|
+
latestByName.set(c.name || "unknown", c);
|
|
8678
|
+
}
|
|
8679
|
+
const states = Array.from(latestByName.values()).map(
|
|
8680
|
+
(c) => (c.conclusion || c.status || "").toUpperCase()
|
|
8681
|
+
);
|
|
8682
|
+
if (states.some((s) => s === "FAILURE" || s === "ERROR" || s === "ACTION_REQUIRED")) {
|
|
8683
|
+
return "failure";
|
|
8684
|
+
}
|
|
8685
|
+
if (states.every((s) => s === "SUCCESS" || s === "NEUTRAL" || s === "SKIPPED")) {
|
|
8686
|
+
return "success";
|
|
8687
|
+
}
|
|
8688
|
+
return "pending";
|
|
8689
|
+
}
|
|
8612
8690
|
async function mergePullRequest(args) {
|
|
8613
8691
|
const method = args.method ?? "merge";
|
|
8614
8692
|
const deleteRemoteBranch = args.deleteRemoteBranch !== false;
|
|
@@ -8739,6 +8817,219 @@ async function getOwnerRepo(cwd) {
|
|
|
8739
8817
|
}
|
|
8740
8818
|
}
|
|
8741
8819
|
|
|
8820
|
+
// scripts/util/ci-secrets.ts
|
|
8821
|
+
init_esm_shims();
|
|
8822
|
+
import * as path3 from "path";
|
|
8823
|
+
|
|
8824
|
+
// scripts/github/secrets.ts
|
|
8825
|
+
init_esm_shims();
|
|
8826
|
+
import sodium from "tweetsodium";
|
|
8827
|
+
var GitHubSecretsError = class extends Error {
|
|
8828
|
+
status;
|
|
8829
|
+
constructor(message, status) {
|
|
8830
|
+
super(message);
|
|
8831
|
+
this.name = "GitHubSecretsError";
|
|
8832
|
+
this.status = status;
|
|
8833
|
+
}
|
|
8834
|
+
};
|
|
8835
|
+
async function getOctokit() {
|
|
8836
|
+
const token = await resolveGitHubToken();
|
|
8837
|
+
return new Octokit2({ auth: token });
|
|
8838
|
+
}
|
|
8839
|
+
function wrap2(err, context) {
|
|
8840
|
+
if (err instanceof RequestError) {
|
|
8841
|
+
throw new GitHubSecretsError(`${context}: ${err.message}`, err.status);
|
|
8842
|
+
}
|
|
8843
|
+
if (err instanceof Error) {
|
|
8844
|
+
throw new GitHubSecretsError(`${context}: ${err.message}`);
|
|
8845
|
+
}
|
|
8846
|
+
throw new GitHubSecretsError(context);
|
|
8847
|
+
}
|
|
8848
|
+
function encryptSecret(publicKey, secretValue) {
|
|
8849
|
+
const keyBytes = Buffer.from(publicKey, "base64");
|
|
8850
|
+
const messageBytes = Buffer.from(secretValue);
|
|
8851
|
+
const encryptedBytes = sodium.seal(messageBytes, keyBytes);
|
|
8852
|
+
return Buffer.from(encryptedBytes).toString("base64");
|
|
8853
|
+
}
|
|
8854
|
+
async function setRepoSecret(ownerRepo, secretName, secretValue) {
|
|
8855
|
+
try {
|
|
8856
|
+
const { owner, repo } = parseOwnerRepo(ownerRepo);
|
|
8857
|
+
const octokit2 = await getOctokit();
|
|
8858
|
+
const { data: keyData } = await octokit2.rest.actions.getRepoPublicKey({ owner, repo });
|
|
8859
|
+
const encryptedValue = encryptSecret(keyData.key, secretValue);
|
|
8860
|
+
await octokit2.rest.actions.createOrUpdateRepoSecret({
|
|
8861
|
+
owner,
|
|
8862
|
+
repo,
|
|
8863
|
+
secret_name: secretName,
|
|
8864
|
+
encrypted_value: encryptedValue,
|
|
8865
|
+
key_id: keyData.key_id
|
|
8866
|
+
});
|
|
8867
|
+
} catch (err) {
|
|
8868
|
+
if (err instanceof GitHubSecretsError) throw err;
|
|
8869
|
+
wrap2(err, `Failed to set secret ${secretName} on ${ownerRepo}`);
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
async function setRepoSecrets(ownerRepo, secrets) {
|
|
8873
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
8874
|
+
if (!value) {
|
|
8875
|
+
throw new GitHubSecretsError(`Missing value for secret ${name}`);
|
|
8876
|
+
}
|
|
8877
|
+
}
|
|
8878
|
+
for (const [name, value] of Object.entries(secrets)) {
|
|
8879
|
+
await setRepoSecret(ownerRepo, name, value);
|
|
8880
|
+
}
|
|
8881
|
+
}
|
|
8882
|
+
async function listSecretNames(ownerRepo) {
|
|
8883
|
+
try {
|
|
8884
|
+
const { owner, repo } = parseOwnerRepo(ownerRepo);
|
|
8885
|
+
const octokit2 = await getOctokit();
|
|
8886
|
+
const { data } = await octokit2.rest.actions.listRepoSecrets({ owner, repo });
|
|
8887
|
+
return data.secrets.map((s) => s.name);
|
|
8888
|
+
} catch {
|
|
8889
|
+
return [];
|
|
8890
|
+
}
|
|
8891
|
+
}
|
|
8892
|
+
|
|
8893
|
+
// scripts/util/ci-secrets.ts
|
|
8894
|
+
var REQUIRED_CI_SECRETS = ["DATABRICKS_HOST", "LAKEBASE_PROJECT_ID", "DATABRICKS_TOKEN"];
|
|
8895
|
+
var CI_TOKEN_LIFETIME_SECONDS = 7776e3;
|
|
8896
|
+
var CI_TOKEN_REMINT_MARGIN_SECONDS = 86400;
|
|
8897
|
+
function ciTokenComment(ownerRepo) {
|
|
8898
|
+
const repoName = ownerRepo.includes("/") ? ownerRepo.slice(ownerRepo.lastIndexOf("/") + 1) : ownerRepo;
|
|
8899
|
+
return `GitHub Actions (${repoName})`;
|
|
8900
|
+
}
|
|
8901
|
+
async function missingCiSecrets(ownerRepo) {
|
|
8902
|
+
const present = new Set(await listSecretNames(ownerRepo));
|
|
8903
|
+
return REQUIRED_CI_SECRETS.filter((n) => !present.has(n));
|
|
8904
|
+
}
|
|
8905
|
+
async function mintCiToken(args) {
|
|
8906
|
+
try {
|
|
8907
|
+
const raw = await runDatabricks(
|
|
8908
|
+
["tokens", "create", "--comment", args.comment, "--lifetime-seconds", String(args.lifetimeSeconds), "-o", "json"],
|
|
8909
|
+
{ host: args.databricksHost, cwd: args.projectDir, timeout: 3e4 }
|
|
8910
|
+
);
|
|
8911
|
+
const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
|
|
8912
|
+
const token = parsed.token_value || parsed.token || "";
|
|
8913
|
+
if (token) return token;
|
|
8914
|
+
} catch {
|
|
8915
|
+
}
|
|
8916
|
+
try {
|
|
8917
|
+
const raw = await runDatabricks(["auth", "token", "-o", "json"], {
|
|
8918
|
+
host: args.databricksHost,
|
|
8919
|
+
cwd: args.projectDir,
|
|
8920
|
+
timeout: 3e4
|
|
8921
|
+
});
|
|
8922
|
+
const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("{"))));
|
|
8923
|
+
return parsed.access_token || "";
|
|
8924
|
+
} catch {
|
|
8925
|
+
return "";
|
|
8926
|
+
}
|
|
8927
|
+
}
|
|
8928
|
+
async function syncCiSecrets(args) {
|
|
8929
|
+
const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
|
|
8930
|
+
if (!ownerRepo) {
|
|
8931
|
+
throw new Error("Could not resolve GitHub repository from git remote");
|
|
8932
|
+
}
|
|
8933
|
+
if (!args.databricksHost) {
|
|
8934
|
+
throw new Error("syncCiSecrets: databricksHost is required");
|
|
8935
|
+
}
|
|
8936
|
+
if (!args.lakebaseProjectId) {
|
|
8937
|
+
throw new Error("syncCiSecrets: lakebaseProjectId is required");
|
|
8938
|
+
}
|
|
8939
|
+
const lifetime = args.lifetimeSeconds ?? CI_TOKEN_LIFETIME_SECONDS;
|
|
8940
|
+
const comment = args.comment ?? ciTokenComment(ownerRepo);
|
|
8941
|
+
const secrets = {
|
|
8942
|
+
DATABRICKS_HOST: args.databricksHost,
|
|
8943
|
+
LAKEBASE_PROJECT_ID: args.lakebaseProjectId
|
|
8944
|
+
};
|
|
8945
|
+
const token = await mintCiToken({
|
|
8946
|
+
databricksHost: args.databricksHost,
|
|
8947
|
+
projectDir: args.projectDir,
|
|
8948
|
+
comment,
|
|
8949
|
+
lifetimeSeconds: lifetime
|
|
8950
|
+
});
|
|
8951
|
+
if (token) secrets.DATABRICKS_TOKEN = token;
|
|
8952
|
+
await setRepoSecrets(ownerRepo, secrets);
|
|
8953
|
+
}
|
|
8954
|
+
async function ciTokenExpiry(args) {
|
|
8955
|
+
const comment = ciTokenComment(args.ownerRepo);
|
|
8956
|
+
let raw;
|
|
8957
|
+
try {
|
|
8958
|
+
raw = await runDatabricks(["tokens", "list", "-o", "json"], {
|
|
8959
|
+
host: args.databricksHost,
|
|
8960
|
+
cwd: args.projectDir,
|
|
8961
|
+
timeout: 3e4
|
|
8962
|
+
});
|
|
8963
|
+
} catch {
|
|
8964
|
+
return null;
|
|
8965
|
+
}
|
|
8966
|
+
let infos;
|
|
8967
|
+
try {
|
|
8968
|
+
const parsed = JSON.parse(raw.slice(Math.max(0, raw.indexOf("["))));
|
|
8969
|
+
infos = Array.isArray(parsed) ? parsed : [];
|
|
8970
|
+
} catch {
|
|
8971
|
+
return null;
|
|
8972
|
+
}
|
|
8973
|
+
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);
|
|
8974
|
+
if (expiries.length === 0) return null;
|
|
8975
|
+
return Math.max(...expiries);
|
|
8976
|
+
}
|
|
8977
|
+
async function ensureCiSecretsFresh(args) {
|
|
8978
|
+
const now = args.now ?? Date.now;
|
|
8979
|
+
const marginMs = (args.marginSeconds ?? CI_TOKEN_REMINT_MARGIN_SECONDS) * 1e3;
|
|
8980
|
+
const ownerRepo = args.ownerRepo ?? await getOwnerRepo(args.projectDir);
|
|
8981
|
+
if (!ownerRepo) {
|
|
8982
|
+
throw new Error("Could not resolve GitHub repository from git remote");
|
|
8983
|
+
}
|
|
8984
|
+
const sync = () => syncCiSecrets({
|
|
8985
|
+
projectDir: args.projectDir,
|
|
8986
|
+
databricksHost: args.databricksHost,
|
|
8987
|
+
lakebaseProjectId: args.lakebaseProjectId,
|
|
8988
|
+
ownerRepo
|
|
8989
|
+
});
|
|
8990
|
+
const missing = await missingCiSecrets(ownerRepo);
|
|
8991
|
+
if (missing.length > 0) {
|
|
8992
|
+
await sync();
|
|
8993
|
+
return { action: "provisioned", reason: `CI secret(s) were missing (${missing.join(", ")}); provisioned.` };
|
|
8994
|
+
}
|
|
8995
|
+
const expiry = await ciTokenExpiry({ projectDir: args.projectDir, databricksHost: args.databricksHost, ownerRepo });
|
|
8996
|
+
if (expiry === null) {
|
|
8997
|
+
await sync();
|
|
8998
|
+
return { action: "reminted", reason: "no live CI token found (expired or minted under a different identity); re-minted." };
|
|
8999
|
+
}
|
|
9000
|
+
if (expiry !== Number.POSITIVE_INFINITY && expiry < now() + marginMs) {
|
|
9001
|
+
await sync();
|
|
9002
|
+
const hrs = Math.max(0, Math.round((expiry - now()) / 36e5));
|
|
9003
|
+
return { action: "reminted", reason: `CI token expires in ~${hrs}h (within the re-mint margin); re-minted.` };
|
|
9004
|
+
}
|
|
9005
|
+
return { action: "ok", reason: "CI token is current." };
|
|
9006
|
+
}
|
|
9007
|
+
async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
|
|
9008
|
+
const envPath = path3.join(projectDir, ".env");
|
|
9009
|
+
const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
|
|
9010
|
+
const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
|
|
9011
|
+
if (!databricksHost || !lakebaseProjectId) {
|
|
9012
|
+
return {
|
|
9013
|
+
action: "skipped",
|
|
9014
|
+
reason: "CI-auth preflight skipped: .env is missing DATABRICKS_HOST / LAKEBASE_PROJECT_ID."
|
|
9015
|
+
};
|
|
9016
|
+
}
|
|
9017
|
+
try {
|
|
9018
|
+
return await ensureCiSecretsFresh({
|
|
9019
|
+
projectDir,
|
|
9020
|
+
databricksHost,
|
|
9021
|
+
lakebaseProjectId,
|
|
9022
|
+
ownerRepo: opts?.ownerRepo,
|
|
9023
|
+
marginSeconds: opts?.marginSeconds
|
|
9024
|
+
});
|
|
9025
|
+
} catch (err) {
|
|
9026
|
+
return {
|
|
9027
|
+
action: "failed",
|
|
9028
|
+
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.`
|
|
9029
|
+
};
|
|
9030
|
+
}
|
|
9031
|
+
}
|
|
9032
|
+
|
|
8742
9033
|
// scripts/util/poll-until.ts
|
|
8743
9034
|
init_esm_shims();
|
|
8744
9035
|
|
|
@@ -8833,11 +9124,11 @@ async function resolveGitBase(parentBranch, cwd) {
|
|
|
8833
9124
|
// scripts/lakebase/workflow-drift.ts
|
|
8834
9125
|
init_esm_shims();
|
|
8835
9126
|
import * as fs3 from "fs";
|
|
8836
|
-
import * as
|
|
9127
|
+
import * as path4 from "path";
|
|
8837
9128
|
function findKitTemplatesDir(start) {
|
|
8838
9129
|
let dir = start;
|
|
8839
9130
|
for (let i = 0; i < 6; i++) {
|
|
8840
|
-
const candidate =
|
|
9131
|
+
const candidate = path4.join(
|
|
8841
9132
|
dir,
|
|
8842
9133
|
"templates",
|
|
8843
9134
|
"project",
|
|
@@ -8846,7 +9137,7 @@ function findKitTemplatesDir(start) {
|
|
|
8846
9137
|
"workflows"
|
|
8847
9138
|
);
|
|
8848
9139
|
if (fs3.existsSync(candidate)) return candidate;
|
|
8849
|
-
const parent =
|
|
9140
|
+
const parent = path4.dirname(dir);
|
|
8850
9141
|
if (parent === dir) break;
|
|
8851
9142
|
dir = parent;
|
|
8852
9143
|
}
|
|
@@ -8870,13 +9161,13 @@ function unifiedDiff(name, projectContent, templateContent) {
|
|
|
8870
9161
|
return out.join("\n");
|
|
8871
9162
|
}
|
|
8872
9163
|
function detectWorkflowDrift(args) {
|
|
8873
|
-
const projectWorkflowsDir =
|
|
9164
|
+
const projectWorkflowsDir = path4.join(
|
|
8874
9165
|
args.projectDir,
|
|
8875
9166
|
".github",
|
|
8876
9167
|
"workflows"
|
|
8877
9168
|
);
|
|
8878
|
-
const here =
|
|
8879
|
-
const kitWorkflowsDir = args.kitDir ?
|
|
9169
|
+
const here = path4.dirname(new URL(import.meta.url).pathname);
|
|
9170
|
+
const kitWorkflowsDir = args.kitDir ? path4.join(
|
|
8880
9171
|
args.kitDir,
|
|
8881
9172
|
"templates",
|
|
8882
9173
|
"project",
|
|
@@ -8891,8 +9182,8 @@ function detectWorkflowDrift(args) {
|
|
|
8891
9182
|
const files = [];
|
|
8892
9183
|
for (const name of templateFiles) {
|
|
8893
9184
|
seen.add(name);
|
|
8894
|
-
const projectPath2 =
|
|
8895
|
-
const templatePath =
|
|
9185
|
+
const projectPath2 = path4.join(projectWorkflowsDir, name);
|
|
9186
|
+
const templatePath = path4.join(kitWorkflowsDir, name);
|
|
8896
9187
|
if (!fs3.existsSync(projectPath2)) {
|
|
8897
9188
|
files.push({ name, status: "missing" });
|
|
8898
9189
|
continue;
|
|
@@ -8929,10 +9220,10 @@ function detectWorkflowDrift(args) {
|
|
|
8929
9220
|
function readKitVersion(kitWorkflowsDir) {
|
|
8930
9221
|
let dir = kitWorkflowsDir;
|
|
8931
9222
|
for (let i = 0; i < 5; i++) {
|
|
8932
|
-
dir =
|
|
9223
|
+
dir = path4.dirname(dir);
|
|
8933
9224
|
}
|
|
8934
9225
|
try {
|
|
8935
|
-
const raw = fs3.readFileSync(
|
|
9226
|
+
const raw = fs3.readFileSync(path4.join(dir, "package.json"), "utf-8");
|
|
8936
9227
|
const pkg = JSON.parse(raw);
|
|
8937
9228
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
8938
9229
|
} catch {
|
|
@@ -8943,13 +9234,13 @@ function applyPlaceholders(content, version) {
|
|
|
8943
9234
|
return content.replace(/\{\{LAKEBASE_SCM_UTILS_VERSION\}\}/g, version);
|
|
8944
9235
|
}
|
|
8945
9236
|
function updateWorkflows(args) {
|
|
8946
|
-
const projectWorkflowsDir =
|
|
9237
|
+
const projectWorkflowsDir = path4.join(
|
|
8947
9238
|
args.projectDir,
|
|
8948
9239
|
".github",
|
|
8949
9240
|
"workflows"
|
|
8950
9241
|
);
|
|
8951
|
-
const here =
|
|
8952
|
-
const kitWorkflowsDir = args.kitDir ?
|
|
9242
|
+
const here = path4.dirname(new URL(import.meta.url).pathname);
|
|
9243
|
+
const kitWorkflowsDir = args.kitDir ? path4.join(
|
|
8953
9244
|
args.kitDir,
|
|
8954
9245
|
"templates",
|
|
8955
9246
|
"project",
|
|
@@ -8970,8 +9261,8 @@ function updateWorkflows(args) {
|
|
|
8970
9261
|
const files = [];
|
|
8971
9262
|
for (const name of templateFiles) {
|
|
8972
9263
|
seen.add(name);
|
|
8973
|
-
const projectPath2 =
|
|
8974
|
-
const templatePath =
|
|
9264
|
+
const projectPath2 = path4.join(projectWorkflowsDir, name);
|
|
9265
|
+
const templatePath = path4.join(kitWorkflowsDir, name);
|
|
8975
9266
|
const templateRaw = fs3.readFileSync(templatePath, "utf-8");
|
|
8976
9267
|
const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
|
|
8977
9268
|
const existed = fs3.existsSync(projectPath2);
|
|
@@ -8992,7 +9283,7 @@ function updateWorkflows(args) {
|
|
|
8992
9283
|
if (pruneExtras) {
|
|
8993
9284
|
for (const name of projectFiles) {
|
|
8994
9285
|
if (seen.has(name)) continue;
|
|
8995
|
-
const projectPath2 =
|
|
9286
|
+
const projectPath2 = path4.join(projectWorkflowsDir, name);
|
|
8996
9287
|
if (!dryRun) {
|
|
8997
9288
|
fs3.unlinkSync(projectPath2);
|
|
8998
9289
|
}
|
|
@@ -9013,7 +9304,7 @@ function updateWorkflows(args) {
|
|
|
9013
9304
|
// scripts/lakebase/scm-workflow-state.ts
|
|
9014
9305
|
init_esm_shims();
|
|
9015
9306
|
import * as fs4 from "fs";
|
|
9016
|
-
import * as
|
|
9307
|
+
import * as path5 from "path";
|
|
9017
9308
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
9018
9309
|
function isGitTracked(projectDir, rel) {
|
|
9019
9310
|
try {
|
|
@@ -9032,7 +9323,7 @@ function ensureWorkflowStateUntracked(projectDir) {
|
|
|
9032
9323
|
} catch {
|
|
9033
9324
|
}
|
|
9034
9325
|
try {
|
|
9035
|
-
const gitignore =
|
|
9326
|
+
const gitignore = path5.join(projectDir, ".gitignore");
|
|
9036
9327
|
const existing = fs4.existsSync(gitignore) ? fs4.readFileSync(gitignore, "utf8") : "";
|
|
9037
9328
|
if (!existing.split("\n").some((l) => l.trim() === rel)) {
|
|
9038
9329
|
const sep2 = existing === "" || existing.endsWith("\n") ? "" : "\n";
|
|
@@ -9060,7 +9351,7 @@ var STATE_INDEX = SCM_STATES.reduce(
|
|
|
9060
9351
|
);
|
|
9061
9352
|
var STATE_FILE_REL = ".lakebase/workflow-state.json";
|
|
9062
9353
|
function stateFilePath(projectDir) {
|
|
9063
|
-
return
|
|
9354
|
+
return path5.join(projectDir, STATE_FILE_REL);
|
|
9064
9355
|
}
|
|
9065
9356
|
function readWorkflowState(projectDir) {
|
|
9066
9357
|
const p = stateFilePath(projectDir);
|
|
@@ -9094,7 +9385,7 @@ function writeWorkflowState(projectDir, state) {
|
|
|
9094
9385
|
${summary}`);
|
|
9095
9386
|
}
|
|
9096
9387
|
ensureWorkflowStateUntracked(projectDir);
|
|
9097
|
-
const dir =
|
|
9388
|
+
const dir = path5.join(projectDir, ".lakebase");
|
|
9098
9389
|
fs4.mkdirSync(dir, { recursive: true });
|
|
9099
9390
|
const target = stateFilePath(projectDir);
|
|
9100
9391
|
const tmp = `${target}.tmp`;
|
|
@@ -9303,6 +9594,48 @@ function shaMigratePredicate(mergeCommitSha) {
|
|
|
9303
9594
|
return !!run.headSha && run.headSha === mergeCommitSha;
|
|
9304
9595
|
};
|
|
9305
9596
|
}
|
|
9597
|
+
var PROMOTE_RUNSTATE_CONFLICT = /(^|\/)\.consort\/(features\/[^/]+\/)?pipeline\.json$/;
|
|
9598
|
+
async function reconcilePromoteRunState(projectDir, baseBranch) {
|
|
9599
|
+
const o = { cwd: projectDir, timeout: 3e4 };
|
|
9600
|
+
const dirty = (await exec2("git status --porcelain", o).catch(() => "")).split("\n").map((l) => l.slice(3).trim()).filter(Boolean);
|
|
9601
|
+
const nonRunStateDirty = dirty.filter((p) => !p.startsWith(".consort/"));
|
|
9602
|
+
if (nonRunStateDirty.length > 0) {
|
|
9603
|
+
throw new ScmMergeError(
|
|
9604
|
+
`working tree has uncommitted non-run-state changes (${nonRunStateDirty.slice(0, 5).join(", ")}${nonRunStateDirty.length > 5 ? ", \u2026" : ""}); commit or stash before promoting.`,
|
|
9605
|
+
"promote-conflict"
|
|
9606
|
+
);
|
|
9607
|
+
}
|
|
9608
|
+
if (dirty.length > 0) {
|
|
9609
|
+
await exec2(`git add ${shellEscape(".consort")}`, o);
|
|
9610
|
+
await exec2(`git commit -m ${shellEscape("chore(run): checkpoint run state before promotion")}`, o);
|
|
9611
|
+
}
|
|
9612
|
+
await exec2(`git fetch origin ${shellEscape(baseBranch)}`, o).catch(() => {
|
|
9613
|
+
});
|
|
9614
|
+
let conflicted = false;
|
|
9615
|
+
try {
|
|
9616
|
+
await exec2(`git merge --no-ff -m ${shellEscape(`merge ${baseBranch} for promotion`)} ${shellEscape(`origin/${baseBranch}`)}`, o);
|
|
9617
|
+
} catch {
|
|
9618
|
+
conflicted = true;
|
|
9619
|
+
}
|
|
9620
|
+
if (!conflicted) return { reconciled: false };
|
|
9621
|
+
const u = (await exec2("git diff --name-only --diff-filter=U", o).catch(() => "")).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
9622
|
+
const other = u.filter((p) => !PROMOTE_RUNSTATE_CONFLICT.test(p));
|
|
9623
|
+
if (u.length === 0 || other.length > 0) {
|
|
9624
|
+
await exec2("git merge --abort", o).catch(() => {
|
|
9625
|
+
});
|
|
9626
|
+
throw new ScmMergeError(
|
|
9627
|
+
other.length > 0 ? `promotion conflicts on non-ledger file(s): ${other.join(", ")}. Resolve the real divergence manually, then re-run the promote.` : `promotion merge failed with no resolvable conflicts; resolve manually and re-run.`,
|
|
9628
|
+
"promote-conflict"
|
|
9629
|
+
);
|
|
9630
|
+
}
|
|
9631
|
+
for (const p of u) {
|
|
9632
|
+
await exec2(`git checkout --ours -- ${shellEscape(p)}`, o);
|
|
9633
|
+
await exec2(`git add -- ${shellEscape(p)}`, o);
|
|
9634
|
+
}
|
|
9635
|
+
await exec2(`git commit -m ${shellEscape(`merge ${baseBranch} for promotion (pipeline.json ledger kept at run state)`)}`, o);
|
|
9636
|
+
await pushCurrentBranchForPr({ cwd: projectDir });
|
|
9637
|
+
return { reconciled: true, detail: `reconciled ${u.length} ledger path(s) to the run side + pushed` };
|
|
9638
|
+
}
|
|
9306
9639
|
async function defaultRefreshPromoteWorkflows(projectDir) {
|
|
9307
9640
|
const drift = detectWorkflowDrift({ projectDir });
|
|
9308
9641
|
const touched = drift.files.filter((f) => f.status === "drifted").map((f) => f.name);
|
|
@@ -9392,6 +9725,24 @@ async function mergeFeature(args) {
|
|
|
9392
9725
|
);
|
|
9393
9726
|
}
|
|
9394
9727
|
}
|
|
9728
|
+
{
|
|
9729
|
+
const ensure = args.ensureCiFresh ?? ((repo) => ensureCiSecretsFreshFromEnv(args.projectDir, { ownerRepo: repo }));
|
|
9730
|
+
try {
|
|
9731
|
+
const r = await ensure(ownerRepo);
|
|
9732
|
+
if (r.action !== "ok" && r.action !== "skipped") preflightNotes.push(`CI-auth preflight: ${r.reason}`);
|
|
9733
|
+
} catch (err) {
|
|
9734
|
+
preflightNotes.push(`CI-auth preflight skipped (${err instanceof Error ? err.message : String(err)}); if the promote CI fails on auth, run lakebase-sync-ci-secrets.`);
|
|
9735
|
+
}
|
|
9736
|
+
}
|
|
9737
|
+
{
|
|
9738
|
+
const fetchState = args.fetchPrState ?? ((o, h) => getPullRequest(o, h));
|
|
9739
|
+
const prState = await fetchState(ownerRepo, current.branch).catch(() => void 0);
|
|
9740
|
+
if (prState?.mergeableState === "dirty") {
|
|
9741
|
+
const reconcile = args.reconcileRunState ?? ((base) => reconcilePromoteRunState(args.projectDir, base));
|
|
9742
|
+
const r = await reconcile(gitBase);
|
|
9743
|
+
if (r.reconciled) preflightNotes.push(`Reconciled a pipeline.json-ledger promotion conflict to the run side${r.detail ? ` (${r.detail})` : ""}.`);
|
|
9744
|
+
}
|
|
9745
|
+
}
|
|
9395
9746
|
let paired;
|
|
9396
9747
|
try {
|
|
9397
9748
|
paired = await mergePairedPullRequest({
|
|
@@ -9601,7 +9952,7 @@ function shellEscape(s) {
|
|
|
9601
9952
|
// scripts/lakebase/schema-migrate.ts
|
|
9602
9953
|
init_esm_shims();
|
|
9603
9954
|
import * as fs11 from "fs";
|
|
9604
|
-
import * as
|
|
9955
|
+
import * as path13 from "path";
|
|
9605
9956
|
|
|
9606
9957
|
// scripts/lakebase/get-connection.ts
|
|
9607
9958
|
init_esm_shims();
|
|
@@ -9621,21 +9972,21 @@ var CONSORT_VERSION_ENV = "CONSORT_VERSION";
|
|
|
9621
9972
|
// scripts/lakebase/self-version.ts
|
|
9622
9973
|
init_esm_shims();
|
|
9623
9974
|
import * as fs5 from "fs";
|
|
9624
|
-
import * as
|
|
9975
|
+
import * as path6 from "path";
|
|
9625
9976
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9626
9977
|
var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
9627
9978
|
var cached;
|
|
9628
9979
|
function substrateSelfVersion() {
|
|
9629
9980
|
if (cached !== void 0) return cached;
|
|
9630
|
-
if ("0.2.
|
|
9631
|
-
cached = "0.2.
|
|
9981
|
+
if ("0.2.49".length > 0) {
|
|
9982
|
+
cached = "0.2.49";
|
|
9632
9983
|
return cached;
|
|
9633
9984
|
}
|
|
9634
9985
|
cached = "unknown";
|
|
9635
9986
|
try {
|
|
9636
|
-
let dir =
|
|
9987
|
+
let dir = path6.dirname(fileURLToPath3(import.meta.url));
|
|
9637
9988
|
for (let i = 0; i < 8; i++) {
|
|
9638
|
-
const pkgPath =
|
|
9989
|
+
const pkgPath = path6.join(dir, "package.json");
|
|
9639
9990
|
if (fs5.existsSync(pkgPath)) {
|
|
9640
9991
|
try {
|
|
9641
9992
|
const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf8"));
|
|
@@ -9646,7 +9997,7 @@ function substrateSelfVersion() {
|
|
|
9646
9997
|
} catch {
|
|
9647
9998
|
}
|
|
9648
9999
|
}
|
|
9649
|
-
const parent =
|
|
10000
|
+
const parent = path6.dirname(dir);
|
|
9650
10001
|
if (parent === dir) break;
|
|
9651
10002
|
dir = parent;
|
|
9652
10003
|
}
|
|
@@ -9742,17 +10093,17 @@ init_esm_shims();
|
|
|
9742
10093
|
// scripts/lakebase/adapters/alembic-adapter.ts
|
|
9743
10094
|
init_esm_shims();
|
|
9744
10095
|
import * as fs7 from "fs";
|
|
9745
|
-
import * as
|
|
10096
|
+
import * as path8 from "path";
|
|
9746
10097
|
|
|
9747
10098
|
// scripts/lakebase/schema-migrate-runners/alembic.ts
|
|
9748
10099
|
init_esm_shims();
|
|
9749
10100
|
import { spawn } from "child_process";
|
|
9750
10101
|
import * as fs6 from "fs";
|
|
9751
|
-
import * as
|
|
10102
|
+
import * as path7 from "path";
|
|
9752
10103
|
function resolveAlembicBin(projectDir) {
|
|
9753
10104
|
const candidates = [
|
|
9754
|
-
|
|
9755
|
-
|
|
10105
|
+
path7.join(projectDir, ".venv", "bin", "alembic"),
|
|
10106
|
+
path7.join(projectDir, "venv", "bin", "alembic")
|
|
9756
10107
|
];
|
|
9757
10108
|
for (const candidate of candidates) {
|
|
9758
10109
|
try {
|
|
@@ -9766,7 +10117,7 @@ function spawnAlembic(projectDir, args, dsn) {
|
|
|
9766
10117
|
return new Promise((resolve2, reject) => {
|
|
9767
10118
|
const bin = resolveAlembicBin(projectDir);
|
|
9768
10119
|
const env = { ...process.env };
|
|
9769
|
-
env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(
|
|
10120
|
+
env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path7.delimiter);
|
|
9770
10121
|
if (dsn) env.DATABASE_URL = dsn;
|
|
9771
10122
|
const child = spawn(bin, args, {
|
|
9772
10123
|
cwd: projectDir,
|
|
@@ -9814,10 +10165,10 @@ async function createAlembicRevision(opts) {
|
|
|
9814
10165
|
const m = stdout.match(/Generating\s+(\S+\.py)/);
|
|
9815
10166
|
if (m) return m[1].trim();
|
|
9816
10167
|
for (const rel of ["migrations/versions", "alembic/versions"]) {
|
|
9817
|
-
const dir =
|
|
10168
|
+
const dir = path7.join(opts.projectDir, rel);
|
|
9818
10169
|
if (!fs6.existsSync(dir)) continue;
|
|
9819
10170
|
const hit = fs6.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
|
|
9820
|
-
if (hit) return
|
|
10171
|
+
if (hit) return path7.join(dir, hit);
|
|
9821
10172
|
}
|
|
9822
10173
|
throw new SchemaMigrationError(
|
|
9823
10174
|
`alembic revision succeeded but the created file could not be located.
|
|
@@ -9952,8 +10303,8 @@ async function buildDsn(args) {
|
|
|
9952
10303
|
}
|
|
9953
10304
|
function findVersionsDir(projectDir) {
|
|
9954
10305
|
const candidates = [
|
|
9955
|
-
|
|
9956
|
-
|
|
10306
|
+
path8.join(projectDir, "migrations", "versions"),
|
|
10307
|
+
path8.join(projectDir, "alembic", "versions")
|
|
9957
10308
|
];
|
|
9958
10309
|
return candidates.find((p) => fs7.existsSync(p));
|
|
9959
10310
|
}
|
|
@@ -9985,9 +10336,9 @@ var AlembicAdapter = {
|
|
|
9985
10336
|
* here. Callers can still force-select via project.yaml#migration_tool.
|
|
9986
10337
|
*/
|
|
9987
10338
|
detect(projectDir) {
|
|
9988
|
-
if (fs7.existsSync(
|
|
9989
|
-
if (fs7.existsSync(
|
|
9990
|
-
if (fs7.existsSync(
|
|
10339
|
+
if (fs7.existsSync(path8.join(projectDir, "alembic.ini"))) return true;
|
|
10340
|
+
if (fs7.existsSync(path8.join(projectDir, "migrations", "env.py"))) return true;
|
|
10341
|
+
if (fs7.existsSync(path8.join(projectDir, "alembic", "env.py"))) return true;
|
|
9991
10342
|
return false;
|
|
9992
10343
|
},
|
|
9993
10344
|
async apply(args) {
|
|
@@ -10093,7 +10444,7 @@ var AlembicAdapter = {
|
|
|
10093
10444
|
autogenerate: !!args.autogenerate,
|
|
10094
10445
|
dsn
|
|
10095
10446
|
});
|
|
10096
|
-
return { status: "ok", version: revId, filename:
|
|
10447
|
+
return { status: "ok", version: revId, filename: path8.basename(created), path: created };
|
|
10097
10448
|
} catch (err) {
|
|
10098
10449
|
return {
|
|
10099
10450
|
status: "error",
|
|
@@ -10110,7 +10461,7 @@ var AlembicAdapter = {
|
|
|
10110
10461
|
if (heads.length <= 1) return { status: "noop", headsBefore: heads };
|
|
10111
10462
|
if (args.dryRun) return { status: "ok", headsBefore: heads };
|
|
10112
10463
|
const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
|
|
10113
|
-
const mergeRevision =
|
|
10464
|
+
const mergeRevision = path8.basename(created).replace(/\.py$/, "").split("_")[0];
|
|
10114
10465
|
return { status: "ok", headsBefore: heads, mergeRevision, path: created };
|
|
10115
10466
|
} catch (err) {
|
|
10116
10467
|
return {
|
|
@@ -10126,12 +10477,12 @@ registerSchemaMigrationAdapter(AlembicAdapter);
|
|
|
10126
10477
|
// scripts/lakebase/adapters/flyway-adapter.ts
|
|
10127
10478
|
init_esm_shims();
|
|
10128
10479
|
import * as fs8 from "fs";
|
|
10129
|
-
import * as
|
|
10480
|
+
import * as path10 from "path";
|
|
10130
10481
|
|
|
10131
10482
|
// scripts/lakebase/schema-migrate-runners/flyway.ts
|
|
10132
10483
|
init_esm_shims();
|
|
10133
10484
|
import { spawn as spawn2 } from "child_process";
|
|
10134
|
-
import * as
|
|
10485
|
+
import * as path9 from "path";
|
|
10135
10486
|
function dsnToFlywayEnv(dsn) {
|
|
10136
10487
|
const u = new URL(dsn);
|
|
10137
10488
|
const user = decodeURIComponent(u.username);
|
|
@@ -10141,7 +10492,7 @@ function dsnToFlywayEnv(dsn) {
|
|
|
10141
10492
|
return { url, user, password };
|
|
10142
10493
|
}
|
|
10143
10494
|
function migrationsLocation(projectDir) {
|
|
10144
|
-
return `filesystem:${
|
|
10495
|
+
return `filesystem:${path9.join(projectDir, "src", "main", "resources", "db", "migration")}`;
|
|
10145
10496
|
}
|
|
10146
10497
|
function runFlyway(ctx, args) {
|
|
10147
10498
|
const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
|
|
@@ -10242,7 +10593,7 @@ async function statusFlyway(ctx) {
|
|
|
10242
10593
|
if (state === "SUCCESS" || state === "BASELINE") {
|
|
10243
10594
|
current = m.version;
|
|
10244
10595
|
} else if (state === "PENDING") {
|
|
10245
|
-
const filename = m.filepath ?
|
|
10596
|
+
const filename = m.filepath ? path9.basename(m.filepath) : `V${m.version}__migration.sql`;
|
|
10246
10597
|
pending.push({
|
|
10247
10598
|
version: m.version,
|
|
10248
10599
|
filename,
|
|
@@ -10265,7 +10616,7 @@ async function buildDsn2(args) {
|
|
|
10265
10616
|
return result.url;
|
|
10266
10617
|
}
|
|
10267
10618
|
function listFlywayFiles(projectDir) {
|
|
10268
|
-
const dir =
|
|
10619
|
+
const dir = path10.join(projectDir, "src", "main", "resources", "db", "migration");
|
|
10269
10620
|
if (!fs8.existsSync(dir)) return [];
|
|
10270
10621
|
const files = fs8.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
|
|
10271
10622
|
return files.map((filename) => {
|
|
@@ -10290,7 +10641,7 @@ var FlywayAdapter = {
|
|
|
10290
10641
|
id: "flyway",
|
|
10291
10642
|
languages: ["java", "kotlin"],
|
|
10292
10643
|
detect(projectDir) {
|
|
10293
|
-
return fs8.existsSync(
|
|
10644
|
+
return fs8.existsSync(path10.join(projectDir, "pom.xml"));
|
|
10294
10645
|
},
|
|
10295
10646
|
async apply(args) {
|
|
10296
10647
|
const dsn = await buildDsn2(args);
|
|
@@ -10348,12 +10699,12 @@ var FlywayAdapter = {
|
|
|
10348
10699
|
// optional-protocol shape makes this additive.
|
|
10349
10700
|
async newMigration(args) {
|
|
10350
10701
|
try {
|
|
10351
|
-
const dir =
|
|
10702
|
+
const dir = path10.join(args.projectDir, "src", "main", "resources", "db", "migration");
|
|
10352
10703
|
fs8.mkdirSync(dir, { recursive: true });
|
|
10353
10704
|
const version = migrationTimestamp();
|
|
10354
10705
|
const slug = migrationSlug2(args.slug);
|
|
10355
10706
|
const filename = `V${version}__${slug}.sql`;
|
|
10356
|
-
const full =
|
|
10707
|
+
const full = path10.join(dir, filename);
|
|
10357
10708
|
if (fs8.existsSync(full)) throw new Error(`${filename} already exists`);
|
|
10358
10709
|
fs8.writeFileSync(
|
|
10359
10710
|
full,
|
|
@@ -10379,17 +10730,17 @@ registerSchemaMigrationAdapter(FlywayAdapter);
|
|
|
10379
10730
|
// scripts/lakebase/adapters/knex-adapter.ts
|
|
10380
10731
|
init_esm_shims();
|
|
10381
10732
|
import * as fs10 from "fs";
|
|
10382
|
-
import * as
|
|
10733
|
+
import * as path12 from "path";
|
|
10383
10734
|
|
|
10384
10735
|
// scripts/lakebase/schema-migrate-runners/knex.ts
|
|
10385
10736
|
init_esm_shims();
|
|
10386
10737
|
import { spawn as spawn3 } from "child_process";
|
|
10387
10738
|
import * as fs9 from "fs";
|
|
10388
|
-
import * as
|
|
10739
|
+
import * as path11 from "path";
|
|
10389
10740
|
var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
|
|
10390
10741
|
function findKnexfile(projectDir) {
|
|
10391
10742
|
for (const name of KNEXFILE_VARIANTS) {
|
|
10392
|
-
const p =
|
|
10743
|
+
const p = path11.join(projectDir, name);
|
|
10393
10744
|
if (fs9.existsSync(p)) return p;
|
|
10394
10745
|
}
|
|
10395
10746
|
return void 0;
|
|
@@ -10542,7 +10893,7 @@ async function buildDsn3(args) {
|
|
|
10542
10893
|
}
|
|
10543
10894
|
var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
|
|
10544
10895
|
function listKnexFiles(projectDir) {
|
|
10545
|
-
const dir =
|
|
10896
|
+
const dir = path12.join(projectDir, "migrations");
|
|
10546
10897
|
if (!fs10.existsSync(dir)) return [];
|
|
10547
10898
|
const files = fs10.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
|
|
10548
10899
|
return files.map((filename) => {
|
|
@@ -10564,7 +10915,7 @@ var KnexAdapter = {
|
|
|
10564
10915
|
* project.yaml#migration_tool.
|
|
10565
10916
|
*/
|
|
10566
10917
|
detect(projectDir) {
|
|
10567
|
-
return KNEXFILE_VARIANTS2.some((name) => fs10.existsSync(
|
|
10918
|
+
return KNEXFILE_VARIANTS2.some((name) => fs10.existsSync(path12.join(projectDir, name)));
|
|
10568
10919
|
},
|
|
10569
10920
|
async apply(args) {
|
|
10570
10921
|
const dsn = await buildDsn3(args);
|
|
@@ -10637,9 +10988,9 @@ var KnexAdapter = {
|
|
|
10637
10988
|
async newMigration(args) {
|
|
10638
10989
|
try {
|
|
10639
10990
|
const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
|
|
10640
|
-
const stem =
|
|
10991
|
+
const stem = path12.basename(created).replace(/\.(js|ts)$/, "");
|
|
10641
10992
|
const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
|
|
10642
|
-
return { status: "ok", version, filename:
|
|
10993
|
+
return { status: "ok", version, filename: path12.basename(created), path: created };
|
|
10643
10994
|
} catch (err) {
|
|
10644
10995
|
return {
|
|
10645
10996
|
status: "error",
|
|
@@ -10932,7 +11283,7 @@ async function runScmMergeCli(argv) {
|
|
|
10932
11283
|
`);
|
|
10933
11284
|
return 0;
|
|
10934
11285
|
}
|
|
10935
|
-
const projectDir =
|
|
11286
|
+
const projectDir = path14.resolve(args.projectDir ?? process.cwd());
|
|
10936
11287
|
const waitMigrate = args.noWaitMigrate ? false : true;
|
|
10937
11288
|
const verifyMigrateAuth = waitMigrate && !args.noVerifyMigrateAuth ? async () => {
|
|
10938
11289
|
try {
|