@databricks-solutions/lakebase-scm-utils 0.2.50 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/index.cjs +2636 -2124
- package/dist/scripts/index.d.cts +1 -1
- package/dist/scripts/index.d.ts +1 -1
- package/dist/scripts/index.js +680 -178
- 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 +2633 -2121
- package/dist/scripts/lakebase/index.d.cts +59 -10
- package/dist/scripts/lakebase/index.d.ts +59 -10
- package/dist/scripts/lakebase/index.js +674 -172
- 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/collapse-heads.cli.ts +1 -1
- package/scripts/lakebase/create-project.ts +14 -12
- 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/.gitignore.base +7 -0
- 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
package/dist/scripts/index.js
CHANGED
|
@@ -2581,7 +2581,7 @@ paginateRest.VERSION = VERSION5;
|
|
|
2581
2581
|
|
|
2582
2582
|
// node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
|
|
2583
2583
|
init_esm_shims();
|
|
2584
|
-
var generateMessage = (
|
|
2584
|
+
var generateMessage = (path37, cursorValue) => `The cursor at "${path37.join(
|
|
2585
2585
|
","
|
|
2586
2586
|
)}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
|
|
2587
2587
|
var MissingCursorChange = class extends Error {
|
|
@@ -2622,9 +2622,9 @@ function findPaginatedResourcePath(responseData) {
|
|
|
2622
2622
|
}
|
|
2623
2623
|
return paginatedResourcePath;
|
|
2624
2624
|
}
|
|
2625
|
-
var deepFindPathToProperty = (object, searchProp,
|
|
2625
|
+
var deepFindPathToProperty = (object, searchProp, path37 = []) => {
|
|
2626
2626
|
for (const key of Object.keys(object)) {
|
|
2627
|
-
const currentPath = [...
|
|
2627
|
+
const currentPath = [...path37, key];
|
|
2628
2628
|
const currentValue = object[key];
|
|
2629
2629
|
if (isObject(currentValue)) {
|
|
2630
2630
|
if (currentValue.hasOwnProperty(searchProp)) {
|
|
@@ -2642,12 +2642,12 @@ var deepFindPathToProperty = (object, searchProp, path34 = []) => {
|
|
|
2642
2642
|
}
|
|
2643
2643
|
return [];
|
|
2644
2644
|
};
|
|
2645
|
-
var get = (object,
|
|
2646
|
-
return
|
|
2645
|
+
var get = (object, path37) => {
|
|
2646
|
+
return path37.reduce((current, nextProperty) => current[nextProperty], object);
|
|
2647
2647
|
};
|
|
2648
|
-
var set = (object,
|
|
2649
|
-
const lastProperty =
|
|
2650
|
-
const parentPath = [...
|
|
2648
|
+
var set = (object, path37, mutator) => {
|
|
2649
|
+
const lastProperty = path37[path37.length - 1];
|
|
2650
|
+
const parentPath = [...path37].slice(0, -1);
|
|
2651
2651
|
const parent = get(object, parentPath);
|
|
2652
2652
|
if (typeof mutator === "function") {
|
|
2653
2653
|
parent[lastProperty] = mutator(parent[lastProperty]);
|
|
@@ -2699,22 +2699,22 @@ var mergeResponses = (response1, response2) => {
|
|
|
2699
2699
|
if (Object.keys(response1).length === 0) {
|
|
2700
2700
|
return Object.assign(response1, response2);
|
|
2701
2701
|
}
|
|
2702
|
-
const
|
|
2703
|
-
const nodesPath = [...
|
|
2702
|
+
const path37 = findPaginatedResourcePath(response1);
|
|
2703
|
+
const nodesPath = [...path37, "nodes"];
|
|
2704
2704
|
const newNodes = get(response2, nodesPath);
|
|
2705
2705
|
if (newNodes) {
|
|
2706
2706
|
set(response1, nodesPath, (values) => {
|
|
2707
2707
|
return [...values, ...newNodes];
|
|
2708
2708
|
});
|
|
2709
2709
|
}
|
|
2710
|
-
const edgesPath = [...
|
|
2710
|
+
const edgesPath = [...path37, "edges"];
|
|
2711
2711
|
const newEdges = get(response2, edgesPath);
|
|
2712
2712
|
if (newEdges) {
|
|
2713
2713
|
set(response1, edgesPath, (values) => {
|
|
2714
2714
|
return [...values, ...newEdges];
|
|
2715
2715
|
});
|
|
2716
2716
|
}
|
|
2717
|
-
const pageInfoPath = [...
|
|
2717
|
+
const pageInfoPath = [...path37, "pageInfo"];
|
|
2718
2718
|
set(response1, pageInfoPath, get(response2, pageInfoPath));
|
|
2719
2719
|
return response1;
|
|
2720
2720
|
};
|
|
@@ -5135,7 +5135,7 @@ var triggers_notification_paths_default = [
|
|
|
5135
5135
|
];
|
|
5136
5136
|
function routeMatcher(paths) {
|
|
5137
5137
|
const regexes = paths.map(
|
|
5138
|
-
(
|
|
5138
|
+
(path37) => path37.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
|
|
5139
5139
|
);
|
|
5140
5140
|
const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
|
|
5141
5141
|
return new RegExp(regex2, "i");
|
|
@@ -8715,9 +8715,9 @@ function asBranchUid(s) {
|
|
|
8715
8715
|
}
|
|
8716
8716
|
return s;
|
|
8717
8717
|
}
|
|
8718
|
-
function branchNameFromResourcePath(
|
|
8719
|
-
if (!
|
|
8720
|
-
const leaf =
|
|
8718
|
+
function branchNameFromResourcePath(path37) {
|
|
8719
|
+
if (!path37.includes("/branches/")) return null;
|
|
8720
|
+
const leaf = path37.split("/branches/").pop();
|
|
8721
8721
|
if (!leaf) return null;
|
|
8722
8722
|
try {
|
|
8723
8723
|
return asBranchName(leaf);
|
|
@@ -9725,8 +9725,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
|
|
|
9725
9725
|
var cached;
|
|
9726
9726
|
function substrateSelfVersion() {
|
|
9727
9727
|
if (cached !== void 0) return cached;
|
|
9728
|
-
if ("0.
|
|
9729
|
-
cached = "0.
|
|
9728
|
+
if ("0.3.0".length > 0) {
|
|
9729
|
+
cached = "0.3.0";
|
|
9730
9730
|
return cached;
|
|
9731
9731
|
}
|
|
9732
9732
|
cached = "unknown";
|
|
@@ -11314,16 +11314,16 @@ function isAllSchemas(schema) {
|
|
|
11314
11314
|
}
|
|
11315
11315
|
function buildSchemaQuery(schema) {
|
|
11316
11316
|
const cols = "c.table_schema, c.table_name, c.column_name, c.data_type";
|
|
11317
|
-
const
|
|
11317
|
+
const join37 = "FROM information_schema.columns c JOIN pg_tables t ON c.table_name = t.tablename AND c.table_schema = t.schemaname ";
|
|
11318
11318
|
if (isAllSchemas(schema)) {
|
|
11319
11319
|
return {
|
|
11320
|
-
text: `SELECT ${cols} ` +
|
|
11320
|
+
text: `SELECT ${cols} ` + join37 + `WHERE ${SYSTEM_SCHEMA_FILTER} ORDER BY c.table_schema, c.table_name, c.ordinal_position`,
|
|
11321
11321
|
values: []
|
|
11322
11322
|
};
|
|
11323
11323
|
}
|
|
11324
11324
|
const one = (schema ?? "").trim() || "public";
|
|
11325
11325
|
return {
|
|
11326
|
-
text: `SELECT ${cols} ` +
|
|
11326
|
+
text: `SELECT ${cols} ` + join37 + "WHERE c.table_schema = $1 ORDER BY c.table_name, c.ordinal_position",
|
|
11327
11327
|
values: [one]
|
|
11328
11328
|
};
|
|
11329
11329
|
}
|
|
@@ -11988,6 +11988,20 @@ async function deployLanguageProject(args) {
|
|
|
11988
11988
|
return;
|
|
11989
11989
|
}
|
|
11990
11990
|
const templatesDir = args.templatesDir ?? findTemplatesDir2();
|
|
11991
|
+
if (args.language === "dotnet") {
|
|
11992
|
+
const tool = args.migrationTool ?? "efcore";
|
|
11993
|
+
if (tool !== "efcore" && tool !== "flyway") {
|
|
11994
|
+
throw new Error(`Unsupported .NET migration tool: ${String(tool)} (expected efcore or flyway)`);
|
|
11995
|
+
}
|
|
11996
|
+
const base = path10.join(templatesDir, "dotnet");
|
|
11997
|
+
const overlay = path10.join(templatesDir, `dotnet-${tool}`);
|
|
11998
|
+
if (!fs11.existsSync(base) || !fs11.existsSync(overlay)) {
|
|
11999
|
+
throw new Error(`No template found for language: dotnet (${tool})`);
|
|
12000
|
+
}
|
|
12001
|
+
copyDirSubstituted(base, args.targetDir, { projectName: args.projectName });
|
|
12002
|
+
copyDirSubstituted(overlay, args.targetDir, { projectName: args.projectName });
|
|
12003
|
+
return;
|
|
12004
|
+
}
|
|
11991
12005
|
const langSrc = path10.join(templatesDir, args.language);
|
|
11992
12006
|
if (!fs11.existsSync(langSrc)) {
|
|
11993
12007
|
throw new Error(`No template found for language: ${args.language}`);
|
|
@@ -12407,6 +12421,7 @@ async function scaffoldAll(args) {
|
|
|
12407
12421
|
targetDir: args.targetDir,
|
|
12408
12422
|
language,
|
|
12409
12423
|
projectName,
|
|
12424
|
+
migrationTool: args.migrationTool,
|
|
12410
12425
|
templatesDir: args.templatesDir,
|
|
12411
12426
|
initializrClient: args.initializrClient,
|
|
12412
12427
|
report
|
|
@@ -13633,7 +13648,7 @@ async function createProject(input, progress) {
|
|
|
13633
13648
|
tierCount > 1 ? `${tierCount} tiers (prod${tierCount >= 2 ? " + staging" : ""}${tierCount >= 3 ? " + dev" : ""})` : null
|
|
13634
13649
|
].filter(Boolean);
|
|
13635
13650
|
report(
|
|
13636
|
-
`Setting up "${input.projectName}"
|
|
13651
|
+
`Setting up "${input.projectName}". This creates: ${bits.join(", ")}. The Consort toolkit downloads on first use. Progress:`
|
|
13637
13652
|
);
|
|
13638
13653
|
}
|
|
13639
13654
|
report("Checking Databricks authentication...");
|
|
@@ -13688,7 +13703,7 @@ Last probe error:
|
|
|
13688
13703
|
fs18.mkdirSync(projectDir, { recursive: true });
|
|
13689
13704
|
await gitInit(projectDir);
|
|
13690
13705
|
}
|
|
13691
|
-
report("Creating Lakebase database (provisioning Postgres
|
|
13706
|
+
report("Creating Lakebase database (provisioning Postgres)...", lakebaseProjectId);
|
|
13692
13707
|
await createLakebaseProject({ projectId: lakebaseProjectId, host });
|
|
13693
13708
|
return await withLakebaseRollback(
|
|
13694
13709
|
{ projectId: lakebaseProjectId, host, report },
|
|
@@ -13704,6 +13719,7 @@ Last probe error:
|
|
|
13704
13719
|
databricksHost: host,
|
|
13705
13720
|
lakebaseProjectId,
|
|
13706
13721
|
language,
|
|
13722
|
+
migrationTool: input.migrationTool,
|
|
13707
13723
|
runnerType,
|
|
13708
13724
|
skipCommands,
|
|
13709
13725
|
clientFramework,
|
|
@@ -13768,7 +13784,7 @@ Last probe error:
|
|
|
13768
13784
|
}
|
|
13769
13785
|
}
|
|
13770
13786
|
if (useGithub && runnerType === "self-hosted") {
|
|
13771
|
-
report("Setting up the self-hosted CI runner
|
|
13787
|
+
report("Setting up the self-hosted CI runner: downloading, extracting, and registering it...");
|
|
13772
13788
|
try {
|
|
13773
13789
|
await setupRunner({
|
|
13774
13790
|
fullRepoName,
|
|
@@ -13840,14 +13856,15 @@ Last probe error:
|
|
|
13840
13856
|
}
|
|
13841
13857
|
}
|
|
13842
13858
|
report(
|
|
13843
|
-
"Consort toolkit downloads on first use
|
|
13859
|
+
"The Consort toolkit downloads on first use , run `./scripts/lk --refresh`, or just your first `./scripts/lk` command, and it installs then."
|
|
13844
13860
|
);
|
|
13845
13861
|
}
|
|
13846
13862
|
const langLabels = {
|
|
13847
13863
|
java: "Java/Spring Boot",
|
|
13848
13864
|
kotlin: "Kotlin/Spring Boot",
|
|
13849
13865
|
python: "Python/FastAPI",
|
|
13850
|
-
nodejs: "Node.js/Express"
|
|
13866
|
+
nodejs: "Node.js/Express",
|
|
13867
|
+
dotnet: `.NET/ASP.NET Core (${input.migrationTool === "flyway" ? "Flyway" : "EF Core"})`
|
|
13851
13868
|
};
|
|
13852
13869
|
const langLabel = langLabels[language] ?? language;
|
|
13853
13870
|
report("Creating initial commit...");
|
|
@@ -14028,8 +14045,8 @@ function _testMakeBrownfieldFixture(opts) {
|
|
|
14028
14045
|
|
|
14029
14046
|
// scripts/lakebase/infra-runner.ts
|
|
14030
14047
|
init_esm_shims();
|
|
14031
|
-
import * as
|
|
14032
|
-
import * as
|
|
14048
|
+
import * as fs29 from "fs";
|
|
14049
|
+
import * as path31 from "path";
|
|
14033
14050
|
|
|
14034
14051
|
// scripts/lakebase/schema-diff.ts
|
|
14035
14052
|
init_esm_shims();
|
|
@@ -14225,18 +14242,84 @@ function dbcli6(args) {
|
|
|
14225
14242
|
|
|
14226
14243
|
// scripts/lakebase/schema-migrate.ts
|
|
14227
14244
|
init_esm_shims();
|
|
14228
|
-
import * as
|
|
14229
|
-
import * as
|
|
14245
|
+
import * as fs28 from "fs";
|
|
14246
|
+
import * as path30 from "path";
|
|
14230
14247
|
|
|
14231
14248
|
// scripts/lakebase/migration-layout.ts
|
|
14232
14249
|
init_esm_shims();
|
|
14250
|
+
import * as fs21 from "fs";
|
|
14251
|
+
import * as path21 from "path";
|
|
14252
|
+
|
|
14253
|
+
// scripts/lakebase/dotnet-project.ts
|
|
14254
|
+
init_esm_shims();
|
|
14233
14255
|
import * as fs20 from "fs";
|
|
14234
14256
|
import * as path20 from "path";
|
|
14257
|
+
var EF_DESIGN_PACKAGE = "Microsoft.EntityFrameworkCore.Design";
|
|
14258
|
+
var DOTNET_FLYWAY_DIR = path20.join("db", "migrations");
|
|
14259
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["bin", "obj", "node_modules", ".git", "client", "tests", "test"]);
|
|
14260
|
+
function safeReaddir(dir) {
|
|
14261
|
+
try {
|
|
14262
|
+
return fs20.readdirSync(dir, { withFileTypes: true });
|
|
14263
|
+
} catch {
|
|
14264
|
+
return [];
|
|
14265
|
+
}
|
|
14266
|
+
}
|
|
14267
|
+
function hasDotnetMarker(dir) {
|
|
14268
|
+
return safeReaddir(dir).some(
|
|
14269
|
+
(e) => e.isFile() && /\.(sln|slnx|csproj)$/i.test(e.name)
|
|
14270
|
+
);
|
|
14271
|
+
}
|
|
14272
|
+
function findCsprojFiles(projectDir) {
|
|
14273
|
+
const found = [];
|
|
14274
|
+
const walk = (dir, depth) => {
|
|
14275
|
+
for (const e of safeReaddir(dir)) {
|
|
14276
|
+
const full = path20.join(dir, e.name);
|
|
14277
|
+
if (e.isFile() && e.name.toLowerCase().endsWith(".csproj")) {
|
|
14278
|
+
found.push(full);
|
|
14279
|
+
} else if (e.isDirectory() && depth < 2 && !SKIP_DIRS.has(e.name.toLowerCase()) && !e.name.startsWith(".")) {
|
|
14280
|
+
walk(full, depth + 1);
|
|
14281
|
+
}
|
|
14282
|
+
}
|
|
14283
|
+
};
|
|
14284
|
+
walk(projectDir, 0);
|
|
14285
|
+
return found.sort();
|
|
14286
|
+
}
|
|
14287
|
+
function findEfCoreProject(projectDir) {
|
|
14288
|
+
for (const csproj of findCsprojFiles(projectDir)) {
|
|
14289
|
+
let content = "";
|
|
14290
|
+
try {
|
|
14291
|
+
content = fs20.readFileSync(csproj, "utf-8");
|
|
14292
|
+
} catch {
|
|
14293
|
+
continue;
|
|
14294
|
+
}
|
|
14295
|
+
if (content.includes(EF_DESIGN_PACKAGE)) {
|
|
14296
|
+
const dir = path20.dirname(csproj);
|
|
14297
|
+
return { csproj, projectDir: dir, migrationsDir: path20.join(dir, "Migrations") };
|
|
14298
|
+
}
|
|
14299
|
+
}
|
|
14300
|
+
return null;
|
|
14301
|
+
}
|
|
14302
|
+
function isDotnetProject(projectDir) {
|
|
14303
|
+
return hasDotnetMarker(projectDir);
|
|
14304
|
+
}
|
|
14305
|
+
function isDotnetFlywayProject(projectDir) {
|
|
14306
|
+
return isDotnetProject(projectDir) && fs20.existsSync(path20.join(projectDir, DOTNET_FLYWAY_DIR));
|
|
14307
|
+
}
|
|
14308
|
+
var MAVEN_FLYWAY_DIR = path20.join("src", "main", "resources", "db", "migration");
|
|
14309
|
+
function flywayMigrationsDir(projectDir) {
|
|
14310
|
+
const maven = path20.join(projectDir, MAVEN_FLYWAY_DIR);
|
|
14311
|
+
if (fs20.existsSync(maven) || fs20.existsSync(path20.join(projectDir, "pom.xml"))) return maven;
|
|
14312
|
+
if (isDotnetFlywayProject(projectDir)) return path20.join(projectDir, DOTNET_FLYWAY_DIR);
|
|
14313
|
+
return maven;
|
|
14314
|
+
}
|
|
14315
|
+
|
|
14316
|
+
// scripts/lakebase/migration-layout.ts
|
|
14235
14317
|
var MIGRATION_LANGUAGES = [
|
|
14236
14318
|
"java",
|
|
14237
14319
|
"kotlin",
|
|
14238
14320
|
"python",
|
|
14239
14321
|
"nodejs",
|
|
14322
|
+
"dotnet",
|
|
14240
14323
|
"unknown"
|
|
14241
14324
|
];
|
|
14242
14325
|
var MIGRATION_DEFAULTS = {
|
|
@@ -14244,16 +14327,19 @@ var MIGRATION_DEFAULTS = {
|
|
|
14244
14327
|
kotlin: { path: "src/main/resources/db/migration", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" },
|
|
14245
14328
|
python: { path: "alembic/versions", pattern: /^[0-9a-f][\w]*.*\.py$/i, glob: "*.py" },
|
|
14246
14329
|
nodejs: { path: "migrations", pattern: /^\d+.*\.(js|ts)$/i, glob: "*.{js,ts}" },
|
|
14330
|
+
// .NET + Flyway; EF Core projects get their Migrations/ dir from
|
|
14331
|
+
// resolveMigrationLayout (see DOTNET_EFCORE_DEFAULTS).
|
|
14332
|
+
dotnet: { path: "db/migrations", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" },
|
|
14247
14333
|
unknown: { path: "src/main/resources/db/migration", pattern: /^V\d+.*\.sql$/i, glob: "*.sql" }
|
|
14248
14334
|
};
|
|
14249
14335
|
function detectLanguageAt(dir) {
|
|
14250
|
-
if (
|
|
14251
|
-
const kotlinDir =
|
|
14252
|
-
if (
|
|
14336
|
+
if (fs21.existsSync(path21.join(dir, "pom.xml"))) {
|
|
14337
|
+
const kotlinDir = path21.join(dir, "src", "main", "kotlin");
|
|
14338
|
+
if (fs21.existsSync(kotlinDir)) {
|
|
14253
14339
|
return "kotlin";
|
|
14254
14340
|
}
|
|
14255
14341
|
try {
|
|
14256
|
-
const pom =
|
|
14342
|
+
const pom = fs21.readFileSync(path21.join(dir, "pom.xml"), "utf-8");
|
|
14257
14343
|
if (pom.includes("kotlin-maven-plugin")) {
|
|
14258
14344
|
return "kotlin";
|
|
14259
14345
|
}
|
|
@@ -14261,10 +14347,13 @@ function detectLanguageAt(dir) {
|
|
|
14261
14347
|
}
|
|
14262
14348
|
return "java";
|
|
14263
14349
|
}
|
|
14264
|
-
if (
|
|
14350
|
+
if (fs21.existsSync(path21.join(dir, "pyproject.toml")) || fs21.existsSync(path21.join(dir, "requirements.txt")) || fs21.existsSync(path21.join(dir, "alembic.ini"))) {
|
|
14265
14351
|
return "python";
|
|
14266
14352
|
}
|
|
14267
|
-
if (
|
|
14353
|
+
if (hasDotnetMarker(dir)) {
|
|
14354
|
+
return "dotnet";
|
|
14355
|
+
}
|
|
14356
|
+
if (fs21.existsSync(path21.join(dir, "package.json"))) {
|
|
14268
14357
|
return "nodejs";
|
|
14269
14358
|
}
|
|
14270
14359
|
return "unknown";
|
|
@@ -14285,14 +14374,14 @@ function resolveMigrationLanguage(projectDir, configuredMigrationPath, override)
|
|
|
14285
14374
|
if (!rel) {
|
|
14286
14375
|
return "unknown";
|
|
14287
14376
|
}
|
|
14288
|
-
const rootResolved =
|
|
14289
|
-
let dir =
|
|
14290
|
-
while (dir === rootResolved || dir.startsWith(rootResolved +
|
|
14377
|
+
const rootResolved = path21.resolve(projectDir);
|
|
14378
|
+
let dir = path21.resolve(projectDir, rel);
|
|
14379
|
+
while (dir === rootResolved || dir.startsWith(rootResolved + path21.sep)) {
|
|
14291
14380
|
const lang = detectLanguageAt(dir);
|
|
14292
14381
|
if (lang !== "unknown") {
|
|
14293
14382
|
return lang;
|
|
14294
14383
|
}
|
|
14295
|
-
const parent =
|
|
14384
|
+
const parent = path21.dirname(dir);
|
|
14296
14385
|
if (parent === dir) {
|
|
14297
14386
|
break;
|
|
14298
14387
|
}
|
|
@@ -14311,10 +14400,33 @@ function compileMigrationPattern(src) {
|
|
|
14311
14400
|
return void 0;
|
|
14312
14401
|
}
|
|
14313
14402
|
}
|
|
14403
|
+
var DOTNET_EFCORE_DEFAULTS = {
|
|
14404
|
+
path: "Migrations",
|
|
14405
|
+
pattern: /^\d{14}_(?!.*\.Designer\.cs$).+\.cs$/i,
|
|
14406
|
+
glob: "*.cs"
|
|
14407
|
+
};
|
|
14408
|
+
var DOTNET_LAYOUT_TTL_MS = 5e3;
|
|
14409
|
+
var dotnetLayoutCache = /* @__PURE__ */ new Map();
|
|
14410
|
+
function dotnetDefaults(projectDir) {
|
|
14411
|
+
if (!projectDir) return MIGRATION_DEFAULTS.dotnet;
|
|
14412
|
+
const key = path21.resolve(projectDir);
|
|
14413
|
+
const hit = dotnetLayoutCache.get(key);
|
|
14414
|
+
if (hit && Date.now() - hit.at < DOTNET_LAYOUT_TTL_MS) return hit.value;
|
|
14415
|
+
let value = MIGRATION_DEFAULTS.dotnet;
|
|
14416
|
+
if (!isDotnetFlywayProject(projectDir)) {
|
|
14417
|
+
const ef = findEfCoreProject(projectDir);
|
|
14418
|
+
if (ef) {
|
|
14419
|
+
const rel = path21.relative(projectDir, ef.migrationsDir).split(path21.sep).join("/");
|
|
14420
|
+
value = { ...DOTNET_EFCORE_DEFAULTS, path: rel };
|
|
14421
|
+
}
|
|
14422
|
+
}
|
|
14423
|
+
dotnetLayoutCache.set(key, { at: Date.now(), value });
|
|
14424
|
+
return value;
|
|
14425
|
+
}
|
|
14314
14426
|
function resolveMigrationLayout(args) {
|
|
14315
14427
|
const configuredMigrationPath = (args.migrationPath ?? "").trim();
|
|
14316
14428
|
const language = resolveMigrationLanguage(args.projectDir, configuredMigrationPath, args.language);
|
|
14317
|
-
const defaults = MIGRATION_DEFAULTS[language];
|
|
14429
|
+
const defaults = language === "dotnet" ? dotnetDefaults(args.projectDir) : MIGRATION_DEFAULTS[language];
|
|
14318
14430
|
return {
|
|
14319
14431
|
language,
|
|
14320
14432
|
migrationPath: configuredMigrationPath || defaults.path,
|
|
@@ -14325,22 +14437,22 @@ function resolveMigrationLayout(args) {
|
|
|
14325
14437
|
|
|
14326
14438
|
// scripts/lakebase/adapters/alembic-adapter.ts
|
|
14327
14439
|
init_esm_shims();
|
|
14328
|
-
import * as
|
|
14329
|
-
import * as
|
|
14440
|
+
import * as fs23 from "fs";
|
|
14441
|
+
import * as path23 from "path";
|
|
14330
14442
|
|
|
14331
14443
|
// scripts/lakebase/schema-migrate-runners/alembic.ts
|
|
14332
14444
|
init_esm_shims();
|
|
14333
14445
|
import { spawn as spawn5 } from "child_process";
|
|
14334
|
-
import * as
|
|
14335
|
-
import * as
|
|
14446
|
+
import * as fs22 from "fs";
|
|
14447
|
+
import * as path22 from "path";
|
|
14336
14448
|
function resolveAlembicBin(projectDir) {
|
|
14337
14449
|
const candidates = [
|
|
14338
|
-
|
|
14339
|
-
|
|
14450
|
+
path22.join(projectDir, ".venv", "bin", "alembic"),
|
|
14451
|
+
path22.join(projectDir, "venv", "bin", "alembic")
|
|
14340
14452
|
];
|
|
14341
14453
|
for (const candidate of candidates) {
|
|
14342
14454
|
try {
|
|
14343
|
-
if (
|
|
14455
|
+
if (fs22.existsSync(candidate)) return candidate;
|
|
14344
14456
|
} catch {
|
|
14345
14457
|
}
|
|
14346
14458
|
}
|
|
@@ -14350,7 +14462,7 @@ function spawnAlembic(projectDir, args, dsn) {
|
|
|
14350
14462
|
return new Promise((resolve2, reject) => {
|
|
14351
14463
|
const bin = resolveAlembicBin(projectDir);
|
|
14352
14464
|
const env = { ...process.env };
|
|
14353
|
-
env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(
|
|
14465
|
+
env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path22.delimiter);
|
|
14354
14466
|
if (dsn) env.DATABASE_URL = dsn;
|
|
14355
14467
|
const child = spawn5(bin, args, {
|
|
14356
14468
|
cwd: projectDir,
|
|
@@ -14398,10 +14510,10 @@ async function createAlembicRevision(opts) {
|
|
|
14398
14510
|
const m = stdout.match(/Generating\s+(\S+\.py)/);
|
|
14399
14511
|
if (m) return m[1].trim();
|
|
14400
14512
|
for (const rel of ["migrations/versions", "alembic/versions"]) {
|
|
14401
|
-
const dir =
|
|
14402
|
-
if (!
|
|
14403
|
-
const hit =
|
|
14404
|
-
if (hit) return
|
|
14513
|
+
const dir = path22.join(opts.projectDir, rel);
|
|
14514
|
+
if (!fs22.existsSync(dir)) continue;
|
|
14515
|
+
const hit = fs22.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
|
|
14516
|
+
if (hit) return path22.join(dir, hit);
|
|
14405
14517
|
}
|
|
14406
14518
|
throw new SchemaMigrationError(
|
|
14407
14519
|
`alembic revision succeeded but the created file could not be located.
|
|
@@ -14536,15 +14648,15 @@ async function buildDsn2(args) {
|
|
|
14536
14648
|
}
|
|
14537
14649
|
function findVersionsDir(projectDir) {
|
|
14538
14650
|
const candidates = [
|
|
14539
|
-
|
|
14540
|
-
|
|
14651
|
+
path23.join(projectDir, "migrations", "versions"),
|
|
14652
|
+
path23.join(projectDir, "alembic", "versions")
|
|
14541
14653
|
];
|
|
14542
|
-
return candidates.find((p) =>
|
|
14654
|
+
return candidates.find((p) => fs23.existsSync(p));
|
|
14543
14655
|
}
|
|
14544
14656
|
function listAlembicFiles(projectDir) {
|
|
14545
14657
|
const dir = findVersionsDir(projectDir);
|
|
14546
14658
|
if (!dir) return [];
|
|
14547
|
-
const files =
|
|
14659
|
+
const files = fs23.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
|
|
14548
14660
|
return files.map((filename) => {
|
|
14549
14661
|
const stem = filename.replace(/\.py$/, "");
|
|
14550
14662
|
const sep4 = stem.indexOf("_");
|
|
@@ -14569,9 +14681,9 @@ var AlembicAdapter = {
|
|
|
14569
14681
|
* here. Callers can still force-select via project.yaml#migration_tool.
|
|
14570
14682
|
*/
|
|
14571
14683
|
detect(projectDir) {
|
|
14572
|
-
if (
|
|
14573
|
-
if (
|
|
14574
|
-
if (
|
|
14684
|
+
if (fs23.existsSync(path23.join(projectDir, "alembic.ini"))) return true;
|
|
14685
|
+
if (fs23.existsSync(path23.join(projectDir, "migrations", "env.py"))) return true;
|
|
14686
|
+
if (fs23.existsSync(path23.join(projectDir, "alembic", "env.py"))) return true;
|
|
14575
14687
|
return false;
|
|
14576
14688
|
},
|
|
14577
14689
|
async apply(args) {
|
|
@@ -14677,7 +14789,7 @@ var AlembicAdapter = {
|
|
|
14677
14789
|
autogenerate: !!args.autogenerate,
|
|
14678
14790
|
dsn
|
|
14679
14791
|
});
|
|
14680
|
-
return { status: "ok", version: revId, filename:
|
|
14792
|
+
return { status: "ok", version: revId, filename: path23.basename(created), path: created };
|
|
14681
14793
|
} catch (err) {
|
|
14682
14794
|
return {
|
|
14683
14795
|
status: "error",
|
|
@@ -14694,7 +14806,7 @@ var AlembicAdapter = {
|
|
|
14694
14806
|
if (heads.length <= 1) return { status: "noop", headsBefore: heads };
|
|
14695
14807
|
if (args.dryRun) return { status: "ok", headsBefore: heads };
|
|
14696
14808
|
const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
|
|
14697
|
-
const mergeRevision =
|
|
14809
|
+
const mergeRevision = path23.basename(created).replace(/\.py$/, "").split("_")[0];
|
|
14698
14810
|
return { status: "ok", headsBefore: heads, mergeRevision, path: created };
|
|
14699
14811
|
} catch (err) {
|
|
14700
14812
|
return {
|
|
@@ -14709,13 +14821,13 @@ registerSchemaMigrationAdapter(AlembicAdapter);
|
|
|
14709
14821
|
|
|
14710
14822
|
// scripts/lakebase/adapters/flyway-adapter.ts
|
|
14711
14823
|
init_esm_shims();
|
|
14712
|
-
import * as
|
|
14713
|
-
import * as
|
|
14824
|
+
import * as fs24 from "fs";
|
|
14825
|
+
import * as path25 from "path";
|
|
14714
14826
|
|
|
14715
14827
|
// scripts/lakebase/schema-migrate-runners/flyway.ts
|
|
14716
14828
|
init_esm_shims();
|
|
14717
14829
|
import { spawn as spawn6 } from "child_process";
|
|
14718
|
-
import * as
|
|
14830
|
+
import * as path24 from "path";
|
|
14719
14831
|
function dsnToFlywayEnv(dsn) {
|
|
14720
14832
|
const u = new URL(dsn);
|
|
14721
14833
|
const user = decodeURIComponent(u.username);
|
|
@@ -14725,7 +14837,7 @@ function dsnToFlywayEnv(dsn) {
|
|
|
14725
14837
|
return { url, user, password };
|
|
14726
14838
|
}
|
|
14727
14839
|
function migrationsLocation(projectDir) {
|
|
14728
|
-
return `filesystem:${
|
|
14840
|
+
return `filesystem:${flywayMigrationsDir(projectDir)}`;
|
|
14729
14841
|
}
|
|
14730
14842
|
function runFlyway(ctx, args) {
|
|
14731
14843
|
const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
|
|
@@ -14826,7 +14938,7 @@ async function statusFlyway(ctx) {
|
|
|
14826
14938
|
if (state === "SUCCESS" || state === "BASELINE") {
|
|
14827
14939
|
current = m.version;
|
|
14828
14940
|
} else if (state === "PENDING") {
|
|
14829
|
-
const filename = m.filepath ?
|
|
14941
|
+
const filename = m.filepath ? path24.basename(m.filepath) : `V${m.version}__migration.sql`;
|
|
14830
14942
|
pending.push({
|
|
14831
14943
|
version: m.version,
|
|
14832
14944
|
filename,
|
|
@@ -14849,9 +14961,9 @@ async function buildDsn3(args) {
|
|
|
14849
14961
|
return result.url;
|
|
14850
14962
|
}
|
|
14851
14963
|
function listFlywayFiles(projectDir) {
|
|
14852
|
-
const dir =
|
|
14853
|
-
if (!
|
|
14854
|
-
const files =
|
|
14964
|
+
const dir = flywayMigrationsDir(projectDir);
|
|
14965
|
+
if (!fs24.existsSync(dir)) return [];
|
|
14966
|
+
const files = fs24.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
|
|
14855
14967
|
return files.map((filename) => {
|
|
14856
14968
|
const m = filename.match(/^V(\d+(?:\.\d+)*)__(.+)\.sql$/);
|
|
14857
14969
|
const version = m[1];
|
|
@@ -14872,9 +14984,9 @@ function versionCompare(a, b) {
|
|
|
14872
14984
|
}
|
|
14873
14985
|
var FlywayAdapter = {
|
|
14874
14986
|
id: "flyway",
|
|
14875
|
-
languages: ["java", "kotlin"],
|
|
14987
|
+
languages: ["java", "kotlin", "dotnet"],
|
|
14876
14988
|
detect(projectDir) {
|
|
14877
|
-
return
|
|
14989
|
+
return fs24.existsSync(path25.join(projectDir, "pom.xml")) || isDotnetFlywayProject(projectDir);
|
|
14878
14990
|
},
|
|
14879
14991
|
async apply(args) {
|
|
14880
14992
|
const dsn = await buildDsn3(args);
|
|
@@ -14932,14 +15044,14 @@ var FlywayAdapter = {
|
|
|
14932
15044
|
// optional-protocol shape makes this additive.
|
|
14933
15045
|
async newMigration(args) {
|
|
14934
15046
|
try {
|
|
14935
|
-
const dir =
|
|
14936
|
-
|
|
15047
|
+
const dir = flywayMigrationsDir(args.projectDir);
|
|
15048
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
14937
15049
|
const version = migrationTimestamp();
|
|
14938
15050
|
const slug = migrationSlug2(args.slug);
|
|
14939
15051
|
const filename = `V${version}__${slug}.sql`;
|
|
14940
|
-
const full =
|
|
14941
|
-
if (
|
|
14942
|
-
|
|
15052
|
+
const full = path25.join(dir, filename);
|
|
15053
|
+
if (fs24.existsSync(full)) throw new Error(`${filename} already exists`);
|
|
15054
|
+
fs24.writeFileSync(
|
|
14943
15055
|
full,
|
|
14944
15056
|
`-- V${version}: ${args.slug}
|
|
14945
15057
|
-- Flyway migration (write your DDL/DML below).
|
|
@@ -14962,19 +15074,19 @@ registerSchemaMigrationAdapter(FlywayAdapter);
|
|
|
14962
15074
|
|
|
14963
15075
|
// scripts/lakebase/adapters/knex-adapter.ts
|
|
14964
15076
|
init_esm_shims();
|
|
14965
|
-
import * as
|
|
14966
|
-
import * as
|
|
15077
|
+
import * as fs26 from "fs";
|
|
15078
|
+
import * as path27 from "path";
|
|
14967
15079
|
|
|
14968
15080
|
// scripts/lakebase/schema-migrate-runners/knex.ts
|
|
14969
15081
|
init_esm_shims();
|
|
14970
15082
|
import { spawn as spawn7 } from "child_process";
|
|
14971
|
-
import * as
|
|
14972
|
-
import * as
|
|
15083
|
+
import * as fs25 from "fs";
|
|
15084
|
+
import * as path26 from "path";
|
|
14973
15085
|
var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
|
|
14974
15086
|
function findKnexfile(projectDir) {
|
|
14975
15087
|
for (const name of KNEXFILE_VARIANTS) {
|
|
14976
|
-
const p =
|
|
14977
|
-
if (
|
|
15088
|
+
const p = path26.join(projectDir, name);
|
|
15089
|
+
if (fs25.existsSync(p)) return p;
|
|
14978
15090
|
}
|
|
14979
15091
|
return void 0;
|
|
14980
15092
|
}
|
|
@@ -15126,9 +15238,9 @@ async function buildDsn4(args) {
|
|
|
15126
15238
|
}
|
|
15127
15239
|
var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
|
|
15128
15240
|
function listKnexFiles(projectDir) {
|
|
15129
|
-
const dir =
|
|
15130
|
-
if (!
|
|
15131
|
-
const files =
|
|
15241
|
+
const dir = path27.join(projectDir, "migrations");
|
|
15242
|
+
if (!fs26.existsSync(dir)) return [];
|
|
15243
|
+
const files = fs26.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
|
|
15132
15244
|
return files.map((filename) => {
|
|
15133
15245
|
const stem = filename.replace(/\.(js|ts)$/, "");
|
|
15134
15246
|
const m = stem.match(/^(\d{14})_(.+)$/);
|
|
@@ -15148,7 +15260,7 @@ var KnexAdapter = {
|
|
|
15148
15260
|
* project.yaml#migration_tool.
|
|
15149
15261
|
*/
|
|
15150
15262
|
detect(projectDir) {
|
|
15151
|
-
return KNEXFILE_VARIANTS2.some((name) =>
|
|
15263
|
+
return KNEXFILE_VARIANTS2.some((name) => fs26.existsSync(path27.join(projectDir, name)));
|
|
15152
15264
|
},
|
|
15153
15265
|
async apply(args) {
|
|
15154
15266
|
const dsn = await buildDsn4(args);
|
|
@@ -15221,9 +15333,9 @@ var KnexAdapter = {
|
|
|
15221
15333
|
async newMigration(args) {
|
|
15222
15334
|
try {
|
|
15223
15335
|
const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
|
|
15224
|
-
const stem =
|
|
15336
|
+
const stem = path27.basename(created).replace(/\.(js|ts)$/, "");
|
|
15225
15337
|
const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
|
|
15226
|
-
return { status: "ok", version, filename:
|
|
15338
|
+
return { status: "ok", version, filename: path27.basename(created), path: created };
|
|
15227
15339
|
} catch (err) {
|
|
15228
15340
|
return {
|
|
15229
15341
|
status: "error",
|
|
@@ -15237,6 +15349,362 @@ var KnexAdapter = {
|
|
|
15237
15349
|
};
|
|
15238
15350
|
registerSchemaMigrationAdapter(KnexAdapter);
|
|
15239
15351
|
|
|
15352
|
+
// scripts/lakebase/adapters/efcore-adapter.ts
|
|
15353
|
+
init_esm_shims();
|
|
15354
|
+
import * as path29 from "path";
|
|
15355
|
+
|
|
15356
|
+
// scripts/lakebase/schema-migrate-runners/efcore.ts
|
|
15357
|
+
init_esm_shims();
|
|
15358
|
+
import { spawn as spawn8 } from "child_process";
|
|
15359
|
+
import * as fs27 from "fs";
|
|
15360
|
+
import * as path28 from "path";
|
|
15361
|
+
import { Client as Client3 } from "pg";
|
|
15362
|
+
var MIGRATION_ID = /^(\d{14})_(.+)$/;
|
|
15363
|
+
function efVersion(id) {
|
|
15364
|
+
return MIGRATION_ID.exec(id)?.[1] ?? id;
|
|
15365
|
+
}
|
|
15366
|
+
function efDescription(id) {
|
|
15367
|
+
const name = MIGRATION_ID.exec(id)?.[2] ?? id;
|
|
15368
|
+
return name.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2");
|
|
15369
|
+
}
|
|
15370
|
+
function dsnToNpgsql(dsn) {
|
|
15371
|
+
const u = new URL(dsn);
|
|
15372
|
+
const parts = [
|
|
15373
|
+
`Host=${u.hostname}`,
|
|
15374
|
+
`Port=${u.port || "5432"}`,
|
|
15375
|
+
`Database=${decodeURIComponent(u.pathname.replace(/^\//, "")) || "databricks_postgres"}`
|
|
15376
|
+
];
|
|
15377
|
+
if (u.username) parts.push(`Username=${decodeURIComponent(u.username)}`);
|
|
15378
|
+
if (u.password) parts.push(`Password=${decodeURIComponent(u.password)}`);
|
|
15379
|
+
const sslmode = (u.searchParams.get("sslmode") ?? "require").toLowerCase();
|
|
15380
|
+
const ssl = {
|
|
15381
|
+
disable: "Disable",
|
|
15382
|
+
allow: "Allow",
|
|
15383
|
+
prefer: "Prefer",
|
|
15384
|
+
require: "Require",
|
|
15385
|
+
"verify-ca": "VerifyCA",
|
|
15386
|
+
"verify-full": "VerifyFull"
|
|
15387
|
+
};
|
|
15388
|
+
parts.push(`SSL Mode=${ssl[sslmode] ?? "Require"}`);
|
|
15389
|
+
const app = u.searchParams.get("application_name");
|
|
15390
|
+
if (app) parts.push(`Application Name=${app}`);
|
|
15391
|
+
return parts.map((p) => p.replace(/;/g, "")).join(";");
|
|
15392
|
+
}
|
|
15393
|
+
function parseEfJson(stdout) {
|
|
15394
|
+
const body = stdout.split(/\r?\n/).filter((l) => l.startsWith("data:")).map((l) => l.slice("data:".length)).join("\n").trim();
|
|
15395
|
+
if (!body) {
|
|
15396
|
+
throw new SchemaMigrationError(`dotnet ef returned no JSON payload: ${stdout.slice(0, 400)}`);
|
|
15397
|
+
}
|
|
15398
|
+
try {
|
|
15399
|
+
return JSON.parse(body);
|
|
15400
|
+
} catch (err) {
|
|
15401
|
+
throw new SchemaMigrationError(
|
|
15402
|
+
`dotnet ef JSON parse failed: ${err instanceof Error ? err.message : String(err)}.
|
|
15403
|
+
Body (first 400 chars): ${body.slice(0, 400)}`
|
|
15404
|
+
);
|
|
15405
|
+
}
|
|
15406
|
+
}
|
|
15407
|
+
function requireProject(projectDir) {
|
|
15408
|
+
const project = findEfCoreProject(projectDir);
|
|
15409
|
+
if (!project) {
|
|
15410
|
+
throw new SchemaMigrationError(
|
|
15411
|
+
`No EF Core project found under ${projectDir}. Expected a *.csproj that references ${EF_DESIGN_PACKAGE}.`
|
|
15412
|
+
);
|
|
15413
|
+
}
|
|
15414
|
+
return project;
|
|
15415
|
+
}
|
|
15416
|
+
function spawnDotnet(projectDir, args, env) {
|
|
15417
|
+
return new Promise((resolve2, reject) => {
|
|
15418
|
+
const child = spawn8("dotnet", args, {
|
|
15419
|
+
cwd: projectDir,
|
|
15420
|
+
env: { ...process.env, DOTNET_NOLOGO: "1", DOTNET_CLI_TELEMETRY_OPTOUT: "1", ...env },
|
|
15421
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
15422
|
+
});
|
|
15423
|
+
let stdout = "";
|
|
15424
|
+
let stderr = "";
|
|
15425
|
+
child.stdout.on("data", (chunk) => {
|
|
15426
|
+
stdout += chunk.toString("utf8");
|
|
15427
|
+
});
|
|
15428
|
+
child.stderr.on("data", (chunk) => {
|
|
15429
|
+
stderr += chunk.toString("utf8");
|
|
15430
|
+
});
|
|
15431
|
+
child.on("error", (err) => {
|
|
15432
|
+
reject(
|
|
15433
|
+
new SchemaMigrationError(
|
|
15434
|
+
`Could not spawn dotnet. Is the .NET SDK installed and on PATH? ${err.message}`,
|
|
15435
|
+
err
|
|
15436
|
+
)
|
|
15437
|
+
);
|
|
15438
|
+
});
|
|
15439
|
+
child.on("close", (code) => {
|
|
15440
|
+
if (code === 0) {
|
|
15441
|
+
resolve2({ stdout, stderr });
|
|
15442
|
+
} else {
|
|
15443
|
+
reject(
|
|
15444
|
+
new SchemaMigrationError(
|
|
15445
|
+
`dotnet ${args.join(" ")} exited with code ${code}.
|
|
15446
|
+
stdout: ${stdout}
|
|
15447
|
+
stderr: ${stderr}`
|
|
15448
|
+
)
|
|
15449
|
+
);
|
|
15450
|
+
}
|
|
15451
|
+
});
|
|
15452
|
+
});
|
|
15453
|
+
}
|
|
15454
|
+
var restored = /* @__PURE__ */ new Set();
|
|
15455
|
+
async function ensureRestored(projectDir, csproj) {
|
|
15456
|
+
if (restored.has(projectDir)) return;
|
|
15457
|
+
if (fs27.existsSync(path28.join(projectDir, ".config", "dotnet-tools.json"))) {
|
|
15458
|
+
await spawnDotnet(projectDir, ["tool", "restore"], {});
|
|
15459
|
+
}
|
|
15460
|
+
await spawnDotnet(projectDir, ["restore", csproj], {});
|
|
15461
|
+
restored.add(projectDir);
|
|
15462
|
+
}
|
|
15463
|
+
async function runEf(projectDir, args, dsn, opts = {}) {
|
|
15464
|
+
const project = requireProject(projectDir);
|
|
15465
|
+
const csproj = path28.relative(projectDir, project.csproj) || project.csproj;
|
|
15466
|
+
await ensureRestored(projectDir, csproj);
|
|
15467
|
+
const full = ["ef", ...args, "--project", csproj, "--prefix-output"];
|
|
15468
|
+
if (opts.noBuild) full.push("--no-build");
|
|
15469
|
+
const env = {};
|
|
15470
|
+
if (dsn) {
|
|
15471
|
+
env.DATABASE_URL = dsn;
|
|
15472
|
+
if (process.env.LAKEBASE_EFCORE_CONNECTION_ARG === "1") full.push("--connection", dsnToNpgsql(dsn));
|
|
15473
|
+
}
|
|
15474
|
+
return spawnDotnet(projectDir, full, env);
|
|
15475
|
+
}
|
|
15476
|
+
async function listEfMigrations(ctx, opts = {}) {
|
|
15477
|
+
const { stdout, stderr } = await runEf(ctx.projectDir, ["migrations", "list", "--json"], ctx.dsn, opts);
|
|
15478
|
+
const entries = parseEfJson(stdout);
|
|
15479
|
+
if (ctx.dsn && entries.some((e) => e.applied === null)) {
|
|
15480
|
+
const warning = stdout.split(/\r?\n/).filter((l) => /^(warn|error):/.test(l)).join("\n");
|
|
15481
|
+
throw new SchemaMigrationError(
|
|
15482
|
+
`dotnet ef could not read migration state from the database (check connectivity and credentials).
|
|
15483
|
+
${warning || stderr}`.trim()
|
|
15484
|
+
);
|
|
15485
|
+
}
|
|
15486
|
+
return entries;
|
|
15487
|
+
}
|
|
15488
|
+
async function readEfHistory(dsn) {
|
|
15489
|
+
const client = new Client3({ connectionString: dsn, application_name: connectionApplicationName() });
|
|
15490
|
+
await client.connect();
|
|
15491
|
+
try {
|
|
15492
|
+
const exists = await client.query(`SELECT to_regclass('"__EFMigrationsHistory"') IS NOT NULL AS present`);
|
|
15493
|
+
if (!exists.rows[0]?.present) return null;
|
|
15494
|
+
const r = await client.query(`SELECT "MigrationId" FROM "__EFMigrationsHistory" ORDER BY "MigrationId"`);
|
|
15495
|
+
return r.rows.map((row) => row.MigrationId);
|
|
15496
|
+
} finally {
|
|
15497
|
+
await client.end();
|
|
15498
|
+
}
|
|
15499
|
+
}
|
|
15500
|
+
function toApplied(entries) {
|
|
15501
|
+
return entries.map((e) => ({ version: efVersion(e.id), description: efDescription(e.id) }));
|
|
15502
|
+
}
|
|
15503
|
+
async function statusEfcore(ctx) {
|
|
15504
|
+
const entries = await listEfMigrations(ctx);
|
|
15505
|
+
const history = await (ctx.readHistory ?? readEfHistory)(ctx.dsn);
|
|
15506
|
+
const current = history && history.length > 0 ? efVersion(history[history.length - 1]) : void 0;
|
|
15507
|
+
const pending = entries.filter((e) => e.applied !== true).map((e) => ({ version: efVersion(e.id), filename: `${e.id}.cs`, description: efDescription(e.id) }));
|
|
15508
|
+
return { current, pending, tool: "efcore" };
|
|
15509
|
+
}
|
|
15510
|
+
async function applyEfcore(ctx) {
|
|
15511
|
+
const before = new Set((await listEfMigrations(ctx)).filter((e) => e.applied).map((e) => e.id));
|
|
15512
|
+
await runEf(ctx.projectDir, ["database", "update"], ctx.dsn, { noBuild: true });
|
|
15513
|
+
const after = await listEfMigrations(ctx, { noBuild: true });
|
|
15514
|
+
const applied = toApplied(after.filter((e) => e.applied && !before.has(e.id)));
|
|
15515
|
+
return { applied, alreadyAtLatest: applied.length === 0, tool: "efcore" };
|
|
15516
|
+
}
|
|
15517
|
+
function resolveEfTarget(target, applied) {
|
|
15518
|
+
const t = target.trim();
|
|
15519
|
+
if (t === "0") return "0";
|
|
15520
|
+
const rel = /^-(\d+)$/.exec(t);
|
|
15521
|
+
if (rel) {
|
|
15522
|
+
const steps = Number(rel[1]);
|
|
15523
|
+
if (steps < 1) throw new SchemaMigrationError(`Invalid rollback step: ${target}`);
|
|
15524
|
+
const index = applied.length - 1 - steps;
|
|
15525
|
+
if (index < -1) {
|
|
15526
|
+
throw new SchemaMigrationError(`Cannot roll back ${steps} migration(s); only ${applied.length} applied.`);
|
|
15527
|
+
}
|
|
15528
|
+
return index === -1 ? "0" : applied[index].id;
|
|
15529
|
+
}
|
|
15530
|
+
const match = applied.find((e) => e.id === t || efVersion(e.id) === t || e.name === t);
|
|
15531
|
+
if (!match) throw new SchemaMigrationError(`Rollback target '${target}' is not an applied migration.`);
|
|
15532
|
+
return match.id;
|
|
15533
|
+
}
|
|
15534
|
+
async function rollbackEfcore(ctx) {
|
|
15535
|
+
const beforeEntries = (await listEfMigrations(ctx)).filter((e) => e.applied);
|
|
15536
|
+
const targetId = resolveEfTarget(ctx.target, beforeEntries);
|
|
15537
|
+
await runEf(ctx.projectDir, ["database", "update", targetId], ctx.dsn, { noBuild: true });
|
|
15538
|
+
const stillApplied = new Set((await listEfMigrations(ctx, { noBuild: true })).filter((e) => e.applied).map((e) => e.id));
|
|
15539
|
+
return { rolledBack: toApplied(beforeEntries.filter((e) => !stillApplied.has(e.id)).reverse()), tool: "efcore" };
|
|
15540
|
+
}
|
|
15541
|
+
function efMigrationName(slug) {
|
|
15542
|
+
const name = slug.split(/[^A-Za-z0-9]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join("");
|
|
15543
|
+
if (!name) throw new SchemaMigrationError(`Cannot derive a migration name from '${slug}'.`);
|
|
15544
|
+
return /^[0-9]/.test(name) ? `M${name}` : name;
|
|
15545
|
+
}
|
|
15546
|
+
async function createEfcoreMigration(opts) {
|
|
15547
|
+
const project = requireProject(opts.projectDir);
|
|
15548
|
+
const name = efMigrationName(opts.slug);
|
|
15549
|
+
const existing = new Set(fs27.existsSync(project.migrationsDir) ? fs27.readdirSync(project.migrationsDir) : []);
|
|
15550
|
+
await runEf(opts.projectDir, ["migrations", "add", name]);
|
|
15551
|
+
const created = fs27.readdirSync(project.migrationsDir).filter((f) => !existing.has(f) && MIGRATION_ID.test(f.replace(/\.cs$/, "")) && !f.endsWith(".Designer.cs"));
|
|
15552
|
+
if (created.length !== 1) {
|
|
15553
|
+
throw new SchemaMigrationError(`Expected one new migration file for ${name}, found: ${created.join(", ") || "none"}`);
|
|
15554
|
+
}
|
|
15555
|
+
return { id: created[0].replace(/\.cs$/, ""), path: path28.join(project.migrationsDir, created[0]) };
|
|
15556
|
+
}
|
|
15557
|
+
function localEfMigrationIds(projectDir) {
|
|
15558
|
+
const project = findEfCoreProject(projectDir);
|
|
15559
|
+
if (!project || !fs27.existsSync(project.migrationsDir)) return [];
|
|
15560
|
+
return fs27.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();
|
|
15561
|
+
}
|
|
15562
|
+
function efProductVersion(project) {
|
|
15563
|
+
try {
|
|
15564
|
+
const csproj = fs27.readFileSync(project.csproj, "utf-8");
|
|
15565
|
+
const m = new RegExp(`${EF_DESIGN_PACKAGE.replace(/\./g, "\\.")}"\\s+Version="([^"]+)"`).exec(csproj);
|
|
15566
|
+
if (m) return m[1];
|
|
15567
|
+
} catch {
|
|
15568
|
+
}
|
|
15569
|
+
return "unknown";
|
|
15570
|
+
}
|
|
15571
|
+
async function stampEfcore(ctx) {
|
|
15572
|
+
const project = requireProject(ctx.projectDir);
|
|
15573
|
+
const ids = localEfMigrationIds(ctx.projectDir);
|
|
15574
|
+
if (ids.length === 0) throw new SchemaMigrationError("No local EF Core migrations to stamp.");
|
|
15575
|
+
const rev = ctx.revision.trim();
|
|
15576
|
+
const end = rev === "head" ? ids.length - 1 : ids.findIndex((id) => id === rev || efVersion(id) === rev);
|
|
15577
|
+
if (end < 0) throw new SchemaMigrationError(`Stamp revision '${ctx.revision}' is not a local migration.`);
|
|
15578
|
+
const toStamp = ids.slice(0, end + 1);
|
|
15579
|
+
const productVersion = efProductVersion(project);
|
|
15580
|
+
const client = new Client3({ connectionString: ctx.dsn, application_name: connectionApplicationName() });
|
|
15581
|
+
await client.connect();
|
|
15582
|
+
try {
|
|
15583
|
+
await client.query("BEGIN");
|
|
15584
|
+
await client.query(
|
|
15585
|
+
`CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
|
|
15586
|
+
"MigrationId" character varying(150) NOT NULL,
|
|
15587
|
+
"ProductVersion" character varying(32) NOT NULL,
|
|
15588
|
+
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId"))`
|
|
15589
|
+
);
|
|
15590
|
+
await client.query(`DELETE FROM "__EFMigrationsHistory" WHERE NOT ("MigrationId" = ANY($1::text[]))`, [toStamp]);
|
|
15591
|
+
for (const id of toStamp) {
|
|
15592
|
+
await client.query(
|
|
15593
|
+
`INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ($1, $2)
|
|
15594
|
+
ON CONFLICT ("MigrationId") DO NOTHING`,
|
|
15595
|
+
[id, productVersion]
|
|
15596
|
+
);
|
|
15597
|
+
}
|
|
15598
|
+
await client.query("COMMIT");
|
|
15599
|
+
} catch (err) {
|
|
15600
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
15601
|
+
throw err;
|
|
15602
|
+
} finally {
|
|
15603
|
+
await client.end();
|
|
15604
|
+
}
|
|
15605
|
+
return efVersion(toStamp[toStamp.length - 1]);
|
|
15606
|
+
}
|
|
15607
|
+
|
|
15608
|
+
// scripts/lakebase/adapters/efcore-adapter.ts
|
|
15609
|
+
async function buildDsn5(args) {
|
|
15610
|
+
const result = await getConnection({
|
|
15611
|
+
output: "dsn",
|
|
15612
|
+
instance: args.instance,
|
|
15613
|
+
branch: args.branch,
|
|
15614
|
+
database: args.database,
|
|
15615
|
+
endpointName: args.endpointName
|
|
15616
|
+
});
|
|
15617
|
+
return result.url;
|
|
15618
|
+
}
|
|
15619
|
+
function errMsg(err) {
|
|
15620
|
+
return err instanceof Error ? err.message : String(err);
|
|
15621
|
+
}
|
|
15622
|
+
function listEfCoreFiles(projectDir) {
|
|
15623
|
+
return localEfMigrationIds(projectDir).map((id) => ({
|
|
15624
|
+
version: efVersion(id),
|
|
15625
|
+
filename: `${id}.cs`,
|
|
15626
|
+
description: efDescription(id),
|
|
15627
|
+
type: "CSharp",
|
|
15628
|
+
tool: "efcore"
|
|
15629
|
+
}));
|
|
15630
|
+
}
|
|
15631
|
+
var EfCoreAdapter = {
|
|
15632
|
+
id: "efcore",
|
|
15633
|
+
languages: ["dotnet"],
|
|
15634
|
+
/** A .NET project (root marker) with a *.csproj that references Microsoft.EntityFrameworkCore.Design. */
|
|
15635
|
+
detect(projectDir) {
|
|
15636
|
+
return isDotnetProject(projectDir) && findEfCoreProject(projectDir) !== null;
|
|
15637
|
+
},
|
|
15638
|
+
async apply(args) {
|
|
15639
|
+
try {
|
|
15640
|
+
const dsn = await buildDsn5(args);
|
|
15641
|
+
const r = await applyEfcore({ projectDir: args.projectDir, dsn });
|
|
15642
|
+
return {
|
|
15643
|
+
applied_migrations: r.applied,
|
|
15644
|
+
status: r.alreadyAtLatest ? "noop" : "ok",
|
|
15645
|
+
tool_specific: { alreadyAtLatest: r.alreadyAtLatest, tool: r.tool }
|
|
15646
|
+
};
|
|
15647
|
+
} catch (err) {
|
|
15648
|
+
return { applied_migrations: [], status: "error", error: errMsg(err) };
|
|
15649
|
+
}
|
|
15650
|
+
},
|
|
15651
|
+
async rollback(args) {
|
|
15652
|
+
try {
|
|
15653
|
+
const dsn = await buildDsn5(args);
|
|
15654
|
+
const r = await rollbackEfcore({ projectDir: args.projectDir, dsn, target: args.target });
|
|
15655
|
+
return {
|
|
15656
|
+
rolled_back: r.rolledBack,
|
|
15657
|
+
status: r.rolledBack.length === 0 ? "noop" : "ok",
|
|
15658
|
+
tool_specific: { tool: r.tool }
|
|
15659
|
+
};
|
|
15660
|
+
} catch (err) {
|
|
15661
|
+
return { rolled_back: [], status: "error", error: errMsg(err) };
|
|
15662
|
+
}
|
|
15663
|
+
},
|
|
15664
|
+
async stamp(args) {
|
|
15665
|
+
try {
|
|
15666
|
+
const dsn = await buildDsn5(args);
|
|
15667
|
+
const stamped = await stampEfcore({ projectDir: args.projectDir, dsn, revision: args.revision });
|
|
15668
|
+
return { status: "ok", stamped_revision: stamped, tool_specific: { tool: "efcore" } };
|
|
15669
|
+
} catch (err) {
|
|
15670
|
+
return { status: "error", stamped_revision: null, error: errMsg(err) };
|
|
15671
|
+
}
|
|
15672
|
+
},
|
|
15673
|
+
async status(args) {
|
|
15674
|
+
try {
|
|
15675
|
+
const dsn = await buildDsn5(args);
|
|
15676
|
+
const r = await statusEfcore({ projectDir: args.projectDir, dsn });
|
|
15677
|
+
return {
|
|
15678
|
+
applied_version: r.current ?? null,
|
|
15679
|
+
pending: r.pending,
|
|
15680
|
+
applied: [],
|
|
15681
|
+
status: "ok",
|
|
15682
|
+
tool_specific: { tool: r.tool }
|
|
15683
|
+
};
|
|
15684
|
+
} catch (err) {
|
|
15685
|
+
return { applied_version: null, pending: [], applied: [], status: "error", error: errMsg(err) };
|
|
15686
|
+
}
|
|
15687
|
+
},
|
|
15688
|
+
async list(args) {
|
|
15689
|
+
return { files: listEfCoreFiles(args.projectDir) };
|
|
15690
|
+
},
|
|
15691
|
+
// baseline: use stamp (EF has no separate baseline concept).
|
|
15692
|
+
async newMigration(args) {
|
|
15693
|
+
try {
|
|
15694
|
+
const created = await createEfcoreMigration({ projectDir: args.projectDir, slug: args.slug });
|
|
15695
|
+
return {
|
|
15696
|
+
status: "ok",
|
|
15697
|
+
version: efVersion(created.id),
|
|
15698
|
+
filename: path29.basename(created.path),
|
|
15699
|
+
path: created.path
|
|
15700
|
+
};
|
|
15701
|
+
} catch (err) {
|
|
15702
|
+
return { status: "error", version: "", filename: "", path: "", error: errMsg(err) };
|
|
15703
|
+
}
|
|
15704
|
+
}
|
|
15705
|
+
};
|
|
15706
|
+
registerSchemaMigrationAdapter(EfCoreAdapter);
|
|
15707
|
+
|
|
15240
15708
|
// scripts/lakebase/schema-migrate.ts
|
|
15241
15709
|
var SchemaMigrationError = class extends Error {
|
|
15242
15710
|
constructor(message, cause) {
|
|
@@ -15250,13 +15718,16 @@ function detectLanguage(projectDir) {
|
|
|
15250
15718
|
const lang = resolveMigrationLanguage(projectDir);
|
|
15251
15719
|
if (lang === "unknown") {
|
|
15252
15720
|
throw new SchemaMigrationError(
|
|
15253
|
-
`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.`
|
|
15721
|
+
`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.`
|
|
15254
15722
|
);
|
|
15255
15723
|
}
|
|
15256
15724
|
return lang;
|
|
15257
15725
|
}
|
|
15258
|
-
function toolForLanguage(language) {
|
|
15726
|
+
function toolForLanguage(language, projectDir) {
|
|
15259
15727
|
switch (language) {
|
|
15728
|
+
case "dotnet":
|
|
15729
|
+
if (projectDir && isDotnetFlywayProject(projectDir)) return "flyway";
|
|
15730
|
+
return "efcore";
|
|
15260
15731
|
case "java":
|
|
15261
15732
|
case "kotlin":
|
|
15262
15733
|
return "flyway";
|
|
@@ -15269,8 +15740,10 @@ function toolForLanguage(language) {
|
|
|
15269
15740
|
function listSchemaMigrations(args = {}) {
|
|
15270
15741
|
const projectDir = args.projectDir ?? process.cwd();
|
|
15271
15742
|
const language = args.language ?? detectLanguage(projectDir);
|
|
15272
|
-
const tool = toolForLanguage(language);
|
|
15743
|
+
const tool = toolForLanguage(language, projectDir);
|
|
15273
15744
|
switch (tool) {
|
|
15745
|
+
case "efcore":
|
|
15746
|
+
return listEfCoreFiles(projectDir);
|
|
15274
15747
|
case "flyway":
|
|
15275
15748
|
return listFlywayMigrations(projectDir);
|
|
15276
15749
|
case "alembic":
|
|
@@ -15280,9 +15753,9 @@ function listSchemaMigrations(args = {}) {
|
|
|
15280
15753
|
}
|
|
15281
15754
|
}
|
|
15282
15755
|
function listFlywayMigrations(projectDir) {
|
|
15283
|
-
const dir =
|
|
15284
|
-
if (!
|
|
15285
|
-
const files =
|
|
15756
|
+
const dir = flywayMigrationsDir(projectDir);
|
|
15757
|
+
if (!fs28.existsSync(dir)) return [];
|
|
15758
|
+
const files = fs28.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
|
|
15286
15759
|
return files.map((filename) => {
|
|
15287
15760
|
const m = filename.match(/^V(\d+(?:\.\d+)*)__(.+)\.sql$/);
|
|
15288
15761
|
const version = m[1];
|
|
@@ -15292,12 +15765,12 @@ function listFlywayMigrations(projectDir) {
|
|
|
15292
15765
|
}
|
|
15293
15766
|
function listAlembicMigrations(projectDir) {
|
|
15294
15767
|
const candidates = [
|
|
15295
|
-
|
|
15296
|
-
|
|
15768
|
+
path30.join(projectDir, "migrations", "versions"),
|
|
15769
|
+
path30.join(projectDir, "alembic", "versions")
|
|
15297
15770
|
];
|
|
15298
|
-
const dir = candidates.find((p) =>
|
|
15771
|
+
const dir = candidates.find((p) => fs28.existsSync(p));
|
|
15299
15772
|
if (!dir) return [];
|
|
15300
|
-
const files =
|
|
15773
|
+
const files = fs28.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
|
|
15301
15774
|
return files.map((filename) => {
|
|
15302
15775
|
const stem = filename.replace(/\.py$/, "");
|
|
15303
15776
|
const sep4 = stem.indexOf("_");
|
|
@@ -15307,9 +15780,9 @@ function listAlembicMigrations(projectDir) {
|
|
|
15307
15780
|
}).sort((a, b) => a.filename.localeCompare(b.filename));
|
|
15308
15781
|
}
|
|
15309
15782
|
function listKnexMigrations(projectDir) {
|
|
15310
|
-
const dir =
|
|
15311
|
-
if (!
|
|
15312
|
-
const files =
|
|
15783
|
+
const dir = path30.join(projectDir, "migrations");
|
|
15784
|
+
if (!fs28.existsSync(dir)) return [];
|
|
15785
|
+
const files = fs28.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
|
|
15313
15786
|
return files.map((filename) => {
|
|
15314
15787
|
const stem = filename.replace(/\.(js|ts)$/, "");
|
|
15315
15788
|
const m = stem.match(/^(\d{14})_(.+)$/);
|
|
@@ -15331,7 +15804,7 @@ function versionCompare2(a, b) {
|
|
|
15331
15804
|
return 0;
|
|
15332
15805
|
}
|
|
15333
15806
|
function adapterFor(projectDir, language) {
|
|
15334
|
-
const override = language ? toolForLanguage(language) : void 0;
|
|
15807
|
+
const override = language ? toolForLanguage(language, projectDir) : void 0;
|
|
15335
15808
|
return resolveSchemaMigrationAdapter(projectDir, override);
|
|
15336
15809
|
}
|
|
15337
15810
|
var TierMigrationRefusedError = class extends Error {
|
|
@@ -15485,8 +15958,8 @@ async function runInfraSuite(args) {
|
|
|
15485
15958
|
duration_ms: Date.now() - start
|
|
15486
15959
|
};
|
|
15487
15960
|
if (args.junitOutput) {
|
|
15488
|
-
|
|
15489
|
-
|
|
15961
|
+
fs29.mkdirSync(path31.dirname(args.junitOutput), { recursive: true });
|
|
15962
|
+
fs29.writeFileSync(args.junitOutput, formatJUnit(result), "utf8");
|
|
15490
15963
|
}
|
|
15491
15964
|
return result;
|
|
15492
15965
|
}
|
|
@@ -15532,8 +16005,8 @@ function escapeXml(s) {
|
|
|
15532
16005
|
|
|
15533
16006
|
// scripts/lakebase/scm-claim-feature.ts
|
|
15534
16007
|
init_esm_shims();
|
|
15535
|
-
import * as
|
|
15536
|
-
import * as
|
|
16008
|
+
import * as fs30 from "fs";
|
|
16009
|
+
import * as path32 from "path";
|
|
15537
16010
|
var ScmClaimError = class extends Error {
|
|
15538
16011
|
constructor(message, code) {
|
|
15539
16012
|
super(message);
|
|
@@ -15590,7 +16063,7 @@ async function claimFeatureBranch(args) {
|
|
|
15590
16063
|
const current = readWorkflowState(args.projectDir);
|
|
15591
16064
|
if (!current) {
|
|
15592
16065
|
throw new ScmClaimError(
|
|
15593
|
-
`No SCM workflow state found at ${
|
|
16066
|
+
`No SCM workflow state found at ${path32.join(args.projectDir, ".lakebase/workflow-state.json")}. Run lakebase-create-project to scaffold, or re-seed via the substrate.`,
|
|
15594
16067
|
"no-state-file"
|
|
15595
16068
|
);
|
|
15596
16069
|
}
|
|
@@ -15694,8 +16167,8 @@ function alreadyClaimedSentinel(state) {
|
|
|
15694
16167
|
};
|
|
15695
16168
|
}
|
|
15696
16169
|
function workflowStateFileExists(projectDir) {
|
|
15697
|
-
return
|
|
15698
|
-
|
|
16170
|
+
return fs30.existsSync(
|
|
16171
|
+
path32.join(projectDir, ".lakebase/workflow-state.json")
|
|
15699
16172
|
);
|
|
15700
16173
|
}
|
|
15701
16174
|
|
|
@@ -16217,12 +16690,12 @@ async function sync(args) {
|
|
|
16217
16690
|
|
|
16218
16691
|
// scripts/lakebase/workflow-drift.ts
|
|
16219
16692
|
init_esm_shims();
|
|
16220
|
-
import * as
|
|
16221
|
-
import * as
|
|
16693
|
+
import * as fs31 from "fs";
|
|
16694
|
+
import * as path33 from "path";
|
|
16222
16695
|
function findKitTemplatesDir(start) {
|
|
16223
16696
|
let dir = start;
|
|
16224
16697
|
for (let i = 0; i < 6; i++) {
|
|
16225
|
-
const candidate =
|
|
16698
|
+
const candidate = path33.join(
|
|
16226
16699
|
dir,
|
|
16227
16700
|
"templates",
|
|
16228
16701
|
"project",
|
|
@@ -16230,8 +16703,8 @@ function findKitTemplatesDir(start) {
|
|
|
16230
16703
|
".github",
|
|
16231
16704
|
"workflows"
|
|
16232
16705
|
);
|
|
16233
|
-
if (
|
|
16234
|
-
const parent =
|
|
16706
|
+
if (fs31.existsSync(candidate)) return candidate;
|
|
16707
|
+
const parent = path33.dirname(dir);
|
|
16235
16708
|
if (parent === dir) break;
|
|
16236
16709
|
dir = parent;
|
|
16237
16710
|
}
|
|
@@ -16255,13 +16728,13 @@ function unifiedDiff(name, projectContent, templateContent) {
|
|
|
16255
16728
|
return out.join("\n");
|
|
16256
16729
|
}
|
|
16257
16730
|
function detectWorkflowDrift(args) {
|
|
16258
|
-
const projectWorkflowsDir =
|
|
16731
|
+
const projectWorkflowsDir = path33.join(
|
|
16259
16732
|
args.projectDir,
|
|
16260
16733
|
".github",
|
|
16261
16734
|
"workflows"
|
|
16262
16735
|
);
|
|
16263
|
-
const here =
|
|
16264
|
-
const kitWorkflowsDir = args.kitDir ?
|
|
16736
|
+
const here = path33.dirname(new URL(import.meta.url).pathname);
|
|
16737
|
+
const kitWorkflowsDir = args.kitDir ? path33.join(
|
|
16265
16738
|
args.kitDir,
|
|
16266
16739
|
"templates",
|
|
16267
16740
|
"project",
|
|
@@ -16269,21 +16742,21 @@ function detectWorkflowDrift(args) {
|
|
|
16269
16742
|
".github",
|
|
16270
16743
|
"workflows"
|
|
16271
16744
|
) : findKitTemplatesDir(here);
|
|
16272
|
-
const templateFiles =
|
|
16273
|
-
const projectFiles =
|
|
16745
|
+
const templateFiles = fs31.existsSync(kitWorkflowsDir) ? fs31.readdirSync(kitWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16746
|
+
const projectFiles = fs31.existsSync(projectWorkflowsDir) ? fs31.readdirSync(projectWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16274
16747
|
const version = readKitVersion(kitWorkflowsDir);
|
|
16275
16748
|
const seen = /* @__PURE__ */ new Set();
|
|
16276
16749
|
const files = [];
|
|
16277
16750
|
for (const name of templateFiles) {
|
|
16278
16751
|
seen.add(name);
|
|
16279
|
-
const projectPath2 =
|
|
16280
|
-
const templatePath =
|
|
16281
|
-
if (!
|
|
16752
|
+
const projectPath2 = path33.join(projectWorkflowsDir, name);
|
|
16753
|
+
const templatePath = path33.join(kitWorkflowsDir, name);
|
|
16754
|
+
if (!fs31.existsSync(projectPath2)) {
|
|
16282
16755
|
files.push({ name, status: "missing" });
|
|
16283
16756
|
continue;
|
|
16284
16757
|
}
|
|
16285
|
-
const projectContent =
|
|
16286
|
-
const templateContent = applyPlaceholders(
|
|
16758
|
+
const projectContent = fs31.readFileSync(projectPath2, "utf8");
|
|
16759
|
+
const templateContent = applyPlaceholders(fs31.readFileSync(templatePath, "utf8"), version);
|
|
16287
16760
|
if (projectContent === templateContent) {
|
|
16288
16761
|
files.push({ name, status: "unchanged" });
|
|
16289
16762
|
} else {
|
|
@@ -16314,10 +16787,10 @@ function detectWorkflowDrift(args) {
|
|
|
16314
16787
|
function readKitVersion(kitWorkflowsDir) {
|
|
16315
16788
|
let dir = kitWorkflowsDir;
|
|
16316
16789
|
for (let i = 0; i < 5; i++) {
|
|
16317
|
-
dir =
|
|
16790
|
+
dir = path33.dirname(dir);
|
|
16318
16791
|
}
|
|
16319
16792
|
try {
|
|
16320
|
-
const raw =
|
|
16793
|
+
const raw = fs31.readFileSync(path33.join(dir, "package.json"), "utf-8");
|
|
16321
16794
|
const pkg = JSON.parse(raw);
|
|
16322
16795
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
16323
16796
|
} catch {
|
|
@@ -16334,7 +16807,7 @@ var COMMAND_HOOK_FILE_PATTERN = /\.(pre|post)-hook\.md$/;
|
|
|
16334
16807
|
function findKitCommandsDir(start) {
|
|
16335
16808
|
let dir = start;
|
|
16336
16809
|
for (let i = 0; i < 6; i++) {
|
|
16337
|
-
const candidate =
|
|
16810
|
+
const candidate = path33.join(
|
|
16338
16811
|
dir,
|
|
16339
16812
|
"templates",
|
|
16340
16813
|
"project",
|
|
@@ -16342,8 +16815,8 @@ function findKitCommandsDir(start) {
|
|
|
16342
16815
|
".claude",
|
|
16343
16816
|
"commands"
|
|
16344
16817
|
);
|
|
16345
|
-
if (
|
|
16346
|
-
const parent =
|
|
16818
|
+
if (fs31.existsSync(candidate)) return candidate;
|
|
16819
|
+
const parent = path33.dirname(dir);
|
|
16347
16820
|
if (parent === dir) break;
|
|
16348
16821
|
dir = parent;
|
|
16349
16822
|
}
|
|
@@ -16356,24 +16829,24 @@ function parsePinnedVersion(content) {
|
|
|
16356
16829
|
return m ? m[1] : void 0;
|
|
16357
16830
|
}
|
|
16358
16831
|
function detectCommandDrift(args) {
|
|
16359
|
-
const projectCommandsDir =
|
|
16360
|
-
const here =
|
|
16361
|
-
const kitCommandsDir = args.kitDir ?
|
|
16832
|
+
const projectCommandsDir = path33.join(args.projectDir, ".claude", "commands");
|
|
16833
|
+
const here = path33.dirname(new URL(import.meta.url).pathname);
|
|
16834
|
+
const kitCommandsDir = args.kitDir ? path33.join(args.kitDir, "templates", "project", "common", ".claude", "commands") : findKitCommandsDir(here);
|
|
16362
16835
|
const kitVersion = readKitVersionFromCommandsDir(kitCommandsDir);
|
|
16363
|
-
const templateFiles =
|
|
16364
|
-
const projectFiles =
|
|
16836
|
+
const templateFiles = fs31.existsSync(kitCommandsDir) ? fs31.readdirSync(kitCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
|
|
16837
|
+
const projectFiles = fs31.existsSync(projectCommandsDir) ? fs31.readdirSync(projectCommandsDir).filter((f) => f.endsWith(".md") && !COMMAND_HOOK_FILE_PATTERN.test(f)) : [];
|
|
16365
16838
|
const seen = /* @__PURE__ */ new Set();
|
|
16366
16839
|
const files = [];
|
|
16367
16840
|
for (const name of templateFiles) {
|
|
16368
16841
|
seen.add(name);
|
|
16369
|
-
const projectPath2 =
|
|
16370
|
-
const templatePath =
|
|
16371
|
-
const templateRaw =
|
|
16372
|
-
if (!
|
|
16842
|
+
const projectPath2 = path33.join(projectCommandsDir, name);
|
|
16843
|
+
const templatePath = path33.join(kitCommandsDir, name);
|
|
16844
|
+
const templateRaw = fs31.readFileSync(templatePath, "utf8");
|
|
16845
|
+
if (!fs31.existsSync(projectPath2)) {
|
|
16373
16846
|
files.push({ name, status: "missing", kit_version: kitVersion });
|
|
16374
16847
|
continue;
|
|
16375
16848
|
}
|
|
16376
|
-
const projectContent =
|
|
16849
|
+
const projectContent = fs31.readFileSync(projectPath2, "utf8");
|
|
16377
16850
|
const pinned = parsePinnedVersion(projectContent);
|
|
16378
16851
|
const versionForCompare = pinned ?? kitVersion;
|
|
16379
16852
|
const templateContent = applyCommandPlaceholders(templateRaw, versionForCompare);
|
|
@@ -16411,10 +16884,10 @@ function detectCommandDrift(args) {
|
|
|
16411
16884
|
function readKitVersionFromCommandsDir(kitCommandsDir) {
|
|
16412
16885
|
let dir = kitCommandsDir;
|
|
16413
16886
|
for (let i = 0; i < 5; i++) {
|
|
16414
|
-
dir =
|
|
16887
|
+
dir = path33.dirname(dir);
|
|
16415
16888
|
}
|
|
16416
16889
|
try {
|
|
16417
|
-
const raw =
|
|
16890
|
+
const raw = fs31.readFileSync(path33.join(dir, "package.json"), "utf-8");
|
|
16418
16891
|
const pkg = JSON.parse(raw);
|
|
16419
16892
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
16420
16893
|
} catch {
|
|
@@ -16431,13 +16904,13 @@ function detectScaffoldedDrift(args) {
|
|
|
16431
16904
|
};
|
|
16432
16905
|
}
|
|
16433
16906
|
function updateWorkflows(args) {
|
|
16434
|
-
const projectWorkflowsDir =
|
|
16907
|
+
const projectWorkflowsDir = path33.join(
|
|
16435
16908
|
args.projectDir,
|
|
16436
16909
|
".github",
|
|
16437
16910
|
"workflows"
|
|
16438
16911
|
);
|
|
16439
|
-
const here =
|
|
16440
|
-
const kitWorkflowsDir = args.kitDir ?
|
|
16912
|
+
const here = path33.dirname(new URL(import.meta.url).pathname);
|
|
16913
|
+
const kitWorkflowsDir = args.kitDir ? path33.join(
|
|
16441
16914
|
args.kitDir,
|
|
16442
16915
|
"templates",
|
|
16443
16916
|
"project",
|
|
@@ -16448,22 +16921,22 @@ function updateWorkflows(args) {
|
|
|
16448
16921
|
const substitute = args.substitute !== false;
|
|
16449
16922
|
const dryRun = args.dryRun === true;
|
|
16450
16923
|
const pruneExtras = args.pruneExtras === true;
|
|
16451
|
-
const templateFiles =
|
|
16452
|
-
const projectFiles =
|
|
16453
|
-
if (!dryRun && templateFiles.length > 0 && !
|
|
16454
|
-
|
|
16924
|
+
const templateFiles = fs31.existsSync(kitWorkflowsDir) ? fs31.readdirSync(kitWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16925
|
+
const projectFiles = fs31.existsSync(projectWorkflowsDir) ? fs31.readdirSync(projectWorkflowsDir).filter((f) => f.endsWith(".yml")) : [];
|
|
16926
|
+
if (!dryRun && templateFiles.length > 0 && !fs31.existsSync(projectWorkflowsDir)) {
|
|
16927
|
+
fs31.mkdirSync(projectWorkflowsDir, { recursive: true });
|
|
16455
16928
|
}
|
|
16456
16929
|
const version = substitute ? readKitVersion(kitWorkflowsDir) : "";
|
|
16457
16930
|
const seen = /* @__PURE__ */ new Set();
|
|
16458
16931
|
const files = [];
|
|
16459
16932
|
for (const name of templateFiles) {
|
|
16460
16933
|
seen.add(name);
|
|
16461
|
-
const projectPath2 =
|
|
16462
|
-
const templatePath =
|
|
16463
|
-
const templateRaw =
|
|
16934
|
+
const projectPath2 = path33.join(projectWorkflowsDir, name);
|
|
16935
|
+
const templatePath = path33.join(kitWorkflowsDir, name);
|
|
16936
|
+
const templateRaw = fs31.readFileSync(templatePath, "utf-8");
|
|
16464
16937
|
const desired = substitute ? applyPlaceholders(templateRaw, version) : templateRaw;
|
|
16465
|
-
const existed =
|
|
16466
|
-
const current = existed ?
|
|
16938
|
+
const existed = fs31.existsSync(projectPath2);
|
|
16939
|
+
const current = existed ? fs31.readFileSync(projectPath2, "utf-8") : "";
|
|
16467
16940
|
let outcome;
|
|
16468
16941
|
if (!existed) {
|
|
16469
16942
|
outcome = "added";
|
|
@@ -16473,16 +16946,16 @@ function updateWorkflows(args) {
|
|
|
16473
16946
|
outcome = "updated";
|
|
16474
16947
|
}
|
|
16475
16948
|
if (!dryRun && outcome !== "unchanged") {
|
|
16476
|
-
|
|
16949
|
+
fs31.writeFileSync(projectPath2, desired);
|
|
16477
16950
|
}
|
|
16478
16951
|
files.push({ name, outcome });
|
|
16479
16952
|
}
|
|
16480
16953
|
if (pruneExtras) {
|
|
16481
16954
|
for (const name of projectFiles) {
|
|
16482
16955
|
if (seen.has(name)) continue;
|
|
16483
|
-
const projectPath2 =
|
|
16956
|
+
const projectPath2 = path33.join(projectWorkflowsDir, name);
|
|
16484
16957
|
if (!dryRun) {
|
|
16485
|
-
|
|
16958
|
+
fs31.unlinkSync(projectPath2);
|
|
16486
16959
|
}
|
|
16487
16960
|
files.push({ name, outcome: "removed" });
|
|
16488
16961
|
}
|
|
@@ -17115,15 +17588,15 @@ function parentForTopology(t, defaultLeaf) {
|
|
|
17115
17588
|
|
|
17116
17589
|
// scripts/lakebase/scm-doctor.ts
|
|
17117
17590
|
init_esm_shims();
|
|
17118
|
-
import * as
|
|
17119
|
-
import * as
|
|
17591
|
+
import * as fs32 from "fs";
|
|
17592
|
+
import * as path34 from "path";
|
|
17120
17593
|
var FEATURE_PREFIX = "feature/";
|
|
17121
17594
|
var TIER_LEAFS2 = DEFAULT_PROTECTED_TIER_NAMES;
|
|
17122
17595
|
function readEnv(projectDir) {
|
|
17123
|
-
const envPath =
|
|
17596
|
+
const envPath = path34.join(projectDir, ".env");
|
|
17124
17597
|
const out = /* @__PURE__ */ new Map();
|
|
17125
|
-
if (!
|
|
17126
|
-
const lines =
|
|
17598
|
+
if (!fs32.existsSync(envPath)) return out;
|
|
17599
|
+
const lines = fs32.readFileSync(envPath, "utf8").split("\n");
|
|
17127
17600
|
for (const line of lines) {
|
|
17128
17601
|
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.+?)\s*$/);
|
|
17129
17602
|
if (m) out.set(m[1], m[2].replace(/^["']|["']$/g, ""));
|
|
@@ -17178,9 +17651,9 @@ async function runDoctor(args, deps = {}) {
|
|
|
17178
17651
|
}
|
|
17179
17652
|
for (const wf of ["pr.yml", "merge.yml"]) {
|
|
17180
17653
|
try {
|
|
17181
|
-
const p =
|
|
17182
|
-
if (!
|
|
17183
|
-
const body =
|
|
17654
|
+
const p = path34.join(projectDir, ".github", "workflows", wf);
|
|
17655
|
+
if (!fs32.existsSync(p)) continue;
|
|
17656
|
+
const body = fs32.readFileSync(p, "utf8");
|
|
17184
17657
|
if (/lakebase-scm-utils#v\d/.test(body)) {
|
|
17185
17658
|
findings.push({
|
|
17186
17659
|
id: "ci-workflow-substrate-pin",
|
|
@@ -17395,7 +17868,7 @@ async function fixFinding(args) {
|
|
|
17395
17868
|
);
|
|
17396
17869
|
}
|
|
17397
17870
|
const sanitized = sanitizeBranchName(branch);
|
|
17398
|
-
const envFile =
|
|
17871
|
+
const envFile = path34.join(args.projectDir, ".env");
|
|
17399
17872
|
updateEnvConnection({
|
|
17400
17873
|
envPath: envFile,
|
|
17401
17874
|
projectId: readEnvVar(envFile, "LAKEBASE_PROJECT_ID") ?? "",
|
|
@@ -17497,14 +17970,14 @@ function shellEscape3(s) {
|
|
|
17497
17970
|
|
|
17498
17971
|
// scripts/lakebase/doctor.ts
|
|
17499
17972
|
init_esm_shims();
|
|
17500
|
-
import * as
|
|
17501
|
-
import * as
|
|
17973
|
+
import * as fs33 from "fs";
|
|
17974
|
+
import * as path35 from "path";
|
|
17502
17975
|
import * as cp6 from "child_process";
|
|
17503
17976
|
function readEnvFile(projectDir) {
|
|
17504
|
-
const envPath =
|
|
17505
|
-
if (!
|
|
17977
|
+
const envPath = path35.join(projectDir, ".env");
|
|
17978
|
+
if (!fs33.existsSync(envPath)) return {};
|
|
17506
17979
|
const out = {};
|
|
17507
|
-
for (const line of
|
|
17980
|
+
for (const line of fs33.readFileSync(envPath, "utf8").split("\n")) {
|
|
17508
17981
|
const m = line.match(/^\s*([A-Z][A-Z0-9_]*)\s*=\s*(.*)\s*$/);
|
|
17509
17982
|
if (!m) continue;
|
|
17510
17983
|
let val = m[2];
|
|
@@ -17658,6 +18131,23 @@ async function checkPrereq(spec, run) {
|
|
|
17658
18131
|
detail: { version: trimmed }
|
|
17659
18132
|
};
|
|
17660
18133
|
}
|
|
18134
|
+
var DOTNET_PREREQ = {
|
|
18135
|
+
name: "dotnet-sdk",
|
|
18136
|
+
cmd: "dotnet",
|
|
18137
|
+
versionArgs: ["--version"],
|
|
18138
|
+
minMajor: 10,
|
|
18139
|
+
label: ".NET SDK",
|
|
18140
|
+
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."
|
|
18141
|
+
};
|
|
18142
|
+
async function checkLanguagePrerequisites(projectDir, run = defaultVersionRunner) {
|
|
18143
|
+
let lang;
|
|
18144
|
+
try {
|
|
18145
|
+
lang = detectLanguage(projectDir);
|
|
18146
|
+
} catch {
|
|
18147
|
+
return [];
|
|
18148
|
+
}
|
|
18149
|
+
return lang === "dotnet" ? [await checkPrereq(DOTNET_PREREQ, run)] : [];
|
|
18150
|
+
}
|
|
17661
18151
|
async function checkPrerequisites(run = defaultVersionRunner) {
|
|
17662
18152
|
return Promise.all(PREREQS.map((spec) => checkPrereq(spec, run)));
|
|
17663
18153
|
}
|
|
@@ -17759,7 +18249,7 @@ function checkEnv(projectDir) {
|
|
|
17759
18249
|
name: "env-file",
|
|
17760
18250
|
status: "warn",
|
|
17761
18251
|
message: ".env not found",
|
|
17762
|
-
detail: { projectDir, envPath:
|
|
18252
|
+
detail: { projectDir, envPath: path35.join(projectDir, ".env") },
|
|
17763
18253
|
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)."
|
|
17764
18254
|
};
|
|
17765
18255
|
}
|
|
@@ -17989,6 +18479,7 @@ async function runDoctor2(args = {}) {
|
|
|
17989
18479
|
const hooks = checkHooks(projectDir);
|
|
17990
18480
|
const workflowDrift = checkWorkflowDrift(projectDir);
|
|
17991
18481
|
const prereqs = await checkPrerequisites();
|
|
18482
|
+
const languagePrereqs = await checkLanguagePrerequisites(projectDir);
|
|
17992
18483
|
const lakebaseEnabled = auth7.status === "ok" ? await checkLakebaseEnabled(profile) : {
|
|
17993
18484
|
name: "lakebase-enabled",
|
|
17994
18485
|
status: "skip",
|
|
@@ -17997,6 +18488,7 @@ async function runDoctor2(args = {}) {
|
|
|
17997
18488
|
const checks = [
|
|
17998
18489
|
cli,
|
|
17999
18490
|
...prereqs,
|
|
18491
|
+
...languagePrereqs,
|
|
18000
18492
|
auth7,
|
|
18001
18493
|
identity,
|
|
18002
18494
|
lakebaseEnabled,
|
|
@@ -18252,8 +18744,8 @@ async function listMigrationsOnBranch(args) {
|
|
|
18252
18744
|
|
|
18253
18745
|
// scripts/git/commits.ts
|
|
18254
18746
|
init_esm_shims();
|
|
18255
|
-
import { existsSync as
|
|
18256
|
-
import { join as
|
|
18747
|
+
import { existsSync as existsSync32 } from "fs";
|
|
18748
|
+
import { join as join35 } from "path";
|
|
18257
18749
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
18258
18750
|
".py",
|
|
18259
18751
|
".ts",
|
|
@@ -18356,7 +18848,7 @@ async function commitAllIfChanged(args) {
|
|
|
18356
18848
|
await exec2("git add -A", { cwd: args.cwd });
|
|
18357
18849
|
}
|
|
18358
18850
|
for (const inc of args.include ?? []) {
|
|
18359
|
-
if (
|
|
18851
|
+
if (existsSync32(join35(args.cwd, inc))) {
|
|
18360
18852
|
await exec2(`git add -f -- ${shq(inc)}`, { cwd: args.cwd });
|
|
18361
18853
|
}
|
|
18362
18854
|
}
|
|
@@ -18498,14 +18990,14 @@ async function stashDropAll(args) {
|
|
|
18498
18990
|
|
|
18499
18991
|
// scripts/git/rebase.ts
|
|
18500
18992
|
init_esm_shims();
|
|
18501
|
-
import * as
|
|
18502
|
-
import * as
|
|
18993
|
+
import * as fs34 from "fs";
|
|
18994
|
+
import * as path36 from "path";
|
|
18503
18995
|
async function abortRebase(args) {
|
|
18504
18996
|
await exec2("git rebase --abort", { cwd: args.cwd });
|
|
18505
18997
|
}
|
|
18506
18998
|
async function isRebasing(args) {
|
|
18507
18999
|
try {
|
|
18508
|
-
return
|
|
19000
|
+
return fs34.existsSync(path36.join(args.cwd, ".git/rebase-merge")) || fs34.existsSync(path36.join(args.cwd, ".git/rebase-apply"));
|
|
18509
19001
|
} catch {
|
|
18510
19002
|
return false;
|
|
18511
19003
|
}
|
|
@@ -18725,6 +19217,9 @@ export {
|
|
|
18725
19217
|
CI_TOKEN_REMINT_MARGIN_SECONDS,
|
|
18726
19218
|
CONVENTION_TIER_DEFAULTS,
|
|
18727
19219
|
DEFAULT_PROTECTED_TIER_NAMES,
|
|
19220
|
+
DOTNET_EFCORE_DEFAULTS,
|
|
19221
|
+
DOTNET_FLYWAY_DIR,
|
|
19222
|
+
EF_DESIGN_PACKAGE,
|
|
18728
19223
|
FIXABLE_FINDING_IDS,
|
|
18729
19224
|
GITHUB_SCOPES,
|
|
18730
19225
|
GitHubPullRequestError,
|
|
@@ -18737,6 +19232,7 @@ export {
|
|
|
18737
19232
|
LakebaseBranchError,
|
|
18738
19233
|
LakebaseBranchTtlTooLongError,
|
|
18739
19234
|
LakebaseProjectError,
|
|
19235
|
+
MAVEN_FLYWAY_DIR,
|
|
18740
19236
|
MIGRATION_DEFAULTS,
|
|
18741
19237
|
NODE_E2E_TEMPLATE_FILES,
|
|
18742
19238
|
PLAYWRIGHT_TEMPLATE_FILES,
|
|
@@ -18873,9 +19369,12 @@ export {
|
|
|
18873
19369
|
fastForwardBranch,
|
|
18874
19370
|
featureBranchName,
|
|
18875
19371
|
fetch2 as fetch,
|
|
19372
|
+
findCsprojFiles,
|
|
18876
19373
|
findDefaultBranchName,
|
|
19374
|
+
findEfCoreProject,
|
|
18877
19375
|
findHistoryRetentionDuration,
|
|
18878
19376
|
fixFinding,
|
|
19377
|
+
flywayMigrationsDir,
|
|
18879
19378
|
formatJUnit,
|
|
18880
19379
|
formatOwnerRepo,
|
|
18881
19380
|
formatSchemaDiffAsMarkdown,
|
|
@@ -18925,6 +19424,7 @@ export {
|
|
|
18925
19424
|
gitInit,
|
|
18926
19425
|
grantLakebasePermission,
|
|
18927
19426
|
grantUcCatalogPermission,
|
|
19427
|
+
hasDotnetMarker,
|
|
18928
19428
|
hasRemoteBranch,
|
|
18929
19429
|
hasUpstream,
|
|
18930
19430
|
inferTierTopology,
|
|
@@ -18934,6 +19434,8 @@ export {
|
|
|
18934
19434
|
isAllSchemas,
|
|
18935
19435
|
isCliEntry,
|
|
18936
19436
|
isDirty,
|
|
19437
|
+
isDotnetFlywayProject,
|
|
19438
|
+
isDotnetProject,
|
|
18937
19439
|
isForeignFeatureClaim,
|
|
18938
19440
|
isGitTracked,
|
|
18939
19441
|
isLongRunningTierBranch,
|