@databricks-solutions/lakebase-scm-utils 0.2.51 → 0.3.1
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/README.md +10 -4
- package/dist/scripts/index.cjs +2813 -2244
- package/dist/scripts/index.d.cts +1 -1
- package/dist/scripts/index.d.ts +1 -1
- package/dist/scripts/index.js +857 -298
- package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2460 -2030
- package/dist/scripts/lakebase/ci-resolve-branch.cli.js +508 -81
- package/dist/scripts/lakebase/collapse-heads.cli.cjs +2429 -2007
- package/dist/scripts/lakebase/collapse-heads.cli.js +477 -58
- package/dist/scripts/lakebase/detect-language.cli.cjs +2441 -2016
- package/dist/scripts/lakebase/detect-language.cli.js +489 -67
- package/dist/scripts/lakebase/doctor.cli.cjs +2484 -2040
- package/dist/scripts/lakebase/doctor.cli.js +532 -91
- 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 +2810 -2205
- package/dist/scripts/lakebase/index.d.cts +59 -10
- package/dist/scripts/lakebase/index.d.ts +59 -10
- package/dist/scripts/lakebase/index.js +851 -256
- package/dist/scripts/lakebase/infra-runner.cli.cjs +2435 -2013
- package/dist/scripts/lakebase/infra-runner.cli.js +483 -64
- package/dist/scripts/lakebase/new-migration.cli.cjs +2429 -2007
- package/dist/scripts/lakebase/new-migration.cli.js +477 -58
- 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 +2461 -2029
- package/dist/scripts/lakebase/schema-migrate.cli.js +509 -80
- package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2460 -2030
- package/dist/scripts/lakebase/scm-claim-feature.cli.js +508 -81
- package/dist/scripts/lakebase/scm-doctor.cli.cjs +2486 -2056
- package/dist/scripts/lakebase/scm-doctor.cli.js +537 -107
- package/dist/scripts/lakebase/scm-merge.cli.cjs +2443 -2021
- package/dist/scripts/lakebase/scm-merge.cli.js +494 -72
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2464 -2034
- package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +511 -84
- package/dist/scripts/util/index.cjs +2 -2
- package/dist/scripts/util/index.js +2 -2
- package/package.json +1 -1
- package/scripts/lakebase/adapters/efcore-adapter.ts +158 -0
- package/scripts/lakebase/adapters/flyway-adapter.ts +8 -5
- package/scripts/lakebase/client-lockfile.ts +102 -0
- package/scripts/lakebase/collapse-heads.cli.ts +1 -1
- package/scripts/lakebase/create-project.ts +25 -2
- package/scripts/lakebase/detect-language.cli.ts +2 -2
- package/scripts/lakebase/doctor.ts +29 -0
- package/scripts/lakebase/dotnet-project.ts +112 -0
- package/scripts/lakebase/index.ts +1 -0
- package/scripts/lakebase/migration-layout.ts +43 -2
- package/scripts/lakebase/new-migration.cli.ts +1 -1
- package/scripts/lakebase/scaffold-language.ts +23 -2
- package/scripts/lakebase/scaffold.ts +4 -1
- package/scripts/lakebase/schema-migrate-runners/efcore.ts +399 -0
- package/scripts/lakebase/schema-migrate-runners/flyway.ts +6 -4
- package/scripts/lakebase/schema-migrate.cli.ts +3 -1
- package/scripts/lakebase/schema-migrate.ts +24 -10
- package/templates/project/common/.github/workflows/merge.yml +13 -1
- package/templates/project/common/.github/workflows/pr.yml +25 -5
- package/templates/project/common/scripts/flyway-migrate.sh +54 -1
- package/templates/project/common/scripts/prepare-schema-diff.sh +5 -0
- package/templates/project/common/scripts/run-dev.sh +10 -1
- package/templates/project/common/scripts/run-tests.sh +6 -1
- package/templates/project/dotnet/.gitignore.extra +8 -0
- package/templates/project/dotnet/App.sln +56 -0
- package/templates/project/dotnet/Makefile +13 -0
- package/templates/project/dotnet/global.json +6 -0
- package/templates/project/dotnet/src/App/Data/AppDbContext.cs +12 -0
- package/templates/project/dotnet/src/App/Lakebase/DotEnv.cs +48 -0
- package/templates/project/dotnet/src/App/Lakebase/LakebaseConnection.cs +225 -0
- package/templates/project/dotnet/src/App/Program.cs +34 -0
- package/templates/project/dotnet/src/App/appsettings.json +9 -0
- package/templates/project/dotnet/tests/App.Tests/App.Tests.csproj +25 -0
- package/templates/project/dotnet/tests/App.Tests/HealthTests.cs +18 -0
- package/templates/project/dotnet/tests/App.Tests/OpenApiTests.cs +23 -0
- package/templates/project/dotnet-efcore/.config/dotnet-tools.json +13 -0
- package/templates/project/dotnet-efcore/src/App/App.csproj +22 -0
- package/templates/project/dotnet-efcore/src/App/Data/DesignTimeDbContextFactory.cs +24 -0
- package/templates/project/dotnet-efcore/src/App/Migrations/README.md +23 -0
- package/templates/project/dotnet-flyway/db/migrations/README.md +23 -0
- package/templates/project/dotnet-flyway/src/App/App.csproj +17 -0
|
@@ -1913,9 +1913,9 @@ function asBranchUid(s) {
|
|
|
1913
1913
|
}
|
|
1914
1914
|
return s;
|
|
1915
1915
|
}
|
|
1916
|
-
function branchNameFromResourcePath(
|
|
1917
|
-
if (!
|
|
1918
|
-
const leaf =
|
|
1916
|
+
function branchNameFromResourcePath(path37) {
|
|
1917
|
+
if (!path37.includes("/branches/")) return null;
|
|
1918
|
+
const leaf = path37.split("/branches/").pop();
|
|
1919
1919
|
if (!leaf) return null;
|
|
1920
1920
|
try {
|
|
1921
1921
|
return asBranchName(leaf);
|
|
@@ -2521,8 +2521,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
|
2521
2521
|
var cached;
|
|
2522
2522
|
function substrateSelfVersion() {
|
|
2523
2523
|
if (cached !== void 0) return cached;
|
|
2524
|
-
if ("0.
|
|
2525
|
-
cached = "0.
|
|
2524
|
+
if ("0.3.1".length > 0) {
|
|
2525
|
+
cached = "0.3.1";
|
|
2526
2526
|
return cached;
|
|
2527
2527
|
}
|
|
2528
2528
|
cached = "unknown";
|
|
@@ -5062,7 +5062,7 @@ paginateRest.VERSION = VERSION5;
|
|
|
5062
5062
|
|
|
5063
5063
|
// node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
|
|
5064
5064
|
init_esm_shims();
|
|
5065
|
-
var generateMessage = (
|
|
5065
|
+
var generateMessage = (path37, cursorValue) => `The cursor at "${path37.join(
|
|
5066
5066
|
","
|
|
5067
5067
|
)}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
|
|
5068
5068
|
var MissingCursorChange = class extends Error {
|
|
@@ -5103,9 +5103,9 @@ function findPaginatedResourcePath(responseData) {
|
|
|
5103
5103
|
}
|
|
5104
5104
|
return paginatedResourcePath;
|
|
5105
5105
|
}
|
|
5106
|
-
var deepFindPathToProperty = (object, searchProp,
|
|
5106
|
+
var deepFindPathToProperty = (object, searchProp, path37 = []) => {
|
|
5107
5107
|
for (const key of Object.keys(object)) {
|
|
5108
|
-
const currentPath = [...
|
|
5108
|
+
const currentPath = [...path37, key];
|
|
5109
5109
|
const currentValue = object[key];
|
|
5110
5110
|
if (isObject(currentValue)) {
|
|
5111
5111
|
if (currentValue.hasOwnProperty(searchProp)) {
|
|
@@ -5123,12 +5123,12 @@ var deepFindPathToProperty = (object, searchProp, path33 = []) => {
|
|
|
5123
5123
|
}
|
|
5124
5124
|
return [];
|
|
5125
5125
|
};
|
|
5126
|
-
var get = (object,
|
|
5127
|
-
return
|
|
5126
|
+
var get = (object, path37) => {
|
|
5127
|
+
return path37.reduce((current, nextProperty) => current[nextProperty], object);
|
|
5128
5128
|
};
|
|
5129
|
-
var set = (object,
|
|
5130
|
-
const lastProperty =
|
|
5131
|
-
const parentPath = [...
|
|
5129
|
+
var set = (object, path37, mutator) => {
|
|
5130
|
+
const lastProperty = path37[path37.length - 1];
|
|
5131
|
+
const parentPath = [...path37].slice(0, -1);
|
|
5132
5132
|
const parent = get(object, parentPath);
|
|
5133
5133
|
if (typeof mutator === "function") {
|
|
5134
5134
|
parent[lastProperty] = mutator(parent[lastProperty]);
|
|
@@ -5180,22 +5180,22 @@ var mergeResponses = (response1, response2) => {
|
|
|
5180
5180
|
if (Object.keys(response1).length === 0) {
|
|
5181
5181
|
return Object.assign(response1, response2);
|
|
5182
5182
|
}
|
|
5183
|
-
const
|
|
5184
|
-
const nodesPath = [...
|
|
5183
|
+
const path37 = findPaginatedResourcePath(response1);
|
|
5184
|
+
const nodesPath = [...path37, "nodes"];
|
|
5185
5185
|
const newNodes = get(response2, nodesPath);
|
|
5186
5186
|
if (newNodes) {
|
|
5187
5187
|
set(response1, nodesPath, (values) => {
|
|
5188
5188
|
return [...values, ...newNodes];
|
|
5189
5189
|
});
|
|
5190
5190
|
}
|
|
5191
|
-
const edgesPath = [...
|
|
5191
|
+
const edgesPath = [...path37, "edges"];
|
|
5192
5192
|
const newEdges = get(response2, edgesPath);
|
|
5193
5193
|
if (newEdges) {
|
|
5194
5194
|
set(response1, edgesPath, (values) => {
|
|
5195
5195
|
return [...values, ...newEdges];
|
|
5196
5196
|
});
|
|
5197
5197
|
}
|
|
5198
|
-
const pageInfoPath = [...
|
|
5198
|
+
const pageInfoPath = [...path37, "pageInfo"];
|
|
5199
5199
|
set(response1, pageInfoPath, get(response2, pageInfoPath));
|
|
5200
5200
|
return response1;
|
|
5201
5201
|
};
|
|
@@ -7616,7 +7616,7 @@ var triggers_notification_paths_default = [
|
|
|
7616
7616
|
];
|
|
7617
7617
|
function routeMatcher(paths) {
|
|
7618
7618
|
const regexes = paths.map(
|
|
7619
|
-
(
|
|
7619
|
+
(path37) => path37.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
|
|
7620
7620
|
);
|
|
7621
7621
|
const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
|
|
7622
7622
|
return new RegExp(regex2, "i");
|
|
@@ -10944,16 +10944,16 @@ function isAllSchemas(schema) {
|
|
|
10944
10944
|
}
|
|
10945
10945
|
function buildSchemaQuery(schema) {
|
|
10946
10946
|
const cols = "c.table_schema, c.table_name, c.column_name, c.data_type";
|
|
10947
|
-
const
|
|
10947
|
+
const join36 = "FROM information_schema.columns c JOIN pg_tables t ON c.table_name = t.tablename AND c.table_schema = t.schemaname ";
|
|
10948
10948
|
if (isAllSchemas(schema)) {
|
|
10949
10949
|
return {
|
|
10950
|
-
text: `SELECT ${cols} ` +
|
|
10950
|
+
text: `SELECT ${cols} ` + join36 + `WHERE ${SYSTEM_SCHEMA_FILTER} ORDER BY c.table_schema, c.table_name, c.ordinal_position`,
|
|
10951
10951
|
values: []
|
|
10952
10952
|
};
|
|
10953
10953
|
}
|
|
10954
10954
|
const one = (schema ?? "").trim() || "public";
|
|
10955
10955
|
return {
|
|
10956
|
-
text: `SELECT ${cols} ` +
|
|
10956
|
+
text: `SELECT ${cols} ` + join36 + "WHERE c.table_schema = $1 ORDER BY c.table_name, c.ordinal_position",
|
|
10957
10957
|
values: [one]
|
|
10958
10958
|
};
|
|
10959
10959
|
}
|
|
@@ -11113,8 +11113,8 @@ async function withLakebaseRollback(opts, fn) {
|
|
|
11113
11113
|
|
|
11114
11114
|
// scripts/lakebase/create-project.ts
|
|
11115
11115
|
init_esm_shims();
|
|
11116
|
-
import * as
|
|
11117
|
-
import * as
|
|
11116
|
+
import * as fs19 from "fs";
|
|
11117
|
+
import * as path19 from "path";
|
|
11118
11118
|
|
|
11119
11119
|
// scripts/lakebase/project-verify.ts
|
|
11120
11120
|
init_esm_shims();
|
|
@@ -11711,6 +11711,20 @@ async function deployLanguageProject(args) {
|
|
|
11711
11711
|
return;
|
|
11712
11712
|
}
|
|
11713
11713
|
const templatesDir = args.templatesDir ?? findTemplatesDir2();
|
|
11714
|
+
if (args.language === "dotnet") {
|
|
11715
|
+
const tool = args.migrationTool ?? "efcore";
|
|
11716
|
+
if (tool !== "efcore" && tool !== "flyway") {
|
|
11717
|
+
throw new Error(`Unsupported .NET migration tool: ${String(tool)} (expected efcore or flyway)`);
|
|
11718
|
+
}
|
|
11719
|
+
const base = path10.join(templatesDir, "dotnet");
|
|
11720
|
+
const overlay = path10.join(templatesDir, `dotnet-${tool}`);
|
|
11721
|
+
if (!fs11.existsSync(base) || !fs11.existsSync(overlay)) {
|
|
11722
|
+
throw new Error(`No template found for language: dotnet (${tool})`);
|
|
11723
|
+
}
|
|
11724
|
+
copyDirSubstituted(base, args.targetDir, { projectName: args.projectName });
|
|
11725
|
+
copyDirSubstituted(overlay, args.targetDir, { projectName: args.projectName });
|
|
11726
|
+
return;
|
|
11727
|
+
}
|
|
11714
11728
|
const langSrc = path10.join(templatesDir, args.language);
|
|
11715
11729
|
if (!fs11.existsSync(langSrc)) {
|
|
11716
11730
|
throw new Error(`No template found for language: ${args.language}`);
|
|
@@ -12130,6 +12144,7 @@ async function scaffoldAll(args) {
|
|
|
12130
12144
|
targetDir: args.targetDir,
|
|
12131
12145
|
language,
|
|
12132
12146
|
projectName,
|
|
12147
|
+
migrationTool: args.migrationTool,
|
|
12133
12148
|
templatesDir: args.templatesDir,
|
|
12134
12149
|
initializrClient: args.initializrClient,
|
|
12135
12150
|
report
|
|
@@ -12462,18 +12477,100 @@ function enableE2eForProject(args) {
|
|
|
12462
12477
|
};
|
|
12463
12478
|
}
|
|
12464
12479
|
|
|
12465
|
-
// scripts/lakebase/
|
|
12480
|
+
// scripts/lakebase/client-lockfile.ts
|
|
12466
12481
|
init_esm_shims();
|
|
12467
12482
|
import * as fs15 from "fs";
|
|
12468
12483
|
import * as path14 from "path";
|
|
12484
|
+
|
|
12485
|
+
// scripts/util/proxy-env.ts
|
|
12486
|
+
init_esm_shims();
|
|
12487
|
+
var PROXY_ENV_KEYS = [
|
|
12488
|
+
"HTTP_PROXY",
|
|
12489
|
+
"HTTPS_PROXY",
|
|
12490
|
+
"NO_PROXY",
|
|
12491
|
+
"http_proxy",
|
|
12492
|
+
"https_proxy",
|
|
12493
|
+
"no_proxy",
|
|
12494
|
+
"npm_config_proxy",
|
|
12495
|
+
"npm_config_https_proxy",
|
|
12496
|
+
"npm_config_no_proxy",
|
|
12497
|
+
"npm_config_registry"
|
|
12498
|
+
];
|
|
12499
|
+
function proxyEnvSubset(source = process.env) {
|
|
12500
|
+
const out = {};
|
|
12501
|
+
for (const key of PROXY_ENV_KEYS) {
|
|
12502
|
+
const v = source[key];
|
|
12503
|
+
if (v !== void 0 && v !== "") {
|
|
12504
|
+
out[key] = v;
|
|
12505
|
+
}
|
|
12506
|
+
}
|
|
12507
|
+
return out;
|
|
12508
|
+
}
|
|
12509
|
+
function withProxyEnv(base = {}) {
|
|
12510
|
+
const out = {};
|
|
12511
|
+
const inherited = proxyEnvSubset();
|
|
12512
|
+
for (const [k, v] of Object.entries(inherited)) {
|
|
12513
|
+
out[k] = v;
|
|
12514
|
+
}
|
|
12515
|
+
for (const [k, v] of Object.entries(base)) {
|
|
12516
|
+
if (v !== void 0) out[k] = v;
|
|
12517
|
+
}
|
|
12518
|
+
return out;
|
|
12519
|
+
}
|
|
12520
|
+
|
|
12521
|
+
// scripts/lakebase/client-lockfile.ts
|
|
12522
|
+
var PROXY_HOST = "npm-proxy.cloud.databricks.com";
|
|
12523
|
+
var PUBLIC_HOST = "registry.npmjs.org";
|
|
12524
|
+
function normalizeLockfileRegistry(lockText) {
|
|
12525
|
+
let swaps = 0;
|
|
12526
|
+
const text = lockText.replace(new RegExp(PROXY_HOST.replace(/\./g, "\\."), "g"), () => {
|
|
12527
|
+
swaps++;
|
|
12528
|
+
return PUBLIC_HOST;
|
|
12529
|
+
});
|
|
12530
|
+
return { text, swaps };
|
|
12531
|
+
}
|
|
12532
|
+
async function ensureClientLockfile(args) {
|
|
12533
|
+
const clientDir = path14.join(args.projectDir, args.clientDir ?? "client");
|
|
12534
|
+
const pkg = path14.join(clientDir, "package.json");
|
|
12535
|
+
if (!fs15.existsSync(pkg)) {
|
|
12536
|
+
return { generated: false, swaps: 0, reason: "no client package.json" };
|
|
12537
|
+
}
|
|
12538
|
+
const lockPath = path14.join(clientDir, "package-lock.json");
|
|
12539
|
+
try {
|
|
12540
|
+
await exec2("npm install --package-lock-only", {
|
|
12541
|
+
cwd: clientDir,
|
|
12542
|
+
env: withProxyEnv(),
|
|
12543
|
+
timeout: 18e4
|
|
12544
|
+
});
|
|
12545
|
+
} catch (err) {
|
|
12546
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12547
|
+
return { generated: fs15.existsSync(lockPath), swaps: 0, reason: `npm resolve failed: ${msg}` };
|
|
12548
|
+
}
|
|
12549
|
+
if (!fs15.existsSync(lockPath)) {
|
|
12550
|
+
return { generated: false, swaps: 0, reason: "npm wrote no package-lock.json" };
|
|
12551
|
+
}
|
|
12552
|
+
try {
|
|
12553
|
+
const { text, swaps } = normalizeLockfileRegistry(fs15.readFileSync(lockPath, "utf8"));
|
|
12554
|
+
if (swaps > 0) fs15.writeFileSync(lockPath, text);
|
|
12555
|
+
return { generated: true, swaps };
|
|
12556
|
+
} catch (err) {
|
|
12557
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12558
|
+
return { generated: true, swaps: 0, reason: `lock normalize failed: ${msg}` };
|
|
12559
|
+
}
|
|
12560
|
+
}
|
|
12561
|
+
|
|
12562
|
+
// scripts/lakebase/enable-infra.ts
|
|
12563
|
+
init_esm_shims();
|
|
12564
|
+
import * as fs16 from "fs";
|
|
12565
|
+
import * as path15 from "path";
|
|
12469
12566
|
var RUN_TESTS_INFRA_MARKER = "# Run Lakebase [Infra]-tag suite when wired";
|
|
12470
12567
|
function addInfraToPackageJson(args) {
|
|
12471
|
-
const pkgPath =
|
|
12472
|
-
if (!
|
|
12568
|
+
const pkgPath = path15.join(args.projectDir, "package.json");
|
|
12569
|
+
if (!fs16.existsSync(pkgPath)) {
|
|
12473
12570
|
return { patched: false, scriptAdded: false };
|
|
12474
12571
|
}
|
|
12475
12572
|
const scriptValue = args.scriptValue ?? "npx --yes lakebase-infra-runner";
|
|
12476
|
-
const raw =
|
|
12573
|
+
const raw = fs16.readFileSync(pkgPath, "utf8");
|
|
12477
12574
|
const pkg = JSON.parse(raw);
|
|
12478
12575
|
const scripts = pkg.scripts ?? {};
|
|
12479
12576
|
let scriptAdded = false;
|
|
@@ -12484,16 +12581,16 @@ function addInfraToPackageJson(args) {
|
|
|
12484
12581
|
pkg.scripts = scripts;
|
|
12485
12582
|
if (scriptAdded) {
|
|
12486
12583
|
const trailing = raw.endsWith("\n") ? "\n" : "";
|
|
12487
|
-
|
|
12584
|
+
fs16.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + trailing, "utf8");
|
|
12488
12585
|
}
|
|
12489
12586
|
return { patched: true, scriptAdded };
|
|
12490
12587
|
}
|
|
12491
12588
|
function addInfraToRunTestsScript(args) {
|
|
12492
|
-
const scriptPath =
|
|
12493
|
-
if (!
|
|
12589
|
+
const scriptPath = path15.join(args.projectDir, "scripts", "run-tests.sh");
|
|
12590
|
+
if (!fs16.existsSync(scriptPath)) {
|
|
12494
12591
|
return { patched: false, inserted: false };
|
|
12495
12592
|
}
|
|
12496
|
-
const original =
|
|
12593
|
+
const original = fs16.readFileSync(scriptPath, "utf8");
|
|
12497
12594
|
if (original.includes(RUN_TESTS_INFRA_MARKER)) {
|
|
12498
12595
|
return { patched: true, inserted: false };
|
|
12499
12596
|
}
|
|
@@ -12509,7 +12606,7 @@ function addInfraToRunTestsScript(args) {
|
|
|
12509
12606
|
"fi",
|
|
12510
12607
|
""
|
|
12511
12608
|
].join("\n");
|
|
12512
|
-
|
|
12609
|
+
fs16.writeFileSync(scriptPath, trimmed + block, "utf8");
|
|
12513
12610
|
return { patched: true, inserted: true };
|
|
12514
12611
|
}
|
|
12515
12612
|
function enableInfraForProject(args) {
|
|
@@ -12523,9 +12620,9 @@ function enableInfraForProject(args) {
|
|
|
12523
12620
|
|
|
12524
12621
|
// scripts/lakebase/runner-setup.ts
|
|
12525
12622
|
init_esm_shims();
|
|
12526
|
-
import * as
|
|
12623
|
+
import * as fs17 from "fs";
|
|
12527
12624
|
import * as os from "os";
|
|
12528
|
-
import * as
|
|
12625
|
+
import * as path16 from "path";
|
|
12529
12626
|
import * as cp4 from "child_process";
|
|
12530
12627
|
import * as tar from "tar";
|
|
12531
12628
|
import findJavaHome from "find-java-home";
|
|
@@ -12612,28 +12709,28 @@ var RUNNER_OS = process.platform === "darwin" ? "osx" : "linux";
|
|
|
12612
12709
|
var RUNNER_ARCHIVE = `actions-runner-${RUNNER_OS}-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz`;
|
|
12613
12710
|
var RUNNER_URL = `https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/${RUNNER_ARCHIVE}`;
|
|
12614
12711
|
function cacheDir() {
|
|
12615
|
-
return
|
|
12712
|
+
return path16.join(os.homedir(), ".cache", "github-actions-runner");
|
|
12616
12713
|
}
|
|
12617
12714
|
function runnersDir() {
|
|
12618
|
-
return
|
|
12715
|
+
return path16.join(os.homedir(), ".lakebase", "runners");
|
|
12619
12716
|
}
|
|
12620
12717
|
function runnerDir(projectName) {
|
|
12621
|
-
return
|
|
12718
|
+
return path16.join(runnersDir(), projectName);
|
|
12622
12719
|
}
|
|
12623
12720
|
function runnerName(projectName) {
|
|
12624
12721
|
return `lakebase-${projectName}`;
|
|
12625
12722
|
}
|
|
12626
12723
|
async function ensureCachedArchive() {
|
|
12627
12724
|
const dir = cacheDir();
|
|
12628
|
-
|
|
12629
|
-
const cachedPath =
|
|
12630
|
-
if (
|
|
12725
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
12726
|
+
const cachedPath = path16.join(dir, RUNNER_ARCHIVE);
|
|
12727
|
+
if (fs17.existsSync(cachedPath)) return cachedPath;
|
|
12631
12728
|
const response = await fetch(RUNNER_URL);
|
|
12632
12729
|
if (!response.ok) {
|
|
12633
12730
|
throw new Error(`Failed to download runner: HTTP ${response.status}`);
|
|
12634
12731
|
}
|
|
12635
12732
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
12636
|
-
|
|
12733
|
+
fs17.writeFileSync(cachedPath, buffer);
|
|
12637
12734
|
return cachedPath;
|
|
12638
12735
|
}
|
|
12639
12736
|
async function resolveJavaHome() {
|
|
@@ -12643,9 +12740,9 @@ async function resolveJavaHome() {
|
|
|
12643
12740
|
});
|
|
12644
12741
|
}
|
|
12645
12742
|
function isRunning(projectName) {
|
|
12646
|
-
const pidFile =
|
|
12647
|
-
if (!
|
|
12648
|
-
const pid = parseInt(
|
|
12743
|
+
const pidFile = path16.join(runnerDir(projectName), ".pid");
|
|
12744
|
+
if (!fs17.existsSync(pidFile)) return false;
|
|
12745
|
+
const pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim(), 10);
|
|
12649
12746
|
if (!pid) return false;
|
|
12650
12747
|
try {
|
|
12651
12748
|
process.kill(pid, 0);
|
|
@@ -12656,23 +12753,23 @@ function isRunning(projectName) {
|
|
|
12656
12753
|
}
|
|
12657
12754
|
function getRunnerInfo(projectName) {
|
|
12658
12755
|
const dir = runnerDir(projectName);
|
|
12659
|
-
if (!
|
|
12660
|
-
const pidFile =
|
|
12756
|
+
if (!fs17.existsSync(dir)) return void 0;
|
|
12757
|
+
const pidFile = path16.join(dir, ".pid");
|
|
12661
12758
|
let pid;
|
|
12662
|
-
if (
|
|
12663
|
-
pid = parseInt(
|
|
12759
|
+
if (fs17.existsSync(pidFile)) {
|
|
12760
|
+
pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim(), 10);
|
|
12664
12761
|
}
|
|
12665
12762
|
return { name: runnerName(projectName), dir, pid, online: isRunning(projectName) };
|
|
12666
12763
|
}
|
|
12667
12764
|
var lastRunnerPid;
|
|
12668
12765
|
function stopRunner(projectName) {
|
|
12669
12766
|
const dir = runnerDir(projectName);
|
|
12670
|
-
const pidFile =
|
|
12767
|
+
const pidFile = path16.join(dir, ".pid");
|
|
12671
12768
|
let pid = lastRunnerPid;
|
|
12672
|
-
if (
|
|
12673
|
-
pid = parseInt(
|
|
12769
|
+
if (fs17.existsSync(pidFile)) {
|
|
12770
|
+
pid = parseInt(fs17.readFileSync(pidFile, "utf-8").trim(), 10);
|
|
12674
12771
|
try {
|
|
12675
|
-
|
|
12772
|
+
fs17.unlinkSync(pidFile);
|
|
12676
12773
|
} catch {
|
|
12677
12774
|
}
|
|
12678
12775
|
}
|
|
@@ -12685,7 +12782,7 @@ function stopRunner(projectName) {
|
|
|
12685
12782
|
} catch {
|
|
12686
12783
|
}
|
|
12687
12784
|
}
|
|
12688
|
-
} else if (
|
|
12785
|
+
} else if (fs17.existsSync(dir)) {
|
|
12689
12786
|
try {
|
|
12690
12787
|
cp4.execSync(`pkill -9 -f "${dir.replace(/\//g, "\\/")}.*Runner" 2>/dev/null || true`, {
|
|
12691
12788
|
timeout: KIT_TIMEOUTS.cmdShort
|
|
@@ -12695,16 +12792,16 @@ function stopRunner(projectName) {
|
|
|
12695
12792
|
}
|
|
12696
12793
|
lastRunnerPid = void 0;
|
|
12697
12794
|
for (const stale of ["_diag/pages", "_work/_temp", "_work/_actions"]) {
|
|
12698
|
-
const full =
|
|
12699
|
-
if (
|
|
12795
|
+
const full = path16.join(dir, stale);
|
|
12796
|
+
if (fs17.existsSync(full)) {
|
|
12700
12797
|
try {
|
|
12701
|
-
|
|
12798
|
+
fs17.rmSync(full, { recursive: true, force: true });
|
|
12702
12799
|
} catch {
|
|
12703
12800
|
}
|
|
12704
12801
|
}
|
|
12705
12802
|
}
|
|
12706
12803
|
try {
|
|
12707
|
-
|
|
12804
|
+
fs17.mkdirSync(path16.join(dir, "_diag", "pages"), { recursive: true });
|
|
12708
12805
|
} catch {
|
|
12709
12806
|
}
|
|
12710
12807
|
}
|
|
@@ -12720,24 +12817,24 @@ function resetRunnerConfig(dir, projectName) {
|
|
|
12720
12817
|
];
|
|
12721
12818
|
for (const f of stateFiles) {
|
|
12722
12819
|
try {
|
|
12723
|
-
|
|
12820
|
+
fs17.unlinkSync(path16.join(dir, f));
|
|
12724
12821
|
} catch {
|
|
12725
12822
|
}
|
|
12726
12823
|
}
|
|
12727
12824
|
if (process.platform === "darwin") {
|
|
12728
|
-
const plist =
|
|
12825
|
+
const plist = path16.join(
|
|
12729
12826
|
os.homedir(),
|
|
12730
12827
|
"Library",
|
|
12731
12828
|
"LaunchAgents",
|
|
12732
12829
|
`actions.runner.${projectName}.plist`
|
|
12733
12830
|
);
|
|
12734
|
-
if (
|
|
12831
|
+
if (fs17.existsSync(plist)) {
|
|
12735
12832
|
try {
|
|
12736
12833
|
cp4.execFileSync("launchctl", ["unload", plist], { stdio: "ignore" });
|
|
12737
12834
|
} catch {
|
|
12738
12835
|
}
|
|
12739
12836
|
try {
|
|
12740
|
-
|
|
12837
|
+
fs17.unlinkSync(plist);
|
|
12741
12838
|
} catch {
|
|
12742
12839
|
}
|
|
12743
12840
|
}
|
|
@@ -12751,24 +12848,24 @@ async function setupRunner(args) {
|
|
|
12751
12848
|
stopRunner(args.projectName);
|
|
12752
12849
|
report("Downloading runner binary...");
|
|
12753
12850
|
const archive = await ensureCachedArchive();
|
|
12754
|
-
|
|
12755
|
-
if (!
|
|
12851
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
12852
|
+
if (!fs17.existsSync(path16.join(dir, "config.sh"))) {
|
|
12756
12853
|
report("Extracting runner...");
|
|
12757
12854
|
await tar.extract({ file: archive, cwd: dir });
|
|
12758
12855
|
}
|
|
12759
|
-
const diagPages =
|
|
12760
|
-
if (
|
|
12761
|
-
|
|
12762
|
-
|
|
12856
|
+
const diagPages = path16.join(dir, "_diag", "pages");
|
|
12857
|
+
if (fs17.existsSync(diagPages)) {
|
|
12858
|
+
fs17.rmSync(diagPages, { recursive: true, force: true });
|
|
12859
|
+
fs17.mkdirSync(diagPages, { recursive: true });
|
|
12763
12860
|
}
|
|
12764
|
-
const runnerFile =
|
|
12765
|
-
let needsConfig = !
|
|
12861
|
+
const runnerFile = path16.join(dir, ".runner");
|
|
12862
|
+
let needsConfig = !fs17.existsSync(runnerFile);
|
|
12766
12863
|
if (needsConfig) {
|
|
12767
12864
|
resetRunnerConfig(dir, args.projectName);
|
|
12768
12865
|
} else {
|
|
12769
12866
|
let urlMismatch = false;
|
|
12770
12867
|
try {
|
|
12771
|
-
const runnerJson = JSON.parse(
|
|
12868
|
+
const runnerJson = JSON.parse(fs17.readFileSync(runnerFile, "utf-8"));
|
|
12772
12869
|
const configuredUrl = runnerJson.gitHubUrl || runnerJson.serverUrl || runnerJson.agentUrl || "";
|
|
12773
12870
|
const expectedUrl = `https://github.com/${args.fullRepoName}`;
|
|
12774
12871
|
urlMismatch = !!configuredUrl && !configuredUrl.startsWith(expectedUrl);
|
|
@@ -12829,7 +12926,7 @@ async function setupRunner(args) {
|
|
|
12829
12926
|
child.unref();
|
|
12830
12927
|
lastRunnerPid = child.pid;
|
|
12831
12928
|
if (child.pid) {
|
|
12832
|
-
|
|
12929
|
+
fs17.writeFileSync(path16.join(dir, ".pid"), String(child.pid));
|
|
12833
12930
|
}
|
|
12834
12931
|
report("Waiting for runner to come online...");
|
|
12835
12932
|
let online = false;
|
|
@@ -12861,14 +12958,14 @@ async function removeRunner(args) {
|
|
|
12861
12958
|
} catch {
|
|
12862
12959
|
}
|
|
12863
12960
|
try {
|
|
12864
|
-
|
|
12961
|
+
fs17.rmSync(dir, { recursive: true, force: true });
|
|
12865
12962
|
} catch {
|
|
12866
12963
|
}
|
|
12867
12964
|
}
|
|
12868
12965
|
|
|
12869
12966
|
// scripts/util/ci-secrets.ts
|
|
12870
12967
|
init_esm_shims();
|
|
12871
|
-
import * as
|
|
12968
|
+
import * as path17 from "path";
|
|
12872
12969
|
|
|
12873
12970
|
// scripts/github/secrets.ts
|
|
12874
12971
|
init_esm_shims();
|
|
@@ -13091,7 +13188,7 @@ async function ensureCiSecretsFresh(args) {
|
|
|
13091
13188
|
return { action: "ok", reason: "CI token is current." };
|
|
13092
13189
|
}
|
|
13093
13190
|
async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
|
|
13094
|
-
const envPath =
|
|
13191
|
+
const envPath = path17.join(projectDir, ".env");
|
|
13095
13192
|
const databricksHost = readEnvVar(envPath, "DATABRICKS_HOST");
|
|
13096
13193
|
const lakebaseProjectId = readEnvVar(envPath, "LAKEBASE_PROJECT_ID");
|
|
13097
13194
|
if (!databricksHost || !lakebaseProjectId) {
|
|
@@ -13118,8 +13215,8 @@ async function ensureCiSecretsFreshFromEnv(projectDir, opts) {
|
|
|
13118
13215
|
|
|
13119
13216
|
// scripts/lakebase/scm-workflow-state.ts
|
|
13120
13217
|
init_esm_shims();
|
|
13121
|
-
import * as
|
|
13122
|
-
import * as
|
|
13218
|
+
import * as fs18 from "fs";
|
|
13219
|
+
import * as path18 from "path";
|
|
13123
13220
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
13124
13221
|
function isGitTracked(projectDir, rel) {
|
|
13125
13222
|
try {
|
|
@@ -13138,11 +13235,11 @@ function ensureWorkflowStateUntracked(projectDir) {
|
|
|
13138
13235
|
} catch {
|
|
13139
13236
|
}
|
|
13140
13237
|
try {
|
|
13141
|
-
const gitignore =
|
|
13142
|
-
const existing =
|
|
13238
|
+
const gitignore = path18.join(projectDir, ".gitignore");
|
|
13239
|
+
const existing = fs18.existsSync(gitignore) ? fs18.readFileSync(gitignore, "utf8") : "";
|
|
13143
13240
|
if (!existing.split("\n").some((l) => l.trim() === rel)) {
|
|
13144
13241
|
const sep4 = existing === "" || existing.endsWith("\n") ? "" : "\n";
|
|
13145
|
-
|
|
13242
|
+
fs18.appendFileSync(
|
|
13146
13243
|
gitignore,
|
|
13147
13244
|
`${sep4}# Runtime SCM claim state (per working tree): a branch checkout must never restore
|
|
13148
13245
|
# a stale committed claim over the live one (issue #203 / Finding 28).
|
|
@@ -13166,12 +13263,12 @@ var STATE_INDEX = SCM_STATES.reduce(
|
|
|
13166
13263
|
);
|
|
13167
13264
|
var STATE_FILE_REL = ".lakebase/workflow-state.json";
|
|
13168
13265
|
function stateFilePath(projectDir) {
|
|
13169
|
-
return
|
|
13266
|
+
return path18.join(projectDir, STATE_FILE_REL);
|
|
13170
13267
|
}
|
|
13171
13268
|
function readWorkflowState(projectDir) {
|
|
13172
13269
|
const p = stateFilePath(projectDir);
|
|
13173
|
-
if (!
|
|
13174
|
-
const raw =
|
|
13270
|
+
if (!fs18.existsSync(p)) return null;
|
|
13271
|
+
const raw = fs18.readFileSync(p, "utf8");
|
|
13175
13272
|
let parsed;
|
|
13176
13273
|
try {
|
|
13177
13274
|
parsed = JSON.parse(raw);
|
|
@@ -13206,14 +13303,14 @@ function writeWorkflowState(projectDir, state) {
|
|
|
13206
13303
|
${summary}`);
|
|
13207
13304
|
}
|
|
13208
13305
|
ensureWorkflowStateUntracked(projectDir);
|
|
13209
|
-
const dir =
|
|
13210
|
-
|
|
13306
|
+
const dir = path18.join(projectDir, ".lakebase");
|
|
13307
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
13211
13308
|
const target = stateFilePath(projectDir);
|
|
13212
13309
|
const tmp = `${target}.tmp`;
|
|
13213
13310
|
const ordered = orderForOutput(result.value);
|
|
13214
|
-
|
|
13311
|
+
fs18.writeFileSync(tmp, `${JSON.stringify(ordered, null, 2)}
|
|
13215
13312
|
`, "utf8");
|
|
13216
|
-
|
|
13313
|
+
fs18.renameSync(tmp, target);
|
|
13217
13314
|
}
|
|
13218
13315
|
function initWorkflowState(args) {
|
|
13219
13316
|
return {
|
|
@@ -13437,7 +13534,7 @@ function orderForOutput(state) {
|
|
|
13437
13534
|
async function createProject(input, progress) {
|
|
13438
13535
|
const report = progress ?? (() => {
|
|
13439
13536
|
});
|
|
13440
|
-
const projectDir =
|
|
13537
|
+
const projectDir = path19.join(input.parentDir, input.projectName);
|
|
13441
13538
|
const lakebaseProjectId = input.projectName;
|
|
13442
13539
|
const host = input.databricksHost.replace(/\/+$/, "");
|
|
13443
13540
|
const useGithub = input.createGithubRepo !== false;
|
|
@@ -13462,7 +13559,7 @@ async function createProject(input, progress) {
|
|
|
13462
13559
|
useGithub,
|
|
13463
13560
|
githubOwner: input.githubOwner,
|
|
13464
13561
|
tiers,
|
|
13465
|
-
dirExists: (p) =>
|
|
13562
|
+
dirExists: (p) => fs19.existsSync(p),
|
|
13466
13563
|
dirIsEmpty
|
|
13467
13564
|
});
|
|
13468
13565
|
if (!v.ok) throw new Error(v.reason);
|
|
@@ -13531,7 +13628,7 @@ Last probe error:
|
|
|
13531
13628
|
});
|
|
13532
13629
|
} else {
|
|
13533
13630
|
report("Creating local project directory...", projectDir);
|
|
13534
|
-
|
|
13631
|
+
fs19.mkdirSync(projectDir, { recursive: true });
|
|
13535
13632
|
await gitInit(projectDir);
|
|
13536
13633
|
}
|
|
13537
13634
|
report("Creating Lakebase database (provisioning Postgres)...", lakebaseProjectId);
|
|
@@ -13550,6 +13647,7 @@ Last probe error:
|
|
|
13550
13647
|
databricksHost: host,
|
|
13551
13648
|
lakebaseProjectId,
|
|
13552
13649
|
language,
|
|
13650
|
+
migrationTool: input.migrationTool,
|
|
13553
13651
|
runnerType,
|
|
13554
13652
|
skipCommands,
|
|
13555
13653
|
clientFramework,
|
|
@@ -13664,9 +13762,9 @@ Last probe error:
|
|
|
13664
13762
|
const scmRef = envRef || (ver !== "unknown" ? `v${ver}` : "");
|
|
13665
13763
|
if (scmRef) {
|
|
13666
13764
|
try {
|
|
13667
|
-
const dir =
|
|
13668
|
-
|
|
13669
|
-
|
|
13765
|
+
const dir = path19.join(projectDir, ".lakebase");
|
|
13766
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
13767
|
+
fs19.writeFileSync(path19.join(dir, "scm-utils-ref"), `${scmRef}
|
|
13670
13768
|
`, "utf8");
|
|
13671
13769
|
} catch (err) {
|
|
13672
13770
|
warnings.push(`Substrate ref pin failed (advisory): ${err instanceof Error ? err.message : String(err)}.`);
|
|
@@ -13677,9 +13775,9 @@ Last probe error:
|
|
|
13677
13775
|
const kitRef = process.env.LAKEBASE_KIT_REF?.trim();
|
|
13678
13776
|
if (kitRef) {
|
|
13679
13777
|
try {
|
|
13680
|
-
const dir =
|
|
13681
|
-
|
|
13682
|
-
|
|
13778
|
+
const dir = path19.join(projectDir, ".lakebase");
|
|
13779
|
+
fs19.mkdirSync(dir, { recursive: true });
|
|
13780
|
+
fs19.writeFileSync(path19.join(dir, "kit-ref"), `${kitRef}
|
|
13683
13781
|
`, "utf8");
|
|
13684
13782
|
} catch (err) {
|
|
13685
13783
|
warnings.push(`Kit ref pin failed (advisory): ${err instanceof Error ? err.message : String(err)}.`);
|
|
@@ -13693,9 +13791,21 @@ Last probe error:
|
|
|
13693
13791
|
java: "Java/Spring Boot",
|
|
13694
13792
|
kotlin: "Kotlin/Spring Boot",
|
|
13695
13793
|
python: "Python/FastAPI",
|
|
13696
|
-
nodejs: "Node.js/Express"
|
|
13794
|
+
nodejs: "Node.js/Express",
|
|
13795
|
+
dotnet: `.NET/ASP.NET Core (${input.migrationTool === "flyway" ? "Flyway" : "EF Core"})`
|
|
13697
13796
|
};
|
|
13698
13797
|
const langLabel = langLabels[language] ?? language;
|
|
13798
|
+
if (clientFramework !== "none") {
|
|
13799
|
+
report("Generating client package-lock.json (registry-normalized)...");
|
|
13800
|
+
const lock = await ensureClientLockfile({ projectDir });
|
|
13801
|
+
if (lock.generated) {
|
|
13802
|
+
report(` wrote client/package-lock.json${lock.swaps > 0 ? ` (normalized ${lock.swaps} proxy URL(s) to the public registry)` : ""}`);
|
|
13803
|
+
} else {
|
|
13804
|
+
const m = `Could not generate client/package-lock.json (${lock.reason ?? "unknown"}). Generate it with: (cd client && npm install) \u2014 the lock is committed on first push.`;
|
|
13805
|
+
warnings.push(m);
|
|
13806
|
+
report(`WARNING: ${m}`);
|
|
13807
|
+
}
|
|
13808
|
+
}
|
|
13699
13809
|
report("Creating initial commit...");
|
|
13700
13810
|
await commitAndPush({
|
|
13701
13811
|
projectDir,
|
|
@@ -13760,17 +13870,17 @@ Last probe error:
|
|
|
13760
13870
|
// scripts/lakebase/adopt-lakebase-project.ts
|
|
13761
13871
|
init_esm_shims();
|
|
13762
13872
|
import * as cp5 from "child_process";
|
|
13763
|
-
import * as
|
|
13764
|
-
import * as
|
|
13873
|
+
import * as fs20 from "fs";
|
|
13874
|
+
import * as path20 from "path";
|
|
13765
13875
|
async function adoptLakebaseProject(args) {
|
|
13766
13876
|
const warnings = [];
|
|
13767
13877
|
const filesWritten = [];
|
|
13768
13878
|
const dryRun = args.dryRun === true;
|
|
13769
13879
|
const preserveExistingEnv = args.preserveExistingEnv !== false;
|
|
13770
|
-
if (!
|
|
13880
|
+
if (!fs20.existsSync(args.projectDir)) {
|
|
13771
13881
|
throw new Error(`adoptLakebaseProject: project directory does not exist: ${args.projectDir}`);
|
|
13772
13882
|
}
|
|
13773
|
-
if (!
|
|
13883
|
+
if (!fs20.existsSync(path20.join(args.projectDir, ".git"))) {
|
|
13774
13884
|
throw new Error(
|
|
13775
13885
|
`adoptLakebaseProject: ${args.projectDir} is not a git repo. Run \`git init\` first, or pass an existing repo path.`
|
|
13776
13886
|
);
|
|
@@ -13836,9 +13946,9 @@ async function adoptLakebaseProject(args) {
|
|
|
13836
13946
|
};
|
|
13837
13947
|
}
|
|
13838
13948
|
function assertEnvCompatibility(projectDir, expectedProjectId) {
|
|
13839
|
-
const envPath =
|
|
13840
|
-
if (!
|
|
13841
|
-
const content =
|
|
13949
|
+
const envPath = path20.join(projectDir, ".env");
|
|
13950
|
+
if (!fs20.existsSync(envPath)) return;
|
|
13951
|
+
const content = fs20.readFileSync(envPath, "utf8");
|
|
13842
13952
|
const match = content.match(/^LAKEBASE_PROJECT_ID\s*=\s*(.+?)\s*$/m);
|
|
13843
13953
|
if (!match) return;
|
|
13844
13954
|
const existing = match[1].trim().replace(/^['"]|['"]$/g, "");
|
|
@@ -13849,10 +13959,10 @@ function assertEnvCompatibility(projectDir, expectedProjectId) {
|
|
|
13849
13959
|
}
|
|
13850
13960
|
}
|
|
13851
13961
|
function assertAdoptionPreflight(args) {
|
|
13852
|
-
if (!
|
|
13962
|
+
if (!fs20.existsSync(args.projectDir)) {
|
|
13853
13963
|
throw new Error(`assertAdoptionPreflight: project directory does not exist: ${args.projectDir}`);
|
|
13854
13964
|
}
|
|
13855
|
-
if (!
|
|
13965
|
+
if (!fs20.existsSync(path20.join(args.projectDir, ".git"))) {
|
|
13856
13966
|
throw new Error(
|
|
13857
13967
|
`assertAdoptionPreflight: ${args.projectDir} is not a git repo.`
|
|
13858
13968
|
);
|
|
@@ -13862,11 +13972,11 @@ function assertAdoptionPreflight(args) {
|
|
|
13862
13972
|
}
|
|
13863
13973
|
}
|
|
13864
13974
|
function _testMakeBrownfieldFixture(opts) {
|
|
13865
|
-
|
|
13975
|
+
fs20.mkdirSync(opts.dir, { recursive: true });
|
|
13866
13976
|
cp5.execSync("git init --quiet", { cwd: opts.dir, stdio: "pipe" });
|
|
13867
13977
|
if (opts.packageJson) {
|
|
13868
|
-
|
|
13869
|
-
|
|
13978
|
+
fs20.writeFileSync(
|
|
13979
|
+
path20.join(opts.dir, "package.json"),
|
|
13870
13980
|
JSON.stringify(opts.packageJson, null, 2) + "\n"
|
|
13871
13981
|
);
|
|
13872
13982
|
}
|
|
@@ -13874,8 +13984,8 @@ function _testMakeBrownfieldFixture(opts) {
|
|
|
13874
13984
|
|
|
13875
13985
|
// scripts/lakebase/infra-runner.ts
|
|
13876
13986
|
init_esm_shims();
|
|
13877
|
-
import * as
|
|
13878
|
-
import * as
|
|
13987
|
+
import * as fs30 from "fs";
|
|
13988
|
+
import * as path32 from "path";
|
|
13879
13989
|
|
|
13880
13990
|
// scripts/lakebase/schema-diff.ts
|
|
13881
13991
|
init_esm_shims();
|
|
@@ -14071,18 +14181,84 @@ function dbcli6(args) {
|
|
|
14071
14181
|
|
|
14072
14182
|
// scripts/lakebase/schema-migrate.ts
|
|
14073
14183
|
init_esm_shims();
|
|
14074
|
-
import * as
|
|
14075
|
-
import * as
|
|
14184
|
+
import * as fs29 from "fs";
|
|
14185
|
+
import * as path31 from "path";
|
|
14076
14186
|
|
|
14077
14187
|
// scripts/lakebase/migration-layout.ts
|
|
14078
14188
|
init_esm_shims();
|
|
14079
|
-
import * as
|
|
14080
|
-
import * as
|
|
14189
|
+
import * as fs22 from "fs";
|
|
14190
|
+
import * as path22 from "path";
|
|
14191
|
+
|
|
14192
|
+
// scripts/lakebase/dotnet-project.ts
|
|
14193
|
+
init_esm_shims();
|
|
14194
|
+
import * as fs21 from "fs";
|
|
14195
|
+
import * as path21 from "path";
|
|
14196
|
+
var EF_DESIGN_PACKAGE = "Microsoft.EntityFrameworkCore.Design";
|
|
14197
|
+
var DOTNET_FLYWAY_DIR = path21.join("db", "migrations");
|
|
14198
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["bin", "obj", "node_modules", ".git", "client", "tests", "test"]);
|
|
14199
|
+
function safeReaddir(dir) {
|
|
14200
|
+
try {
|
|
14201
|
+
return fs21.readdirSync(dir, { withFileTypes: true });
|
|
14202
|
+
} catch {
|
|
14203
|
+
return [];
|
|
14204
|
+
}
|
|
14205
|
+
}
|
|
14206
|
+
function hasDotnetMarker(dir) {
|
|
14207
|
+
return safeReaddir(dir).some(
|
|
14208
|
+
(e) => e.isFile() && /\.(sln|slnx|csproj)$/i.test(e.name)
|
|
14209
|
+
);
|
|
14210
|
+
}
|
|
14211
|
+
function findCsprojFiles(projectDir) {
|
|
14212
|
+
const found = [];
|
|
14213
|
+
const walk = (dir, depth) => {
|
|
14214
|
+
for (const e of safeReaddir(dir)) {
|
|
14215
|
+
const full = path21.join(dir, e.name);
|
|
14216
|
+
if (e.isFile() && e.name.toLowerCase().endsWith(".csproj")) {
|
|
14217
|
+
found.push(full);
|
|
14218
|
+
} else if (e.isDirectory() && depth < 2 && !SKIP_DIRS.has(e.name.toLowerCase()) && !e.name.startsWith(".")) {
|
|
14219
|
+
walk(full, depth + 1);
|
|
14220
|
+
}
|
|
14221
|
+
}
|
|
14222
|
+
};
|
|
14223
|
+
walk(projectDir, 0);
|
|
14224
|
+
return found.sort();
|
|
14225
|
+
}
|
|
14226
|
+
function findEfCoreProject(projectDir) {
|
|
14227
|
+
for (const csproj of findCsprojFiles(projectDir)) {
|
|
14228
|
+
let content = "";
|
|
14229
|
+
try {
|
|
14230
|
+
content = fs21.readFileSync(csproj, "utf-8");
|
|
14231
|
+
} catch {
|
|
14232
|
+
continue;
|
|
14233
|
+
}
|
|
14234
|
+
if (content.includes(EF_DESIGN_PACKAGE)) {
|
|
14235
|
+
const dir = path21.dirname(csproj);
|
|
14236
|
+
return { csproj, projectDir: dir, migrationsDir: path21.join(dir, "Migrations") };
|
|
14237
|
+
}
|
|
14238
|
+
}
|
|
14239
|
+
return null;
|
|
14240
|
+
}
|
|
14241
|
+
function isDotnetProject(projectDir) {
|
|
14242
|
+
return hasDotnetMarker(projectDir);
|
|
14243
|
+
}
|
|
14244
|
+
function isDotnetFlywayProject(projectDir) {
|
|
14245
|
+
return isDotnetProject(projectDir) && fs21.existsSync(path21.join(projectDir, DOTNET_FLYWAY_DIR));
|
|
14246
|
+
}
|
|
14247
|
+
var MAVEN_FLYWAY_DIR = path21.join("src", "main", "resources", "db", "migration");
|
|
14248
|
+
function flywayMigrationsDir(projectDir) {
|
|
14249
|
+
const maven = path21.join(projectDir, MAVEN_FLYWAY_DIR);
|
|
14250
|
+
if (fs21.existsSync(maven) || fs21.existsSync(path21.join(projectDir, "pom.xml"))) return maven;
|
|
14251
|
+
if (isDotnetFlywayProject(projectDir)) return path21.join(projectDir, DOTNET_FLYWAY_DIR);
|
|
14252
|
+
return maven;
|
|
14253
|
+
}
|
|
14254
|
+
|
|
14255
|
+
// scripts/lakebase/migration-layout.ts
|
|
14081
14256
|
var MIGRATION_LANGUAGES = [
|
|
14082
14257
|
"java",
|
|
14083
14258
|
"kotlin",
|
|
14084
14259
|
"python",
|
|
14085
14260
|
"nodejs",
|
|
14261
|
+
"dotnet",
|
|
14086
14262
|
"unknown"
|
|
14087
14263
|
];
|
|
14088
14264
|
var MIGRATION_DEFAULTS = {
|
|
@@ -14090,16 +14266,19 @@ var MIGRATION_DEFAULTS = {
|
|
|
14090
14266
|
kotlin: { path: "src/main/resources/db/migration", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" },
|
|
14091
14267
|
python: { path: "alembic/versions", pattern: /^[0-9a-f][\w]*.*\.py$/i, glob: "*.py" },
|
|
14092
14268
|
nodejs: { path: "migrations", pattern: /^\d+.*\.(js|ts)$/i, glob: "*.{js,ts}" },
|
|
14269
|
+
// .NET + Flyway; EF Core projects get their Migrations/ dir from
|
|
14270
|
+
// resolveMigrationLayout (see DOTNET_EFCORE_DEFAULTS).
|
|
14271
|
+
dotnet: { path: "db/migrations", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" },
|
|
14093
14272
|
unknown: { path: "src/main/resources/db/migration", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" }
|
|
14094
14273
|
};
|
|
14095
14274
|
function detectLanguageAt(dir) {
|
|
14096
|
-
if (
|
|
14097
|
-
const kotlinDir =
|
|
14098
|
-
if (
|
|
14275
|
+
if (fs22.existsSync(path22.join(dir, "pom.xml"))) {
|
|
14276
|
+
const kotlinDir = path22.join(dir, "src", "main", "kotlin");
|
|
14277
|
+
if (fs22.existsSync(kotlinDir)) {
|
|
14099
14278
|
return "kotlin";
|
|
14100
14279
|
}
|
|
14101
14280
|
try {
|
|
14102
|
-
const pom =
|
|
14281
|
+
const pom = fs22.readFileSync(path22.join(dir, "pom.xml"), "utf-8");
|
|
14103
14282
|
if (pom.includes("kotlin-maven-plugin")) {
|
|
14104
14283
|
return "kotlin";
|
|
14105
14284
|
}
|
|
@@ -14107,10 +14286,13 @@ function detectLanguageAt(dir) {
|
|
|
14107
14286
|
}
|
|
14108
14287
|
return "java";
|
|
14109
14288
|
}
|
|
14110
|
-
if (
|
|
14289
|
+
if (fs22.existsSync(path22.join(dir, "pyproject.toml")) || fs22.existsSync(path22.join(dir, "requirements.txt")) || fs22.existsSync(path22.join(dir, "alembic.ini"))) {
|
|
14111
14290
|
return "python";
|
|
14112
14291
|
}
|
|
14113
|
-
if (
|
|
14292
|
+
if (hasDotnetMarker(dir)) {
|
|
14293
|
+
return "dotnet";
|
|
14294
|
+
}
|
|
14295
|
+
if (fs22.existsSync(path22.join(dir, "package.json"))) {
|
|
14114
14296
|
return "nodejs";
|
|
14115
14297
|
}
|
|
14116
14298
|
return "unknown";
|
|
@@ -14131,14 +14313,14 @@ function resolveMigrationLanguage(projectDir, configuredMigrationPath, override)
|
|
|
14131
14313
|
if (!rel) {
|
|
14132
14314
|
return "unknown";
|
|
14133
14315
|
}
|
|
14134
|
-
const rootResolved =
|
|
14135
|
-
let dir =
|
|
14136
|
-
while (dir === rootResolved || dir.startsWith(rootResolved +
|
|
14316
|
+
const rootResolved = path22.resolve(projectDir);
|
|
14317
|
+
let dir = path22.resolve(projectDir, rel);
|
|
14318
|
+
while (dir === rootResolved || dir.startsWith(rootResolved + path22.sep)) {
|
|
14137
14319
|
const lang = detectLanguageAt(dir);
|
|
14138
14320
|
if (lang !== "unknown") {
|
|
14139
14321
|
return lang;
|
|
14140
14322
|
}
|
|
14141
|
-
const parent =
|
|
14323
|
+
const parent = path22.dirname(dir);
|
|
14142
14324
|
if (parent === dir) {
|
|
14143
14325
|
break;
|
|
14144
14326
|
}
|
|
@@ -14157,10 +14339,33 @@ function compileMigrationPattern(src) {
|
|
|
14157
14339
|
return void 0;
|
|
14158
14340
|
}
|
|
14159
14341
|
}
|
|
14342
|
+
var DOTNET_EFCORE_DEFAULTS = {
|
|
14343
|
+
path: "Migrations",
|
|
14344
|
+
pattern: /^\d{14}_(?!.*\.Designer\.cs$).+\.cs$/i,
|
|
14345
|
+
glob: "*.cs"
|
|
14346
|
+
};
|
|
14347
|
+
var DOTNET_LAYOUT_TTL_MS = 5e3;
|
|
14348
|
+
var dotnetLayoutCache = /* @__PURE__ */ new Map();
|
|
14349
|
+
function dotnetDefaults(projectDir) {
|
|
14350
|
+
if (!projectDir) return MIGRATION_DEFAULTS.dotnet;
|
|
14351
|
+
const key = path22.resolve(projectDir);
|
|
14352
|
+
const hit = dotnetLayoutCache.get(key);
|
|
14353
|
+
if (hit && Date.now() - hit.at < DOTNET_LAYOUT_TTL_MS) return hit.value;
|
|
14354
|
+
let value = MIGRATION_DEFAULTS.dotnet;
|
|
14355
|
+
if (!isDotnetFlywayProject(projectDir)) {
|
|
14356
|
+
const ef = findEfCoreProject(projectDir);
|
|
14357
|
+
if (ef) {
|
|
14358
|
+
const rel = path22.relative(projectDir, ef.migrationsDir).split(path22.sep).join("/");
|
|
14359
|
+
value = { ...DOTNET_EFCORE_DEFAULTS, path: rel };
|
|
14360
|
+
}
|
|
14361
|
+
}
|
|
14362
|
+
dotnetLayoutCache.set(key, { at: Date.now(), value });
|
|
14363
|
+
return value;
|
|
14364
|
+
}
|
|
14160
14365
|
function resolveMigrationLayout(args) {
|
|
14161
14366
|
const configuredMigrationPath = (args.migrationPath ?? "").trim();
|
|
14162
14367
|
const language = resolveMigrationLanguage(args.projectDir, configuredMigrationPath, args.language);
|
|
14163
|
-
const defaults = MIGRATION_DEFAULTS[language];
|
|
14368
|
+
const defaults = language === "dotnet" ? dotnetDefaults(args.projectDir) : MIGRATION_DEFAULTS[language];
|
|
14164
14369
|
return {
|
|
14165
14370
|
language,
|
|
14166
14371
|
migrationPath: configuredMigrationPath || defaults.path,
|
|
@@ -14171,22 +14376,22 @@ function resolveMigrationLayout(args) {
|
|
|
14171
14376
|
|
|
14172
14377
|
// scripts/lakebase/adapters/alembic-adapter.ts
|
|
14173
14378
|
init_esm_shims();
|
|
14174
|
-
import * as
|
|
14175
|
-
import * as
|
|
14379
|
+
import * as fs24 from "fs";
|
|
14380
|
+
import * as path24 from "path";
|
|
14176
14381
|
|
|
14177
14382
|
// scripts/lakebase/schema-migrate-runners/alembic.ts
|
|
14178
14383
|
init_esm_shims();
|
|
14179
14384
|
import { spawn as spawn5 } from "child_process";
|
|
14180
|
-
import * as
|
|
14181
|
-
import * as
|
|
14385
|
+
import * as fs23 from "fs";
|
|
14386
|
+
import * as path23 from "path";
|
|
14182
14387
|
function resolveAlembicBin(projectDir) {
|
|
14183
14388
|
const candidates = [
|
|
14184
|
-
|
|
14185
|
-
|
|
14389
|
+
path23.join(projectDir, ".venv", "bin", "alembic"),
|
|
14390
|
+
path23.join(projectDir, "venv", "bin", "alembic")
|
|
14186
14391
|
];
|
|
14187
14392
|
for (const candidate of candidates) {
|
|
14188
14393
|
try {
|
|
14189
|
-
if (
|
|
14394
|
+
if (fs23.existsSync(candidate)) return candidate;
|
|
14190
14395
|
} catch {
|
|
14191
14396
|
}
|
|
14192
14397
|
}
|
|
@@ -14196,7 +14401,7 @@ function spawnAlembic(projectDir, args, dsn) {
|
|
|
14196
14401
|
return new Promise((resolve2, reject) => {
|
|
14197
14402
|
const bin = resolveAlembicBin(projectDir);
|
|
14198
14403
|
const env = { ...process.env };
|
|
14199
|
-
env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(
|
|
14404
|
+
env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path23.delimiter);
|
|
14200
14405
|
if (dsn) env.DATABASE_URL = dsn;
|
|
14201
14406
|
const child = spawn5(bin, args, {
|
|
14202
14407
|
cwd: projectDir,
|
|
@@ -14244,10 +14449,10 @@ async function createAlembicRevision(opts) {
|
|
|
14244
14449
|
const m = stdout.match(/Generating\s+(\S+\.py)/);
|
|
14245
14450
|
if (m) return m[1].trim();
|
|
14246
14451
|
for (const rel of ["migrations/versions", "alembic/versions"]) {
|
|
14247
|
-
const dir =
|
|
14248
|
-
if (!
|
|
14249
|
-
const hit =
|
|
14250
|
-
if (hit) return
|
|
14452
|
+
const dir = path23.join(opts.projectDir, rel);
|
|
14453
|
+
if (!fs23.existsSync(dir)) continue;
|
|
14454
|
+
const hit = fs23.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
|
|
14455
|
+
if (hit) return path23.join(dir, hit);
|
|
14251
14456
|
}
|
|
14252
14457
|
throw new SchemaMigrationError(
|
|
14253
14458
|
`alembic revision succeeded but the created file could not be located.
|
|
@@ -14382,15 +14587,15 @@ async function buildDsn2(args) {
|
|
|
14382
14587
|
}
|
|
14383
14588
|
function findVersionsDir(projectDir) {
|
|
14384
14589
|
const candidates = [
|
|
14385
|
-
|
|
14386
|
-
|
|
14590
|
+
path24.join(projectDir, "migrations", "versions"),
|
|
14591
|
+
path24.join(projectDir, "alembic", "versions")
|
|
14387
14592
|
];
|
|
14388
|
-
return candidates.find((p) =>
|
|
14593
|
+
return candidates.find((p) => fs24.existsSync(p));
|
|
14389
14594
|
}
|
|
14390
14595
|
function listAlembicFiles(projectDir) {
|
|
14391
14596
|
const dir = findVersionsDir(projectDir);
|
|
14392
14597
|
if (!dir) return [];
|
|
14393
|
-
const files =
|
|
14598
|
+
const files = fs24.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
|
|
14394
14599
|
return files.map((filename) => {
|
|
14395
14600
|
const stem = filename.replace(/\.py$/, "");
|
|
14396
14601
|
const sep4 = stem.indexOf("_");
|
|
@@ -14415,9 +14620,9 @@ var AlembicAdapter = {
|
|
|
14415
14620
|
* here. Callers can still force-select via project.yaml#migration_tool.
|
|
14416
14621
|
*/
|
|
14417
14622
|
detect(projectDir) {
|
|
14418
|
-
if (
|
|
14419
|
-
if (
|
|
14420
|
-
if (
|
|
14623
|
+
if (fs24.existsSync(path24.join(projectDir, "alembic.ini"))) return true;
|
|
14624
|
+
if (fs24.existsSync(path24.join(projectDir, "migrations", "env.py"))) return true;
|
|
14625
|
+
if (fs24.existsSync(path24.join(projectDir, "alembic", "env.py"))) return true;
|
|
14421
14626
|
return false;
|
|
14422
14627
|
},
|
|
14423
14628
|
async apply(args) {
|
|
@@ -14523,7 +14728,7 @@ var AlembicAdapter = {
|
|
|
14523
14728
|
autogenerate: !!args.autogenerate,
|
|
14524
14729
|
dsn
|
|
14525
14730
|
});
|
|
14526
|
-
return { status: "ok", version: revId, filename:
|
|
14731
|
+
return { status: "ok", version: revId, filename: path24.basename(created), path: created };
|
|
14527
14732
|
} catch (err) {
|
|
14528
14733
|
return {
|
|
14529
14734
|
status: "error",
|
|
@@ -14540,7 +14745,7 @@ var AlembicAdapter = {
|
|
|
14540
14745
|
if (heads.length <= 1) return { status: "noop", headsBefore: heads };
|
|
14541
14746
|
if (args.dryRun) return { status: "ok", headsBefore: heads };
|
|
14542
14747
|
const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
|
|
14543
|
-
const mergeRevision =
|
|
14748
|
+
const mergeRevision = path24.basename(created).replace(/\.py$/, "").split("_")[0];
|
|
14544
14749
|
return { status: "ok", headsBefore: heads, mergeRevision, path: created };
|
|
14545
14750
|
} catch (err) {
|
|
14546
14751
|
return {
|
|
@@ -14555,13 +14760,13 @@ registerSchemaMigrationAdapter(AlembicAdapter);
|
|
|
14555
14760
|
|
|
14556
14761
|
// scripts/lakebase/adapters/flyway-adapter.ts
|
|
14557
14762
|
init_esm_shims();
|
|
14558
|
-
import * as
|
|
14559
|
-
import * as
|
|
14763
|
+
import * as fs25 from "fs";
|
|
14764
|
+
import * as path26 from "path";
|
|
14560
14765
|
|
|
14561
14766
|
// scripts/lakebase/schema-migrate-runners/flyway.ts
|
|
14562
14767
|
init_esm_shims();
|
|
14563
14768
|
import { spawn as spawn6 } from "child_process";
|
|
14564
|
-
import * as
|
|
14769
|
+
import * as path25 from "path";
|
|
14565
14770
|
function dsnToFlywayEnv(dsn) {
|
|
14566
14771
|
const u = new URL(dsn);
|
|
14567
14772
|
const user = decodeURIComponent(u.username);
|
|
@@ -14571,7 +14776,7 @@ function dsnToFlywayEnv(dsn) {
|
|
|
14571
14776
|
return { url, user, password };
|
|
14572
14777
|
}
|
|
14573
14778
|
function migrationsLocation(projectDir) {
|
|
14574
|
-
return `filesystem:${
|
|
14779
|
+
return `filesystem:${flywayMigrationsDir(projectDir)}`;
|
|
14575
14780
|
}
|
|
14576
14781
|
function runFlyway(ctx, args) {
|
|
14577
14782
|
const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
|
|
@@ -14672,7 +14877,7 @@ async function statusFlyway(ctx) {
|
|
|
14672
14877
|
if (state === "SUCCESS" || state === "BASELINE") {
|
|
14673
14878
|
current = m.version;
|
|
14674
14879
|
} else if (state === "PENDING") {
|
|
14675
|
-
const filename = m.filepath ?
|
|
14880
|
+
const filename = m.filepath ? path25.basename(m.filepath) : `V${m.version}__migration.sql`;
|
|
14676
14881
|
pending.push({
|
|
14677
14882
|
version: m.version,
|
|
14678
14883
|
filename,
|
|
@@ -14695,9 +14900,9 @@ async function buildDsn3(args) {
|
|
|
14695
14900
|
return result.url;
|
|
14696
14901
|
}
|
|
14697
14902
|
function listFlywayFiles(projectDir) {
|
|
14698
|
-
const dir =
|
|
14699
|
-
if (!
|
|
14700
|
-
const files =
|
|
14903
|
+
const dir = flywayMigrationsDir(projectDir);
|
|
14904
|
+
if (!fs25.existsSync(dir)) return [];
|
|
14905
|
+
const files = fs25.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
|
|
14701
14906
|
return files.map((filename) => {
|
|
14702
14907
|
const m = filename.match(/^V(\d+(?:\.\d+)*)__(.+)\.sql$/);
|
|
14703
14908
|
const version = m[1];
|
|
@@ -14718,9 +14923,9 @@ function versionCompare(a, b) {
|
|
|
14718
14923
|
}
|
|
14719
14924
|
var FlywayAdapter = {
|
|
14720
14925
|
id: "flyway",
|
|
14721
|
-
languages: ["java", "kotlin"],
|
|
14926
|
+
languages: ["java", "kotlin", "dotnet"],
|
|
14722
14927
|
detect(projectDir) {
|
|
14723
|
-
return
|
|
14928
|
+
return fs25.existsSync(path26.join(projectDir, "pom.xml")) || isDotnetFlywayProject(projectDir);
|
|
14724
14929
|
},
|
|
14725
14930
|
async apply(args) {
|
|
14726
14931
|
const dsn = await buildDsn3(args);
|
|
@@ -14778,14 +14983,14 @@ var FlywayAdapter = {
|
|
|
14778
14983
|
// optional-protocol shape makes this additive.
|
|
14779
14984
|
async newMigration(args) {
|
|
14780
14985
|
try {
|
|
14781
|
-
const dir =
|
|
14782
|
-
|
|
14986
|
+
const dir = flywayMigrationsDir(args.projectDir);
|
|
14987
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
14783
14988
|
const version = migrationTimestamp();
|
|
14784
14989
|
const slug = migrationSlug2(args.slug);
|
|
14785
14990
|
const filename = `V${version}__${slug}.sql`;
|
|
14786
|
-
const full =
|
|
14787
|
-
if (
|
|
14788
|
-
|
|
14991
|
+
const full = path26.join(dir, filename);
|
|
14992
|
+
if (fs25.existsSync(full)) throw new Error(`${filename} already exists`);
|
|
14993
|
+
fs25.writeFileSync(
|
|
14789
14994
|
full,
|
|
14790
14995
|
`-- V${version}: ${args.slug}
|
|
14791
14996
|
-- Flyway migration (write your DDL/DML below).
|
|
@@ -14808,19 +15013,19 @@ registerSchemaMigrationAdapter(FlywayAdapter);
|
|
|
14808
15013
|
|
|
14809
15014
|
// scripts/lakebase/adapters/knex-adapter.ts
|
|
14810
15015
|
init_esm_shims();
|
|
14811
|
-
import * as
|
|
14812
|
-
import * as
|
|
15016
|
+
import * as fs27 from "fs";
|
|
15017
|
+
import * as path28 from "path";
|
|
14813
15018
|
|
|
14814
15019
|
// scripts/lakebase/schema-migrate-runners/knex.ts
|
|
14815
15020
|
init_esm_shims();
|
|
14816
15021
|
import { spawn as spawn7 } from "child_process";
|
|
14817
|
-
import * as
|
|
14818
|
-
import * as
|
|
15022
|
+
import * as fs26 from "fs";
|
|
15023
|
+
import * as path27 from "path";
|
|
14819
15024
|
var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
|
|
14820
15025
|
function findKnexfile(projectDir) {
|
|
14821
15026
|
for (const name of KNEXFILE_VARIANTS) {
|
|
14822
|
-
const p =
|
|
14823
|
-
if (
|
|
15027
|
+
const p = path27.join(projectDir, name);
|
|
15028
|
+
if (fs26.existsSync(p)) return p;
|
|
14824
15029
|
}
|
|
14825
15030
|
return void 0;
|
|
14826
15031
|
}
|
|
@@ -14972,9 +15177,9 @@ async function buildDsn4(args) {
|
|
|
14972
15177
|
}
|
|
14973
15178
|
var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
|
|
14974
15179
|
function listKnexFiles(projectDir) {
|
|
14975
|
-
const dir =
|
|
14976
|
-
if (!
|
|
14977
|
-
const files =
|
|
15180
|
+
const dir = path28.join(projectDir, "migrations");
|
|
15181
|
+
if (!fs27.existsSync(dir)) return [];
|
|
15182
|
+
const files = fs27.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
|
|
14978
15183
|
return files.map((filename) => {
|
|
14979
15184
|
const stem = filename.replace(/\.(js|ts)$/, "");
|
|
14980
15185
|
const m = stem.match(/^(\d{14})_(.+)$/);
|
|
@@ -14994,7 +15199,7 @@ var KnexAdapter = {
|
|
|
14994
15199
|
* project.yaml#migration_tool.
|
|
14995
15200
|
*/
|
|
14996
15201
|
detect(projectDir) {
|
|
14997
|
-
return KNEXFILE_VARIANTS2.some((name) =>
|
|
15202
|
+
return KNEXFILE_VARIANTS2.some((name) => fs27.existsSync(path28.join(projectDir, name)));
|
|
14998
15203
|
},
|
|
14999
15204
|
async apply(args) {
|
|
15000
15205
|
const dsn = await buildDsn4(args);
|
|
@@ -15067,9 +15272,9 @@ var KnexAdapter = {
|
|
|
15067
15272
|
async newMigration(args) {
|
|
15068
15273
|
try {
|
|
15069
15274
|
const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
|
|
15070
|
-
const stem =
|
|
15275
|
+
const stem = path28.basename(created).replace(/\.(js|ts)$/, "");
|
|
15071
15276
|
const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
|
|
15072
|
-
return { status: "ok", version, filename:
|
|
15277
|
+
return { status: "ok", version, filename: path28.basename(created), path: created };
|
|
15073
15278
|
} catch (err) {
|
|
15074
15279
|
return {
|
|
15075
15280
|
status: "error",
|
|
@@ -15083,6 +15288,362 @@ var KnexAdapter = {
|
|
|
15083
15288
|
};
|
|
15084
15289
|
registerSchemaMigrationAdapter(KnexAdapter);
|
|
15085
15290
|
|
|
15291
|
+
// scripts/lakebase/adapters/efcore-adapter.ts
|
|
15292
|
+
init_esm_shims();
|
|
15293
|
+
import * as path30 from "path";
|
|
15294
|
+
|
|
15295
|
+
// scripts/lakebase/schema-migrate-runners/efcore.ts
|
|
15296
|
+
init_esm_shims();
|
|
15297
|
+
import { spawn as spawn8 } from "child_process";
|
|
15298
|
+
import * as fs28 from "fs";
|
|
15299
|
+
import * as path29 from "path";
|
|
15300
|
+
import { Client as Client3 } from "pg";
|
|
15301
|
+
var MIGRATION_ID = /^(\d{14})_(.+)$/;
|
|
15302
|
+
function efVersion(id) {
|
|
15303
|
+
return MIGRATION_ID.exec(id)?.[1] ?? id;
|
|
15304
|
+
}
|
|
15305
|
+
function efDescription(id) {
|
|
15306
|
+
const name = MIGRATION_ID.exec(id)?.[2] ?? id;
|
|
15307
|
+
return name.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2");
|
|
15308
|
+
}
|
|
15309
|
+
function dsnToNpgsql(dsn) {
|
|
15310
|
+
const u = new URL(dsn);
|
|
15311
|
+
const parts = [
|
|
15312
|
+
`Host=${u.hostname}`,
|
|
15313
|
+
`Port=${u.port || "5432"}`,
|
|
15314
|
+
`Database=${decodeURIComponent(u.pathname.replace(/^\//, "")) || "databricks_postgres"}`
|
|
15315
|
+
];
|
|
15316
|
+
if (u.username) parts.push(`Username=${decodeURIComponent(u.username)}`);
|
|
15317
|
+
if (u.password) parts.push(`Password=${decodeURIComponent(u.password)}`);
|
|
15318
|
+
const sslmode = (u.searchParams.get("sslmode") ?? "require").toLowerCase();
|
|
15319
|
+
const ssl = {
|
|
15320
|
+
disable: "Disable",
|
|
15321
|
+
allow: "Allow",
|
|
15322
|
+
prefer: "Prefer",
|
|
15323
|
+
require: "Require",
|
|
15324
|
+
"verify-ca": "VerifyCA",
|
|
15325
|
+
"verify-full": "VerifyFull"
|
|
15326
|
+
};
|
|
15327
|
+
parts.push(`SSL Mode=${ssl[sslmode] ?? "Require"}`);
|
|
15328
|
+
const app = u.searchParams.get("application_name");
|
|
15329
|
+
if (app) parts.push(`Application Name=${app}`);
|
|
15330
|
+
return parts.map((p) => p.replace(/;/g, "")).join(";");
|
|
15331
|
+
}
|
|
15332
|
+
function parseEfJson(stdout) {
|
|
15333
|
+
const body = stdout.split(/\r?\n/).filter((l) => l.startsWith("data:")).map((l) => l.slice("data:".length)).join("\n").trim();
|
|
15334
|
+
if (!body) {
|
|
15335
|
+
throw new SchemaMigrationError(`dotnet ef returned no JSON payload: ${stdout.slice(0, 400)}`);
|
|
15336
|
+
}
|
|
15337
|
+
try {
|
|
15338
|
+
return JSON.parse(body);
|
|
15339
|
+
} catch (err) {
|
|
15340
|
+
throw new SchemaMigrationError(
|
|
15341
|
+
`dotnet ef JSON parse failed: ${err instanceof Error ? err.message : String(err)}.
|
|
15342
|
+
Body (first 400 chars): ${body.slice(0, 400)}`
|
|
15343
|
+
);
|
|
15344
|
+
}
|
|
15345
|
+
}
|
|
15346
|
+
function requireProject(projectDir) {
|
|
15347
|
+
const project = findEfCoreProject(projectDir);
|
|
15348
|
+
if (!project) {
|
|
15349
|
+
throw new SchemaMigrationError(
|
|
15350
|
+
`No EF Core project found under ${projectDir}. Expected a *.csproj that references ${EF_DESIGN_PACKAGE}.`
|
|
15351
|
+
);
|
|
15352
|
+
}
|
|
15353
|
+
return project;
|
|
15354
|
+
}
|
|
15355
|
+
function spawnDotnet(projectDir, args, env) {
|
|
15356
|
+
return new Promise((resolve2, reject) => {
|
|
15357
|
+
const child = spawn8("dotnet", args, {
|
|
15358
|
+
cwd: projectDir,
|
|
15359
|
+
env: { ...process.env, DOTNET_NOLOGO: "1", DOTNET_CLI_TELEMETRY_OPTOUT: "1", ...env },
|
|
15360
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
15361
|
+
});
|
|
15362
|
+
let stdout = "";
|
|
15363
|
+
let stderr = "";
|
|
15364
|
+
child.stdout.on("data", (chunk) => {
|
|
15365
|
+
stdout += chunk.toString("utf8");
|
|
15366
|
+
});
|
|
15367
|
+
child.stderr.on("data", (chunk) => {
|
|
15368
|
+
stderr += chunk.toString("utf8");
|
|
15369
|
+
});
|
|
15370
|
+
child.on("error", (err) => {
|
|
15371
|
+
reject(
|
|
15372
|
+
new SchemaMigrationError(
|
|
15373
|
+
`Could not spawn dotnet. Is the .NET SDK installed and on PATH? ${err.message}`,
|
|
15374
|
+
err
|
|
15375
|
+
)
|
|
15376
|
+
);
|
|
15377
|
+
});
|
|
15378
|
+
child.on("close", (code) => {
|
|
15379
|
+
if (code === 0) {
|
|
15380
|
+
resolve2({ stdout, stderr });
|
|
15381
|
+
} else {
|
|
15382
|
+
reject(
|
|
15383
|
+
new SchemaMigrationError(
|
|
15384
|
+
`dotnet ${args.join(" ")} exited with code ${code}.
|
|
15385
|
+
stdout: ${stdout}
|
|
15386
|
+
stderr: ${stderr}`
|
|
15387
|
+
)
|
|
15388
|
+
);
|
|
15389
|
+
}
|
|
15390
|
+
});
|
|
15391
|
+
});
|
|
15392
|
+
}
|
|
15393
|
+
var restored = /* @__PURE__ */ new Set();
|
|
15394
|
+
async function ensureRestored(projectDir, csproj) {
|
|
15395
|
+
if (restored.has(projectDir)) return;
|
|
15396
|
+
if (fs28.existsSync(path29.join(projectDir, ".config", "dotnet-tools.json"))) {
|
|
15397
|
+
await spawnDotnet(projectDir, ["tool", "restore"], {});
|
|
15398
|
+
}
|
|
15399
|
+
await spawnDotnet(projectDir, ["restore", csproj], {});
|
|
15400
|
+
restored.add(projectDir);
|
|
15401
|
+
}
|
|
15402
|
+
async function runEf(projectDir, args, dsn, opts = {}) {
|
|
15403
|
+
const project = requireProject(projectDir);
|
|
15404
|
+
const csproj = path29.relative(projectDir, project.csproj) || project.csproj;
|
|
15405
|
+
await ensureRestored(projectDir, csproj);
|
|
15406
|
+
const full = ["ef", ...args, "--project", csproj, "--prefix-output"];
|
|
15407
|
+
if (opts.noBuild) full.push("--no-build");
|
|
15408
|
+
const env = {};
|
|
15409
|
+
if (dsn) {
|
|
15410
|
+
env.DATABASE_URL = dsn;
|
|
15411
|
+
if (process.env.LAKEBASE_EFCORE_CONNECTION_ARG === "1") full.push("--connection", dsnToNpgsql(dsn));
|
|
15412
|
+
}
|
|
15413
|
+
return spawnDotnet(projectDir, full, env);
|
|
15414
|
+
}
|
|
15415
|
+
async function listEfMigrations(ctx, opts = {}) {
|
|
15416
|
+
const { stdout, stderr } = await runEf(ctx.projectDir, ["migrations", "list", "--json"], ctx.dsn, opts);
|
|
15417
|
+
const entries = parseEfJson(stdout);
|
|
15418
|
+
if (ctx.dsn && entries.some((e) => e.applied === null)) {
|
|
15419
|
+
const warning = stdout.split(/\r?\n/).filter((l) => /^(warn|error):/.test(l)).join("\n");
|
|
15420
|
+
throw new SchemaMigrationError(
|
|
15421
|
+
`dotnet ef could not read migration state from the database (check connectivity and credentials).
|
|
15422
|
+
${warning || stderr}`.trim()
|
|
15423
|
+
);
|
|
15424
|
+
}
|
|
15425
|
+
return entries;
|
|
15426
|
+
}
|
|
15427
|
+
async function readEfHistory(dsn) {
|
|
15428
|
+
const client = new Client3({ connectionString: dsn, application_name: connectionApplicationName() });
|
|
15429
|
+
await client.connect();
|
|
15430
|
+
try {
|
|
15431
|
+
const exists = await client.query(`SELECT to_regclass('"__EFMigrationsHistory"') IS NOT NULL AS present`);
|
|
15432
|
+
if (!exists.rows[0]?.present) return null;
|
|
15433
|
+
const r = await client.query(`SELECT "MigrationId" FROM "__EFMigrationsHistory" ORDER BY "MigrationId"`);
|
|
15434
|
+
return r.rows.map((row) => row.MigrationId);
|
|
15435
|
+
} finally {
|
|
15436
|
+
await client.end();
|
|
15437
|
+
}
|
|
15438
|
+
}
|
|
15439
|
+
function toApplied(entries) {
|
|
15440
|
+
return entries.map((e) => ({ version: efVersion(e.id), description: efDescription(e.id) }));
|
|
15441
|
+
}
|
|
15442
|
+
async function statusEfcore(ctx) {
|
|
15443
|
+
const entries = await listEfMigrations(ctx);
|
|
15444
|
+
const history = await (ctx.readHistory ?? readEfHistory)(ctx.dsn);
|
|
15445
|
+
const current = history && history.length > 0 ? efVersion(history[history.length - 1]) : void 0;
|
|
15446
|
+
const pending = entries.filter((e) => e.applied !== true).map((e) => ({ version: efVersion(e.id), filename: `${e.id}.cs`, description: efDescription(e.id) }));
|
|
15447
|
+
return { current, pending, tool: "efcore" };
|
|
15448
|
+
}
|
|
15449
|
+
async function applyEfcore(ctx) {
|
|
15450
|
+
const before = new Set((await listEfMigrations(ctx)).filter((e) => e.applied).map((e) => e.id));
|
|
15451
|
+
await runEf(ctx.projectDir, ["database", "update"], ctx.dsn, { noBuild: true });
|
|
15452
|
+
const after = await listEfMigrations(ctx, { noBuild: true });
|
|
15453
|
+
const applied = toApplied(after.filter((e) => e.applied && !before.has(e.id)));
|
|
15454
|
+
return { applied, alreadyAtLatest: applied.length === 0, tool: "efcore" };
|
|
15455
|
+
}
|
|
15456
|
+
function resolveEfTarget(target, applied) {
|
|
15457
|
+
const t = target.trim();
|
|
15458
|
+
if (t === "0") return "0";
|
|
15459
|
+
const rel = /^-(\d+)$/.exec(t);
|
|
15460
|
+
if (rel) {
|
|
15461
|
+
const steps = Number(rel[1]);
|
|
15462
|
+
if (steps < 1) throw new SchemaMigrationError(`Invalid rollback step: ${target}`);
|
|
15463
|
+
const index = applied.length - 1 - steps;
|
|
15464
|
+
if (index < -1) {
|
|
15465
|
+
throw new SchemaMigrationError(`Cannot roll back ${steps} migration(s); only ${applied.length} applied.`);
|
|
15466
|
+
}
|
|
15467
|
+
return index === -1 ? "0" : applied[index].id;
|
|
15468
|
+
}
|
|
15469
|
+
const match = applied.find((e) => e.id === t || efVersion(e.id) === t || e.name === t);
|
|
15470
|
+
if (!match) throw new SchemaMigrationError(`Rollback target '${target}' is not an applied migration.`);
|
|
15471
|
+
return match.id;
|
|
15472
|
+
}
|
|
15473
|
+
async function rollbackEfcore(ctx) {
|
|
15474
|
+
const beforeEntries = (await listEfMigrations(ctx)).filter((e) => e.applied);
|
|
15475
|
+
const targetId = resolveEfTarget(ctx.target, beforeEntries);
|
|
15476
|
+
await runEf(ctx.projectDir, ["database", "update", targetId], ctx.dsn, { noBuild: true });
|
|
15477
|
+
const stillApplied = new Set((await listEfMigrations(ctx, { noBuild: true })).filter((e) => e.applied).map((e) => e.id));
|
|
15478
|
+
return { rolledBack: toApplied(beforeEntries.filter((e) => !stillApplied.has(e.id)).reverse()), tool: "efcore" };
|
|
15479
|
+
}
|
|
15480
|
+
function efMigrationName(slug) {
|
|
15481
|
+
const name = slug.split(/[^A-Za-z0-9]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join("");
|
|
15482
|
+
if (!name) throw new SchemaMigrationError(`Cannot derive a migration name from '${slug}'.`);
|
|
15483
|
+
return /^[0-9]/.test(name) ? `M${name}` : name;
|
|
15484
|
+
}
|
|
15485
|
+
async function createEfcoreMigration(opts) {
|
|
15486
|
+
const project = requireProject(opts.projectDir);
|
|
15487
|
+
const name = efMigrationName(opts.slug);
|
|
15488
|
+
const existing = new Set(fs28.existsSync(project.migrationsDir) ? fs28.readdirSync(project.migrationsDir) : []);
|
|
15489
|
+
await runEf(opts.projectDir, ["migrations", "add", name]);
|
|
15490
|
+
const created = fs28.readdirSync(project.migrationsDir).filter((f) => !existing.has(f) && MIGRATION_ID.test(f.replace(/\.cs$/, "")) && !f.endsWith(".Designer.cs"));
|
|
15491
|
+
if (created.length !== 1) {
|
|
15492
|
+
throw new SchemaMigrationError(`Expected one new migration file for ${name}, found: ${created.join(", ") || "none"}`);
|
|
15493
|
+
}
|
|
15494
|
+
return { id: created[0].replace(/\.cs$/, ""), path: path29.join(project.migrationsDir, created[0]) };
|
|
15495
|
+
}
|
|
15496
|
+
function localEfMigrationIds(projectDir) {
|
|
15497
|
+
const project = findEfCoreProject(projectDir);
|
|
15498
|
+
if (!project || !fs28.existsSync(project.migrationsDir)) return [];
|
|
15499
|
+
return fs28.readdirSync(project.migrationsDir).filter((f) => f.endsWith(".cs") && !f.endsWith(".Designer.cs") && MIGRATION_ID.test(f.slice(0, -3))).map((f) => f.slice(0, -3)).sort();
|
|
15500
|
+
}
|
|
15501
|
+
function efProductVersion(project) {
|
|
15502
|
+
try {
|
|
15503
|
+
const csproj = fs28.readFileSync(project.csproj, "utf-8");
|
|
15504
|
+
const m = new RegExp(`${EF_DESIGN_PACKAGE.replace(/\./g, "\\.")}"\\s+Version="([^"]+)"`).exec(csproj);
|
|
15505
|
+
if (m) return m[1];
|
|
15506
|
+
} catch {
|
|
15507
|
+
}
|
|
15508
|
+
return "unknown";
|
|
15509
|
+
}
|
|
15510
|
+
async function stampEfcore(ctx) {
|
|
15511
|
+
const project = requireProject(ctx.projectDir);
|
|
15512
|
+
const ids = localEfMigrationIds(ctx.projectDir);
|
|
15513
|
+
if (ids.length === 0) throw new SchemaMigrationError("No local EF Core migrations to stamp.");
|
|
15514
|
+
const rev = ctx.revision.trim();
|
|
15515
|
+
const end = rev === "head" ? ids.length - 1 : ids.findIndex((id) => id === rev || efVersion(id) === rev);
|
|
15516
|
+
if (end < 0) throw new SchemaMigrationError(`Stamp revision '${ctx.revision}' is not a local migration.`);
|
|
15517
|
+
const toStamp = ids.slice(0, end + 1);
|
|
15518
|
+
const productVersion = efProductVersion(project);
|
|
15519
|
+
const client = new Client3({ connectionString: ctx.dsn, application_name: connectionApplicationName() });
|
|
15520
|
+
await client.connect();
|
|
15521
|
+
try {
|
|
15522
|
+
await client.query("BEGIN");
|
|
15523
|
+
await client.query(
|
|
15524
|
+
`CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
|
|
15525
|
+
"MigrationId" character varying(150) NOT NULL,
|
|
15526
|
+
"ProductVersion" character varying(32) NOT NULL,
|
|
15527
|
+
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId"))`
|
|
15528
|
+
);
|
|
15529
|
+
await client.query(`DELETE FROM "__EFMigrationsHistory" WHERE NOT ("MigrationId" = ANY($1::text[]))`, [toStamp]);
|
|
15530
|
+
for (const id of toStamp) {
|
|
15531
|
+
await client.query(
|
|
15532
|
+
`INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ($1, $2)
|
|
15533
|
+
ON CONFLICT ("MigrationId") DO NOTHING`,
|
|
15534
|
+
[id, productVersion]
|
|
15535
|
+
);
|
|
15536
|
+
}
|
|
15537
|
+
await client.query("COMMIT");
|
|
15538
|
+
} catch (err) {
|
|
15539
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
15540
|
+
throw err;
|
|
15541
|
+
} finally {
|
|
15542
|
+
await client.end();
|
|
15543
|
+
}
|
|
15544
|
+
return efVersion(toStamp[toStamp.length - 1]);
|
|
15545
|
+
}
|
|
15546
|
+
|
|
15547
|
+
// scripts/lakebase/adapters/efcore-adapter.ts
|
|
15548
|
+
async function buildDsn5(args) {
|
|
15549
|
+
const result = await getConnection({
|
|
15550
|
+
output: "dsn",
|
|
15551
|
+
instance: args.instance,
|
|
15552
|
+
branch: args.branch,
|
|
15553
|
+
database: args.database,
|
|
15554
|
+
endpointName: args.endpointName
|
|
15555
|
+
});
|
|
15556
|
+
return result.url;
|
|
15557
|
+
}
|
|
15558
|
+
function errMsg(err) {
|
|
15559
|
+
return err instanceof Error ? err.message : String(err);
|
|
15560
|
+
}
|
|
15561
|
+
function listEfCoreFiles(projectDir) {
|
|
15562
|
+
return localEfMigrationIds(projectDir).map((id) => ({
|
|
15563
|
+
version: efVersion(id),
|
|
15564
|
+
filename: `${id}.cs`,
|
|
15565
|
+
description: efDescription(id),
|
|
15566
|
+
type: "CSharp",
|
|
15567
|
+
tool: "efcore"
|
|
15568
|
+
}));
|
|
15569
|
+
}
|
|
15570
|
+
var EfCoreAdapter = {
|
|
15571
|
+
id: "efcore",
|
|
15572
|
+
languages: ["dotnet"],
|
|
15573
|
+
/** A .NET project (root marker) with a *.csproj that references Microsoft.EntityFrameworkCore.Design. */
|
|
15574
|
+
detect(projectDir) {
|
|
15575
|
+
return isDotnetProject(projectDir) && findEfCoreProject(projectDir) !== null;
|
|
15576
|
+
},
|
|
15577
|
+
async apply(args) {
|
|
15578
|
+
try {
|
|
15579
|
+
const dsn = await buildDsn5(args);
|
|
15580
|
+
const r = await applyEfcore({ projectDir: args.projectDir, dsn });
|
|
15581
|
+
return {
|
|
15582
|
+
applied_migrations: r.applied,
|
|
15583
|
+
status: r.alreadyAtLatest ? "noop" : "ok",
|
|
15584
|
+
tool_specific: { alreadyAtLatest: r.alreadyAtLatest, tool: r.tool }
|
|
15585
|
+
};
|
|
15586
|
+
} catch (err) {
|
|
15587
|
+
return { applied_migrations: [], status: "error", error: errMsg(err) };
|
|
15588
|
+
}
|
|
15589
|
+
},
|
|
15590
|
+
async rollback(args) {
|
|
15591
|
+
try {
|
|
15592
|
+
const dsn = await buildDsn5(args);
|
|
15593
|
+
const r = await rollbackEfcore({ projectDir: args.projectDir, dsn, target: args.target });
|
|
15594
|
+
return {
|
|
15595
|
+
rolled_back: r.rolledBack,
|
|
15596
|
+
status: r.rolledBack.length === 0 ? "noop" : "ok",
|
|
15597
|
+
tool_specific: { tool: r.tool }
|
|
15598
|
+
};
|
|
15599
|
+
} catch (err) {
|
|
15600
|
+
return { rolled_back: [], status: "error", error: errMsg(err) };
|
|
15601
|
+
}
|
|
15602
|
+
},
|
|
15603
|
+
async stamp(args) {
|
|
15604
|
+
try {
|
|
15605
|
+
const dsn = await buildDsn5(args);
|
|
15606
|
+
const stamped = await stampEfcore({ projectDir: args.projectDir, dsn, revision: args.revision });
|
|
15607
|
+
return { status: "ok", stamped_revision: stamped, tool_specific: { tool: "efcore" } };
|
|
15608
|
+
} catch (err) {
|
|
15609
|
+
return { status: "error", stamped_revision: null, error: errMsg(err) };
|
|
15610
|
+
}
|
|
15611
|
+
},
|
|
15612
|
+
async status(args) {
|
|
15613
|
+
try {
|
|
15614
|
+
const dsn = await buildDsn5(args);
|
|
15615
|
+
const r = await statusEfcore({ projectDir: args.projectDir, dsn });
|
|
15616
|
+
return {
|
|
15617
|
+
applied_version: r.current ?? null,
|
|
15618
|
+
pending: r.pending,
|
|
15619
|
+
applied: [],
|
|
15620
|
+
status: "ok",
|
|
15621
|
+
tool_specific: { tool: r.tool }
|
|
15622
|
+
};
|
|
15623
|
+
} catch (err) {
|
|
15624
|
+
return { applied_version: null, pending: [], applied: [], status: "error", error: errMsg(err) };
|
|
15625
|
+
}
|
|
15626
|
+
},
|
|
15627
|
+
async list(args) {
|
|
15628
|
+
return { files: listEfCoreFiles(args.projectDir) };
|
|
15629
|
+
},
|
|
15630
|
+
// baseline: use stamp (EF has no separate baseline concept).
|
|
15631
|
+
async newMigration(args) {
|
|
15632
|
+
try {
|
|
15633
|
+
const created = await createEfcoreMigration({ projectDir: args.projectDir, slug: args.slug });
|
|
15634
|
+
return {
|
|
15635
|
+
status: "ok",
|
|
15636
|
+
version: efVersion(created.id),
|
|
15637
|
+
filename: path30.basename(created.path),
|
|
15638
|
+
path: created.path
|
|
15639
|
+
};
|
|
15640
|
+
} catch (err) {
|
|
15641
|
+
return { status: "error", version: "", filename: "", path: "", error: errMsg(err) };
|
|
15642
|
+
}
|
|
15643
|
+
}
|
|
15644
|
+
};
|
|
15645
|
+
registerSchemaMigrationAdapter(EfCoreAdapter);
|
|
15646
|
+
|
|
15086
15647
|
// scripts/lakebase/schema-migrate.ts
|
|
15087
15648
|
var SchemaMigrationError = class extends Error {
|
|
15088
15649
|
constructor(message, cause) {
|
|
@@ -15096,13 +15657,16 @@ function detectLanguage(projectDir) {
|
|
|
15096
15657
|
const lang = resolveMigrationLanguage(projectDir);
|
|
15097
15658
|
if (lang === "unknown") {
|
|
15098
15659
|
throw new SchemaMigrationError(
|
|
15099
|
-
`Could not detect project language in ${projectDir}. Expected one of: pom.xml (java/kotlin), pyproject.toml or alembic.ini (python), package.json (nodejs). Pass {language} explicitly to override.`
|
|
15660
|
+
`Could not detect project language in ${projectDir}. Expected one of: pom.xml (java/kotlin), pyproject.toml or alembic.ini (python), package.json (nodejs), *.sln or *.csproj (dotnet). Pass {language} explicitly to override.`
|
|
15100
15661
|
);
|
|
15101
15662
|
}
|
|
15102
15663
|
return lang;
|
|
15103
15664
|
}
|
|
15104
|
-
function toolForLanguage(language) {
|
|
15665
|
+
function toolForLanguage(language, projectDir) {
|
|
15105
15666
|
switch (language) {
|
|
15667
|
+
case "dotnet":
|
|
15668
|
+
if (projectDir && isDotnetFlywayProject(projectDir)) return "flyway";
|
|
15669
|
+
return "efcore";
|
|
15106
15670
|
case "java":
|
|
15107
15671
|
case "kotlin":
|
|
15108
15672
|
return "flyway";
|
|
@@ -15115,8 +15679,10 @@ function toolForLanguage(language) {
|
|
|
15115
15679
|
function listSchemaMigrations(args = {}) {
|
|
15116
15680
|
const projectDir = args.projectDir ?? process.cwd();
|
|
15117
15681
|
const language = args.language ?? detectLanguage(projectDir);
|
|
15118
|
-
const tool = toolForLanguage(language);
|
|
15682
|
+
const tool = toolForLanguage(language, projectDir);
|
|
15119
15683
|
switch (tool) {
|
|
15684
|
+
case "efcore":
|
|
15685
|
+
return listEfCoreFiles(projectDir);
|
|
15120
15686
|
case "flyway":
|
|
15121
15687
|
return listFlywayMigrations(projectDir);
|
|
15122
15688
|
case "alembic":
|
|
@@ -15126,9 +15692,9 @@ function listSchemaMigrations(args = {}) {
|
|
|
15126
15692
|
}
|
|
15127
15693
|
}
|
|
15128
15694
|
function listFlywayMigrations(projectDir) {
|
|
15129
|
-
const dir =
|
|
15130
|
-
if (!
|
|
15131
|
-
const files =
|
|
15695
|
+
const dir = flywayMigrationsDir(projectDir);
|
|
15696
|
+
if (!fs29.existsSync(dir)) return [];
|
|
15697
|
+
const files = fs29.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
|
|
15132
15698
|
return files.map((filename) => {
|
|
15133
15699
|
const m = filename.match(/^V(\d+(?:\.\d+)*)__(.+)\.sql$/);
|
|
15134
15700
|
const version = m[1];
|
|
@@ -15138,12 +15704,12 @@ function listFlywayMigrations(projectDir) {
|
|
|
15138
15704
|
}
|
|
15139
15705
|
function listAlembicMigrations(projectDir) {
|
|
15140
15706
|
const candidates = [
|
|
15141
|
-
|
|
15142
|
-
|
|
15707
|
+
path31.join(projectDir, "migrations", "versions"),
|
|
15708
|
+
path31.join(projectDir, "alembic", "versions")
|
|
15143
15709
|
];
|
|
15144
|
-
const dir = candidates.find((p) =>
|
|
15710
|
+
const dir = candidates.find((p) => fs29.existsSync(p));
|
|
15145
15711
|
if (!dir) return [];
|
|
15146
|
-
const files =
|
|
15712
|
+
const files = fs29.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
|
|
15147
15713
|
return files.map((filename) => {
|
|
15148
15714
|
const stem = filename.replace(/\.py$/, "");
|
|
15149
15715
|
const sep4 = stem.indexOf("_");
|
|
@@ -15153,9 +15719,9 @@ function listAlembicMigrations(projectDir) {
|
|
|
15153
15719
|
}).sort((a, b) => a.filename.localeCompare(b.filename));
|
|
15154
15720
|
}
|
|
15155
15721
|
function listKnexMigrations(projectDir) {
|
|
15156
|
-
const dir =
|
|
15157
|
-
if (!
|
|
15158
|
-
const files =
|
|
15722
|
+
const dir = path31.join(projectDir, "migrations");
|
|
15723
|
+
if (!fs29.existsSync(dir)) return [];
|
|
15724
|
+
const files = fs29.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
|
|
15159
15725
|
return files.map((filename) => {
|
|
15160
15726
|
const stem = filename.replace(/\.(js|ts)$/, "");
|
|
15161
15727
|
const m = stem.match(/^(\d{14})_(.+)$/);
|
|
@@ -15177,7 +15743,7 @@ function versionCompare2(a, b) {
|
|
|
15177
15743
|
return 0;
|
|
15178
15744
|
}
|
|
15179
15745
|
function adapterFor(projectDir, language) {
|
|
15180
|
-
const override = language ? toolForLanguage(language) : void 0;
|
|
15746
|
+
const override = language ? toolForLanguage(language, projectDir) : void 0;
|
|
15181
15747
|
return resolveSchemaMigrationAdapter(projectDir, override);
|
|
15182
15748
|
}
|
|
15183
15749
|
var TierMigrationRefusedError = class extends Error {
|
|
@@ -15331,8 +15897,8 @@ async function runInfraSuite(args) {
|
|
|
15331
15897
|
duration_ms: Date.now() - start
|
|
15332
15898
|
};
|
|
15333
15899
|
if (args.junitOutput) {
|
|
15334
|
-
|
|
15335
|
-
|
|
15900
|
+
fs30.mkdirSync(path32.dirname(args.junitOutput), { recursive: true });
|
|
15901
|
+
fs30.writeFileSync(args.junitOutput, formatJUnit(result), "utf8");
|
|
15336
15902
|
}
|
|
15337
15903
|
return result;
|
|
15338
15904
|
}
|
|
@@ -15378,8 +15944,8 @@ function escapeXml(s) {
|
|
|
15378
15944
|
|
|
15379
15945
|
// scripts/lakebase/scm-claim-feature.ts
|
|
15380
15946
|
init_esm_shims();
|
|
15381
|
-
import * as
|
|
15382
|
-
import * as
|
|
15947
|
+
import * as fs31 from "fs";
|
|
15948
|
+
import * as path33 from "path";
|
|
15383
15949
|
var ScmClaimError = class extends Error {
|
|
15384
15950
|
constructor(message, code) {
|
|
15385
15951
|
super(message);
|
|
@@ -15436,7 +16002,7 @@ async function claimFeatureBranch(args) {
|
|
|
15436
16002
|
const current = readWorkflowState(args.projectDir);
|
|
15437
16003
|
if (!current) {
|
|
15438
16004
|
throw new ScmClaimError(
|
|
15439
|
-
`No SCM workflow state found at ${
|
|
16005
|
+
`No SCM workflow state found at ${path33.join(args.projectDir, ".lakebase/workflow-state.json")}. Run lakebase-create-project to scaffold, or re-seed via the substrate.`,
|
|
15440
16006
|
"no-state-file"
|
|
15441
16007
|
);
|
|
15442
16008
|
}
|
|
@@ -15540,8 +16106,8 @@ function alreadyClaimedSentinel(state) {
|
|
|
15540
16106
|
};
|
|
15541
16107
|
}
|
|
15542
16108
|
function workflowStateFileExists(projectDir) {
|
|
15543
|
-
return
|
|
15544
|
-
|
|
16109
|
+
return fs31.existsSync(
|
|
16110
|
+
path33.join(projectDir, ".lakebase/workflow-state.json")
|
|
15545
16111
|
);
|
|
15546
16112
|
}
|
|
15547
16113
|
|
|
@@ -16029,12 +16595,12 @@ async function pushCurrentBranchForPr(args) {
|
|
|
16029
16595
|
|
|
16030
16596
|
// scripts/lakebase/workflow-drift.ts
|
|
16031
16597
|
init_esm_shims();
|
|
16032
|
-
import * as
|
|
16033
|
-
import * as
|
|
16598
|
+
import * as fs32 from "fs";
|
|
16599
|
+
import * as path34 from "path";
|
|
16034
16600
|
function findKitTemplatesDir(start) {
|
|
16035
16601
|
let dir = start;
|
|
16036
16602
|
for (let i = 0; i < 6; i++) {
|
|
16037
|
-
const candidate =
|
|
16603
|
+
const candidate = path34.join(
|
|
16038
16604
|
dir,
|
|
16039
16605
|
"templates",
|
|
16040
16606
|
"project",
|
|
@@ -16042,8 +16608,8 @@ function findKitTemplatesDir(start) {
|
|
|
16042
16608
|
".github",
|
|
16043
16609
|
"workflows"
|
|
16044
16610
|
);
|
|
16045
|
-
if (
|
|
16046
|
-
const parent =
|
|
16611
|
+
if (fs32.existsSync(candidate)) return candidate;
|
|
16612
|
+
const parent = path34.dirname(dir);
|
|
16047
16613
|
if (parent === dir) break;
|
|
16048
16614
|
dir = parent;
|
|
16049
16615
|
}
|
|
@@ -16067,13 +16633,13 @@ function unifiedDiff(name, projectContent, templateContent) {
|
|
|
16067
16633
|
return out.join("\n");
|
|
16068
16634
|
}
|
|
16069
16635
|
function detectWorkflowDrift(args) {
|
|
16070
|
-
const projectWorkflowsDir =
|
|
16636
|
+
const projectWorkflowsDir = path34.join(
|
|
16071
16637
|
args.projectDir,
|
|
16072
16638
|
".github",
|
|
16073
16639
|
"workflows"
|
|
16074
16640
|
);
|
|
16075
|
-
const here =
|
|
16076
|
-
const kitWorkflowsDir = args.kitDir ?
|
|
16641
|
+
const here = path34.dirname(new URL(import.meta.url).pathname);
|
|
16642
|
+
const kitWorkflowsDir = args.kitDir ? path34.join(
|
|
16077
16643
|
args.kitDir,
|
|
16078
16644
|
"templates",
|
|
16079
16645
|
"project",
|
|
@@ -16081,21 +16647,21 @@ function detectWorkflowDrift(args) {
|
|
|
16081
16647
|
".github",
|
|
16082
16648
|
"workflows"
|
|
16083
16649
|
) : findKitTemplatesDir(here);
|
|
16084
|
-
const templateFiles =
|
|
16085
|
-
const projectFiles =
|
|
16650
|
+
const templateFiles = fs32.existsSync(kitWorkflowsDir) ? fs32.readdirSync(kitWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16651
|
+
const projectFiles = fs32.existsSync(projectWorkflowsDir) ? fs32.readdirSync(projectWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16086
16652
|
const version = readKitVersion(kitWorkflowsDir);
|
|
16087
16653
|
const seen = /* @__PURE__ */ new Set();
|
|
16088
16654
|
const files = [];
|
|
16089
16655
|
for (const name of templateFiles) {
|
|
16090
16656
|
seen.add(name);
|
|
16091
|
-
const projectPath2 =
|
|
16092
|
-
const templatePath =
|
|
16093
|
-
if (!
|
|
16657
|
+
const projectPath2 = path34.join(projectWorkflowsDir, name);
|
|
16658
|
+
const templatePath = path34.join(kitWorkflowsDir, name);
|
|
16659
|
+
if (!fs32.existsSync(projectPath2)) {
|
|
16094
16660
|
files.push({ name, status: "missing" });
|
|
16095
16661
|
continue;
|
|
16096
16662
|
}
|
|
16097
|
-
const projectContent =
|
|
16098
|
-
const templateContent = applyPlaceholders(
|
|
16663
|
+
const projectContent = fs32.readFileSync(projectPath2, "utf8");
|
|
16664
|
+
const templateContent = applyPlaceholders(fs32.readFileSync(templatePath, "utf8"), version);
|
|
16099
16665
|
if (projectContent === templateContent) {
|
|
16100
16666
|
files.push({ name, status: "unchanged" });
|
|
16101
16667
|
} else {
|
|
@@ -16126,10 +16692,10 @@ function detectWorkflowDrift(args) {
|
|
|
16126
16692
|
function readKitVersion(kitWorkflowsDir) {
|
|
16127
16693
|
let dir = kitWorkflowsDir;
|
|
16128
16694
|
for (let i = 0; i < 5; i++) {
|
|
16129
|
-
dir =
|
|
16695
|
+
dir = path34.dirname(dir);
|
|
16130
16696
|
}
|
|
16131
16697
|
try {
|
|
16132
|
-
const raw =
|
|
16698
|
+
const raw = fs32.readFileSync(path34.join(dir, "package.json"), "utf-8");
|
|
16133
16699
|
const pkg = JSON.parse(raw);
|
|
16134
16700
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
16135
16701
|
} catch {
|
|
@@ -16146,7 +16712,7 @@ var COMMAND_HOOK_FILE_PATTERN = /\.(pre|post)-hook\.md$/;
|
|
|
16146
16712
|
function findKitCommandsDir(start) {
|
|
16147
16713
|
let dir = start;
|
|
16148
16714
|
for (let i = 0; i < 6; i++) {
|
|
16149
|
-
const candidate =
|
|
16715
|
+
const candidate = path34.join(
|
|
16150
16716
|
dir,
|
|
16151
16717
|
"templates",
|
|
16152
16718
|
"project",
|
|
@@ -16154,8 +16720,8 @@ function findKitCommandsDir(start) {
|
|
|
16154
16720
|
".claude",
|
|
16155
16721
|
"commands"
|
|
16156
16722
|
);
|
|
16157
|
-
if (
|
|
16158
|
-
const parent =
|
|
16723
|
+
if (fs32.existsSync(candidate)) return candidate;
|
|
16724
|
+
const parent = path34.dirname(dir);
|
|
16159
16725
|
if (parent === dir) break;
|
|
16160
16726
|
dir = parent;
|
|
16161
16727
|
}
|
|
@@ -16168,24 +16734,24 @@ function parsePinnedVersion(content) {
|
|
|
16168
16734
|
return m ? m[1] : void 0;
|
|
16169
16735
|
}
|
|
16170
16736
|
function detectCommandDrift(args) {
|
|
16171
|
-
const projectCommandsDir =
|
|
16172
|
-
const here =
|
|
16173
|
-
const kitCommandsDir = args.kitDir ?
|
|
16737
|
+
const projectCommandsDir = path34.join(args.projectDir, ".claude", "commands");
|
|
16738
|
+
const here = path34.dirname(new URL(import.meta.url).pathname);
|
|
16739
|
+
const kitCommandsDir = args.kitDir ? path34.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
|
|
16174
16740
|
const kitVersion = readKitVersionFromCommandsDir(kitCommandsDir);
|
|
16175
|
-
const templateFiles =
|
|
16176
|
-
const projectFiles =
|
|
16741
|
+
const templateFiles = fs32.existsSync(kitCommandsDir) ? fs32.readdirSync(kitCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
|
|
16742
|
+
const projectFiles = fs32.existsSync(projectCommandsDir) ? fs32.readdirSync(projectCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
|
|
16177
16743
|
const seen = /* @__PURE__ */ new Set();
|
|
16178
16744
|
const files = [];
|
|
16179
16745
|
for (const name of templateFiles) {
|
|
16180
16746
|
seen.add(name);
|
|
16181
|
-
const projectPath2 =
|
|
16182
|
-
const templatePath =
|
|
16183
|
-
const templateRaw =
|
|
16184
|
-
if (!
|
|
16747
|
+
const projectPath2 = path34.join(projectCommandsDir, name);
|
|
16748
|
+
const templatePath = path34.join(kitCommandsDir, name);
|
|
16749
|
+
const templateRaw = fs32.readFileSync(templatePath, "utf8");
|
|
16750
|
+
if (!fs32.existsSync(projectPath2)) {
|
|
16185
16751
|
files.push({ name, status: "missing", kit_version: kitVersion });
|
|
16186
16752
|
continue;
|
|
16187
16753
|
}
|
|
16188
|
-
const projectContent =
|
|
16754
|
+
const projectContent = fs32.readFileSync(projectPath2, "utf8");
|
|
16189
16755
|
const pinned = parsePinnedVersion(projectContent);
|
|
16190
16756
|
const versionForCompare = pinned ?? kitVersion;
|
|
16191
16757
|
const templateContent = applyCommandPlaceholders(templateRaw, versionForCompare);
|
|
@@ -16223,10 +16789,10 @@ function detectCommandDrift(args) {
|
|
|
16223
16789
|
function readKitVersionFromCommandsDir(kitCommandsDir) {
|
|
16224
16790
|
let dir = kitCommandsDir;
|
|
16225
16791
|
for (let i = 0; i < 5; i++) {
|
|
16226
|
-
dir =
|
|
16792
|
+
dir = path34.dirname(dir);
|
|
16227
16793
|
}
|
|
16228
16794
|
try {
|
|
16229
|
-
const raw =
|
|
16795
|
+
const raw = fs32.readFileSync(path34.join(dir, "package.json"), "utf-8");
|
|
16230
16796
|
const pkg = JSON.parse(raw);
|
|
16231
16797
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
16232
16798
|
} catch {
|
|
@@ -16243,13 +16809,13 @@ function detectScaffoldedDrift(args) {
|
|
|
16243
16809
|
};
|
|
16244
16810
|
}
|
|
16245
16811
|
function updateWorkflows(args) {
|
|
16246
|
-
const projectWorkflowsDir =
|
|
16812
|
+
const projectWorkflowsDir = path34.join(
|
|
16247
16813
|
args.projectDir,
|
|
16248
16814
|
".github",
|
|
16249
16815
|
"workflows"
|
|
16250
16816
|
);
|
|
16251
|
-
const here =
|
|
16252
|
-
const kitWorkflowsDir = args.kitDir ?
|
|
16817
|
+
const here = path34.dirname(new URL(import.meta.url).pathname);
|
|
16818
|
+
const kitWorkflowsDir = args.kitDir ? path34.join(
|
|
16253
16819
|
args.kitDir,
|
|
16254
16820
|
"templates",
|
|
16255
16821
|
"project",
|
|
@@ -16260,22 +16826,22 @@ function updateWorkflows(args) {
|
|
|
16260
16826
|
const substitute = args.substitute !== false;
|
|
16261
16827
|
const dryRun = args.dryRun === true;
|
|
16262
16828
|
const pruneExtras = args.pruneExtras === true;
|
|
16263
|
-
const templateFiles =
|
|
16264
|
-
const projectFiles =
|
|
16265
|
-
if (!dryRun && templateFiles.length > 0 && !
|
|
16266
|
-
|
|
16829
|
+
const templateFiles = fs32.existsSync(kitWorkflowsDir) ? fs32.readdirSync(kitWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16830
|
+
const projectFiles = fs32.existsSync(projectWorkflowsDir) ? fs32.readdirSync(projectWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16831
|
+
if (!dryRun && templateFiles.length > 0 && !fs32.existsSync(projectWorkflowsDir)) {
|
|
16832
|
+
fs32.mkdirSync(projectWorkflowsDir, { recursive: true });
|
|
16267
16833
|
}
|
|
16268
16834
|
const version = substitute ? readKitVersion(kitWorkflowsDir) : "";
|
|
16269
16835
|
const seen = /* @__PURE__ */ new Set();
|
|
16270
16836
|
const files = [];
|
|
16271
16837
|
for (const name of templateFiles) {
|
|
16272
16838
|
seen.add(name);
|
|
16273
|
-
const projectPath2 =
|
|
16274
|
-
const templatePath =
|
|
16275
|
-
const templateRaw =
|
|
16839
|
+
const projectPath2 = path34.join(projectWorkflowsDir, name);
|
|
16840
|
+
const templatePath = path34.join(kitWorkflowsDir, name);
|
|
16841
|
+
const templateRaw = fs32.readFileSync(templatePath, "utf-8");
|
|
16276
16842
|
const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
|
|
16277
|
-
const existed =
|
|
16278
|
-
const current = existed ?
|
|
16843
|
+
const existed = fs32.existsSync(projectPath2);
|
|
16844
|
+
const current = existed ? fs32.readFileSync(projectPath2, "utf-8") : "";
|
|
16279
16845
|
let outcome;
|
|
16280
16846
|
if (!existed) {
|
|
16281
16847
|
outcome = "added";
|
|
@@ -16285,16 +16851,16 @@ function updateWorkflows(args) {
|
|
|
16285
16851
|
outcome = "updated";
|
|
16286
16852
|
}
|
|
16287
16853
|
if (!dryRun && outcome !== "unchanged") {
|
|
16288
|
-
|
|
16854
|
+
fs32.writeFileSync(projectPath2, desired);
|
|
16289
16855
|
}
|
|
16290
16856
|
files.push({ name, outcome });
|
|
16291
16857
|
}
|
|
16292
16858
|
if (pruneExtras) {
|
|
16293
16859
|
for (const name of projectFiles) {
|
|
16294
16860
|
if (seen.has(name)) continue;
|
|
16295
|
-
const projectPath2 =
|
|
16861
|
+
const projectPath2 = path34.join(projectWorkflowsDir, name);
|
|
16296
16862
|
if (!dryRun) {
|
|
16297
|
-
|
|
16863
|
+
fs32.unlinkSync(projectPath2);
|
|
16298
16864
|
}
|
|
16299
16865
|
files.push({ name, outcome: "removed" });
|
|
16300
16866
|
}
|
|
@@ -16892,15 +17458,15 @@ function parentForTopology(t, defaultLeaf) {
|
|
|
16892
17458
|
|
|
16893
17459
|
// scripts/lakebase/scm-doctor.ts
|
|
16894
17460
|
init_esm_shims();
|
|
16895
|
-
import * as
|
|
16896
|
-
import * as
|
|
17461
|
+
import * as fs33 from "fs";
|
|
17462
|
+
import * as path35 from "path";
|
|
16897
17463
|
var FEATURE_PREFIX = "feature/";
|
|
16898
17464
|
var TIER_LEAFS2 = DEFAULT_PROTECTED_TIER_NAMES;
|
|
16899
17465
|
function readEnv(projectDir) {
|
|
16900
|
-
const envPath =
|
|
17466
|
+
const envPath = path35.join(projectDir, ".env");
|
|
16901
17467
|
const out = /* @__PURE__ */ new Map();
|
|
16902
|
-
if (!
|
|
16903
|
-
const lines =
|
|
17468
|
+
if (!fs33.existsSync(envPath)) return out;
|
|
17469
|
+
const lines = fs33.readFileSync(envPath, "utf8").split("\n");
|
|
16904
17470
|
for (const line of lines) {
|
|
16905
17471
|
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.+?)\s*$/);
|
|
16906
17472
|
if (m) out.set(m[1], m[2].replace(/^["']|["']$/g, ""));
|
|
@@ -16955,9 +17521,9 @@ async function runDoctor(args, deps = {}) {
|
|
|
16955
17521
|
}
|
|
16956
17522
|
for (const wf of ["pr.yml", "merge.yml"]) {
|
|
16957
17523
|
try {
|
|
16958
|
-
const p =
|
|
16959
|
-
if (!
|
|
16960
|
-
const body =
|
|
17524
|
+
const p = path35.join(projectDir, ".github", "workflows", wf);
|
|
17525
|
+
if (!fs33.existsSync(p)) continue;
|
|
17526
|
+
const body = fs33.readFileSync(p, "utf8");
|
|
16961
17527
|
if (/lakebase-scm-utils#v\d/.test(body)) {
|
|
16962
17528
|
findings.push({
|
|
16963
17529
|
id: "ci-workflow-substrate-pin",
|
|
@@ -17172,7 +17738,7 @@ async function fixFinding(args) {
|
|
|
17172
17738
|
);
|
|
17173
17739
|
}
|
|
17174
17740
|
const sanitized = sanitizeBranchName(branch);
|
|
17175
|
-
const envFile =
|
|
17741
|
+
const envFile = path35.join(args.projectDir, ".env");
|
|
17176
17742
|
updateEnvConnection({
|
|
17177
17743
|
envPath: envFile,
|
|
17178
17744
|
projectId: readEnvVar(envFile, "LAKEBASE_PROJECT_ID") ?? "",
|
|
@@ -17274,14 +17840,14 @@ function shellEscape3(s) {
|
|
|
17274
17840
|
|
|
17275
17841
|
// scripts/lakebase/doctor.ts
|
|
17276
17842
|
init_esm_shims();
|
|
17277
|
-
import * as
|
|
17278
|
-
import * as
|
|
17843
|
+
import * as fs34 from "fs";
|
|
17844
|
+
import * as path36 from "path";
|
|
17279
17845
|
import * as cp6 from "child_process";
|
|
17280
17846
|
function readEnvFile(projectDir) {
|
|
17281
|
-
const envPath =
|
|
17282
|
-
if (!
|
|
17847
|
+
const envPath = path36.join(projectDir, ".env");
|
|
17848
|
+
if (!fs34.existsSync(envPath)) return {};
|
|
17283
17849
|
const out = {};
|
|
17284
|
-
for (const line of
|
|
17850
|
+
for (const line of fs34.readFileSync(envPath, "utf8").split("\n")) {
|
|
17285
17851
|
const m = line.match(/^\s*([A-Z][A-Z0-9_]*)\s*=\s*(.*)\s*$/);
|
|
17286
17852
|
if (!m) continue;
|
|
17287
17853
|
let val = m[2];
|
|
@@ -17435,6 +18001,23 @@ async function checkPrereq(spec, run) {
|
|
|
17435
18001
|
detail: { version: trimmed }
|
|
17436
18002
|
};
|
|
17437
18003
|
}
|
|
18004
|
+
var DOTNET_PREREQ = {
|
|
18005
|
+
name: "dotnet-sdk",
|
|
18006
|
+
cmd: "dotnet",
|
|
18007
|
+
versionArgs: ["--version"],
|
|
18008
|
+
minMajor: 10,
|
|
18009
|
+
label: ".NET SDK",
|
|
18010
|
+
hint: "Install the .NET 10 SDK (e.g. `brew install --cask dotnet-sdk` or https://dot.net). EF Core's dotnet-ef is restored per project from .config/dotnet-tools.json."
|
|
18011
|
+
};
|
|
18012
|
+
async function checkLanguagePrerequisites(projectDir, run = defaultVersionRunner) {
|
|
18013
|
+
let lang;
|
|
18014
|
+
try {
|
|
18015
|
+
lang = detectLanguage(projectDir);
|
|
18016
|
+
} catch {
|
|
18017
|
+
return [];
|
|
18018
|
+
}
|
|
18019
|
+
return lang === "dotnet" ? [await checkPrereq(DOTNET_PREREQ, run)] : [];
|
|
18020
|
+
}
|
|
17438
18021
|
async function checkPrerequisites(run = defaultVersionRunner) {
|
|
17439
18022
|
return Promise.all(PREREQS.map((spec) => checkPrereq(spec, run)));
|
|
17440
18023
|
}
|
|
@@ -17536,7 +18119,7 @@ function checkEnv(projectDir) {
|
|
|
17536
18119
|
name: "env-file",
|
|
17537
18120
|
status: "warn",
|
|
17538
18121
|
message: ".env not found",
|
|
17539
|
-
detail: { projectDir, envPath:
|
|
18122
|
+
detail: { projectDir, envPath: path36.join(projectDir, ".env") },
|
|
17540
18123
|
hint: "Run `lakebase-branch sync-env`, or `git checkout <branch>` so the post-checkout hook writes .env (or copy .env.example). The kit stores connection METADATA only , no DB token (the app mints a short-lived credential at runtime)."
|
|
17541
18124
|
};
|
|
17542
18125
|
}
|
|
@@ -17766,6 +18349,7 @@ async function runDoctor2(args = {}) {
|
|
|
17766
18349
|
const hooks = checkHooks(projectDir);
|
|
17767
18350
|
const workflowDrift = checkWorkflowDrift(projectDir);
|
|
17768
18351
|
const prereqs = await checkPrerequisites();
|
|
18352
|
+
const languagePrereqs = await checkLanguagePrerequisites(projectDir);
|
|
17769
18353
|
const lakebaseEnabled = auth7.status === "ok" ? await checkLakebaseEnabled(profile) : {
|
|
17770
18354
|
name: "lakebase-enabled",
|
|
17771
18355
|
status: "skip",
|
|
@@ -17774,6 +18358,7 @@ async function runDoctor2(args = {}) {
|
|
|
17774
18358
|
const checks = [
|
|
17775
18359
|
cli,
|
|
17776
18360
|
...prereqs,
|
|
18361
|
+
...languagePrereqs,
|
|
17777
18362
|
auth7,
|
|
17778
18363
|
identity,
|
|
17779
18364
|
lakebaseEnabled,
|
|
@@ -17956,12 +18541,16 @@ function isUcMissingError(msg) {
|
|
|
17956
18541
|
export {
|
|
17957
18542
|
CONVENTION_TIER_DEFAULTS,
|
|
17958
18543
|
DEFAULT_PROTECTED_TIER_NAMES,
|
|
18544
|
+
DOTNET_EFCORE_DEFAULTS,
|
|
18545
|
+
DOTNET_FLYWAY_DIR,
|
|
18546
|
+
EF_DESIGN_PACKAGE,
|
|
17959
18547
|
FIXABLE_FINDING_IDS,
|
|
17960
18548
|
InitializrNetworkError,
|
|
17961
18549
|
InitializrParseError,
|
|
17962
18550
|
LakebaseBranchError,
|
|
17963
18551
|
LakebaseBranchTtlTooLongError,
|
|
17964
18552
|
LakebaseProjectError,
|
|
18553
|
+
MAVEN_FLYWAY_DIR,
|
|
17965
18554
|
MIGRATION_DEFAULTS,
|
|
17966
18555
|
NODE_E2E_TEMPLATE_FILES,
|
|
17967
18556
|
PLAYWRIGHT_TEMPLATE_FILES,
|
|
@@ -18058,9 +18647,12 @@ export {
|
|
|
18058
18647
|
ensureSchemaAndVolume,
|
|
18059
18648
|
extractPullNumber,
|
|
18060
18649
|
featureBranchName,
|
|
18650
|
+
findCsprojFiles,
|
|
18061
18651
|
findDefaultBranchName,
|
|
18652
|
+
findEfCoreProject,
|
|
18062
18653
|
findHistoryRetentionDuration,
|
|
18063
18654
|
fixFinding,
|
|
18655
|
+
flywayMigrationsDir,
|
|
18064
18656
|
formatJUnit,
|
|
18065
18657
|
formatSchemaDiffAsMarkdown,
|
|
18066
18658
|
generateAppYaml,
|
|
@@ -18082,11 +18674,14 @@ export {
|
|
|
18082
18674
|
getTargetNames,
|
|
18083
18675
|
grantLakebasePermission,
|
|
18084
18676
|
grantUcCatalogPermission,
|
|
18677
|
+
hasDotnetMarker,
|
|
18085
18678
|
inferTierTopology,
|
|
18086
18679
|
initWorkflowState,
|
|
18087
18680
|
installHooks,
|
|
18088
18681
|
installPlaywright,
|
|
18089
18682
|
isAllSchemas,
|
|
18683
|
+
isDotnetFlywayProject,
|
|
18684
|
+
isDotnetProject,
|
|
18090
18685
|
isForeignFeatureClaim,
|
|
18091
18686
|
isGitTracked,
|
|
18092
18687
|
isLongRunningTierBranch,
|