@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
|
@@ -30,6 +30,9 @@ import { normalizeTierName, protectedTierNamesFromEnv } from "./branch-utils.js"
|
|
|
30
30
|
import "./adapters/alembic-adapter.js";
|
|
31
31
|
import "./adapters/flyway-adapter.js";
|
|
32
32
|
import "./adapters/knex-adapter.js";
|
|
33
|
+
import "./adapters/efcore-adapter.js";
|
|
34
|
+
import { isDotnetFlywayProject, flywayMigrationsDir } from "./dotnet-project.js";
|
|
35
|
+
import { listEfCoreFiles } from "./adapters/efcore-adapter.js";
|
|
33
36
|
import {
|
|
34
37
|
resolveSchemaMigrationAdapter,
|
|
35
38
|
type SchemaMigrationAdapterId,
|
|
@@ -38,9 +41,9 @@ import {
|
|
|
38
41
|
type CollapseHeadsResult,
|
|
39
42
|
} from "./schema-migration-adapter.js";
|
|
40
43
|
|
|
41
|
-
export type SchemaMigrationLanguage = "java" | "kotlin" | "python" | "nodejs";
|
|
44
|
+
export type SchemaMigrationLanguage = "java" | "kotlin" | "python" | "nodejs" | "dotnet";
|
|
42
45
|
|
|
43
|
-
export type SchemaMigrationToolName = "flyway" | "alembic" | "knex";
|
|
46
|
+
export type SchemaMigrationToolName = "flyway" | "alembic" | "knex" | "efcore";
|
|
44
47
|
|
|
45
48
|
export interface SchemaMigrationFile {
|
|
46
49
|
/** Stable identifier sortable in apply-order: Flyway `V<n>`, Alembic
|
|
@@ -48,7 +51,7 @@ export interface SchemaMigrationFile {
|
|
|
48
51
|
version: string;
|
|
49
52
|
filename: string;
|
|
50
53
|
description: string;
|
|
51
|
-
type: "SQL" | "Python" | "JavaScript" | "TypeScript";
|
|
54
|
+
type: "SQL" | "Python" | "JavaScript" | "TypeScript" | "CSharp";
|
|
52
55
|
/** Tool that should run this file. */
|
|
53
56
|
tool: SchemaMigrationToolName;
|
|
54
57
|
}
|
|
@@ -149,16 +152,24 @@ export function detectLanguage(projectDir: string): SchemaMigrationLanguage {
|
|
|
149
152
|
if (lang === "unknown") {
|
|
150
153
|
throw new SchemaMigrationError(
|
|
151
154
|
`Could not detect project language in ${projectDir}. ` +
|
|
152
|
-
`Expected one of: pom.xml (java/kotlin), pyproject.toml or alembic.ini (python), package.json (nodejs). ` +
|
|
155
|
+
`Expected one of: pom.xml (java/kotlin), pyproject.toml or alembic.ini (python), package.json (nodejs), *.sln or *.csproj (dotnet). ` +
|
|
153
156
|
`Pass {language} explicitly to override.`
|
|
154
157
|
);
|
|
155
158
|
}
|
|
156
159
|
return lang;
|
|
157
160
|
}
|
|
158
161
|
|
|
159
|
-
/**
|
|
160
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Map a language to the migration tool the kit invokes for it. .NET supports
|
|
164
|
+
* two tools, so it also needs the project directory: EF Core when a project
|
|
165
|
+
* references Microsoft.EntityFrameworkCore.Design, Flyway when SQL migrations
|
|
166
|
+
* live in db/migrations/ (Flyway wins when both are present), else EF Core.
|
|
167
|
+
*/
|
|
168
|
+
export function toolForLanguage(language: SchemaMigrationLanguage, projectDir?: string): SchemaMigrationToolName {
|
|
161
169
|
switch (language) {
|
|
170
|
+
case "dotnet":
|
|
171
|
+
if (projectDir && isDotnetFlywayProject(projectDir)) return "flyway";
|
|
172
|
+
return "efcore";
|
|
162
173
|
case "java":
|
|
163
174
|
case "kotlin":
|
|
164
175
|
return "flyway";
|
|
@@ -182,9 +193,11 @@ export function toolForLanguage(language: SchemaMigrationLanguage): SchemaMigrat
|
|
|
182
193
|
export function listSchemaMigrations(args: ListSchemaMigrationsArgs = {}): SchemaMigrationFile[] {
|
|
183
194
|
const projectDir = args.projectDir ?? process.cwd();
|
|
184
195
|
const language = args.language ?? detectLanguage(projectDir);
|
|
185
|
-
const tool = toolForLanguage(language);
|
|
196
|
+
const tool = toolForLanguage(language, projectDir);
|
|
186
197
|
|
|
187
198
|
switch (tool) {
|
|
199
|
+
case "efcore":
|
|
200
|
+
return listEfCoreFiles(projectDir);
|
|
188
201
|
case "flyway":
|
|
189
202
|
return listFlywayMigrations(projectDir);
|
|
190
203
|
case "alembic":
|
|
@@ -195,8 +208,9 @@ export function listSchemaMigrations(args: ListSchemaMigrationsArgs = {}): Schem
|
|
|
195
208
|
}
|
|
196
209
|
|
|
197
210
|
function listFlywayMigrations(projectDir: string): SchemaMigrationFile[] {
|
|
198
|
-
// Flyway convention:
|
|
199
|
-
|
|
211
|
+
// Flyway convention: V<n>__<desc>.sql under the Maven layout (Java/Kotlin)
|
|
212
|
+
// or db/migrations/ (.NET); see flywayMigrationsDir.
|
|
213
|
+
const dir = flywayMigrationsDir(projectDir);
|
|
200
214
|
if (!fs.existsSync(dir)) return [];
|
|
201
215
|
const files = fs.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
|
|
202
216
|
return files
|
|
@@ -291,7 +305,7 @@ async function dsnFor(args: {
|
|
|
291
305
|
/** Resolve an adapter, honoring an explicit language override. */
|
|
292
306
|
function adapterFor(projectDir: string, language?: SchemaMigrationLanguage) {
|
|
293
307
|
const override: SchemaMigrationAdapterId | undefined = language
|
|
294
|
-
? toolForLanguage(language)
|
|
308
|
+
? toolForLanguage(language, projectDir)
|
|
295
309
|
: undefined;
|
|
296
310
|
return resolveSchemaMigrationAdapter(projectDir, override);
|
|
297
311
|
}
|
|
@@ -143,6 +143,18 @@ jobs:
|
|
|
143
143
|
fi
|
|
144
144
|
npm install
|
|
145
145
|
|
|
146
|
+
- name: Set up .NET
|
|
147
|
+
if: steps.detect-lang.outputs.lang == 'dotnet'
|
|
148
|
+
uses: actions/setup-dotnet@v4
|
|
149
|
+
with:
|
|
150
|
+
global-json-file: global.json
|
|
151
|
+
|
|
152
|
+
- name: Restore .NET packages and tools
|
|
153
|
+
if: steps.detect-lang.outputs.lang == 'dotnet'
|
|
154
|
+
run: |
|
|
155
|
+
dotnet restore
|
|
156
|
+
if [ -f .config/dotnet-tools.json ]; then dotnet tool restore; fi
|
|
157
|
+
|
|
146
158
|
# The official action installs to a user-writable path (no sudo). It's
|
|
147
159
|
# a no-op if a compatible databricks CLI is already on PATH.
|
|
148
160
|
- name: Install Databricks CLI
|
|
@@ -218,7 +230,7 @@ jobs:
|
|
|
218
230
|
# 3. Default https://repo1.maven.org/maven2 for GitHub-hosted
|
|
219
231
|
# runners with public internet.
|
|
220
232
|
- name: Install Flyway CLI
|
|
221
|
-
if: hashFiles('pom.xml') != ''
|
|
233
|
+
if: (hashFiles('pom.xml') != '' || hashFiles('db/migrations/**') != '')
|
|
222
234
|
env:
|
|
223
235
|
FLYWAY_DOWNLOAD_BASE_URL: ${{ vars.FLYWAY_DOWNLOAD_BASE_URL }}
|
|
224
236
|
run: |
|
|
@@ -102,6 +102,18 @@ jobs:
|
|
|
102
102
|
fi
|
|
103
103
|
npm install
|
|
104
104
|
|
|
105
|
+
- name: Set up .NET
|
|
106
|
+
if: steps.detect-lang.outputs.lang == 'dotnet'
|
|
107
|
+
uses: actions/setup-dotnet@v4
|
|
108
|
+
with:
|
|
109
|
+
global-json-file: global.json
|
|
110
|
+
|
|
111
|
+
- name: Restore .NET packages and tools
|
|
112
|
+
if: steps.detect-lang.outputs.lang == 'dotnet'
|
|
113
|
+
run: |
|
|
114
|
+
dotnet restore
|
|
115
|
+
if [ -f .config/dotnet-tools.json ]; then dotnet tool restore; fi
|
|
116
|
+
|
|
105
117
|
# Install frontend dependencies when a `client/` workspace is present
|
|
106
118
|
# (Python+React layouts etc.). Gated on client/package.json so projects
|
|
107
119
|
# without a frontend skip this transparently.
|
|
@@ -301,10 +313,12 @@ jobs:
|
|
|
301
313
|
BODY="⚠️ **No Lakebase CI branch** was created. This run is not using a dedicated database branch. Open the [workflow run](${RUN_URL}), expand **Create CI database branch (Lakebase)** and check the step **Summary** (or log) for the reason and how to fix it."
|
|
302
314
|
gh pr comment "$PR" --body "$BODY" 2>/dev/null || true
|
|
303
315
|
|
|
304
|
-
# Install Flyway CLI for Java/Kotlin projects
|
|
305
|
-
# migrate runner spawns the
|
|
306
|
-
# projects don't need it. Runtime-gated
|
|
307
|
-
#
|
|
316
|
+
# Install Flyway CLI for Java/Kotlin projects and .NET projects that use
|
|
317
|
+
# Flyway (db/migrations/). The substrate's migrate runner spawns the
|
|
318
|
+
# standalone `flyway` binary; other projects don't need it. Runtime-gated
|
|
319
|
+
# on pom.xml / any file under db/migrations/ (what the adapter checks; a
|
|
320
|
+
# fresh scaffold has only its README there) so the YAML is one shape for
|
|
321
|
+
# every language.
|
|
308
322
|
#
|
|
309
323
|
# Resolution order:
|
|
310
324
|
# 1. `flyway` already on PATH (self-hosted runner with brew /
|
|
@@ -315,7 +329,7 @@ jobs:
|
|
|
315
329
|
# 3. Default https://repo1.maven.org/maven2 for GitHub-hosted
|
|
316
330
|
# runners with public internet.
|
|
317
331
|
- name: Install Flyway CLI
|
|
318
|
-
if: steps.lakebase-db.outputs.url != '' && hashFiles('pom.xml') != ''
|
|
332
|
+
if: steps.lakebase-db.outputs.url != '' && (hashFiles('pom.xml') != '' || hashFiles('db/migrations/**') != '')
|
|
319
333
|
env:
|
|
320
334
|
FLYWAY_DOWNLOAD_BASE_URL: ${{ vars.FLYWAY_DOWNLOAD_BASE_URL }}
|
|
321
335
|
run: |
|
|
@@ -388,6 +402,8 @@ jobs:
|
|
|
388
402
|
uv run pytest
|
|
389
403
|
elif [ "$LANG" = "nodejs" ]; then
|
|
390
404
|
npm test
|
|
405
|
+
elif [ "$LANG" = "dotnet" ]; then
|
|
406
|
+
dotnet test --no-restore
|
|
391
407
|
fi
|
|
392
408
|
else
|
|
393
409
|
echo "::error::No CI branch URL – cannot run tests without a database. Check the 'Create CI database branch' step for details."
|
|
@@ -570,6 +586,10 @@ jobs:
|
|
|
570
586
|
desc=$(echo "$base" | sed 's/^[^_]*_//' | sed 's/\.py$//' | tr '_' ' ')
|
|
571
587
|
[ -n "$rev" ] && echo "| $rev | $desc |" >> "$MD"
|
|
572
588
|
done
|
|
589
|
+
elif [ "$LANG" = "dotnet" ]; then
|
|
590
|
+
# EF Core or Flyway: the kit's canonical discovery picks the tool + files.
|
|
591
|
+
npx --yes --package="${SCM_UTILS_NPX_PKG}" lakebase-schema-migrate list \
|
|
592
|
+
| jq -r '.[] | if .tool == "flyway" then "| V\(.version) | \(.description) |" else "| \(.version) | \(.description) (EF Core) |" end' >> "$MD"
|
|
573
593
|
elif [ "$LANG" = "nodejs" ]; then
|
|
574
594
|
for f in migrations/*.js; do
|
|
575
595
|
[ -f "$f" ] || continue
|
|
@@ -66,10 +66,63 @@ elif [ -f "$REPO_ROOT/requirements.txt" ] || [ -f "$REPO_ROOT/pyproject.toml" ];
|
|
|
66
66
|
source .venv/bin/activate
|
|
67
67
|
fi
|
|
68
68
|
alembic upgrade head "$@"
|
|
69
|
+
elif [ -n "$(find "$REPO_ROOT" -maxdepth 1 \( -name '*.sln' -o -name '*.slnx' -o -name '*.csproj' \) -print -quit 2>/dev/null)" ]; then
|
|
70
|
+
# .NET: EF Core or Flyway (db/migrations/).
|
|
71
|
+
if [ -n "${DATABASE_URL:-}" ]; then
|
|
72
|
+
# Explicit target (CI secret, ephemeral-verify DSN): run the tool directly.
|
|
73
|
+
if [ -d "$REPO_ROOT/db/migrations" ]; then
|
|
74
|
+
_np="${DATABASE_URL#postgresql://}"; _cr="${_np%%@*}"; _hp="${_np#*@}"
|
|
75
|
+
# Decode %XX only ('+' is literal in URL userinfo, and backslashes in a
|
|
76
|
+
# credential must not be interpreted as escapes).
|
|
77
|
+
_urldecode() {
|
|
78
|
+
local s="$1" out="" c
|
|
79
|
+
while [ -n "$s" ]; do
|
|
80
|
+
c="${s:0:1}"; s="${s:1}"
|
|
81
|
+
if [ "$c" = "%" ] && [ "${#s}" -ge 2 ]; then
|
|
82
|
+
out+="$(printf "\\x${s:0:2}")"; s="${s:2}"
|
|
83
|
+
else
|
|
84
|
+
out+="$c"
|
|
85
|
+
fi
|
|
86
|
+
done
|
|
87
|
+
printf '%s' "$out"
|
|
88
|
+
}
|
|
89
|
+
FLYWAY_URL="jdbc:postgresql://${_hp}" \
|
|
90
|
+
FLYWAY_USER="$(_urldecode "${_cr%%:*}")" \
|
|
91
|
+
FLYWAY_PASSWORD="$(_urldecode "${_cr#*:}")" \
|
|
92
|
+
flyway "-locations=filesystem:$REPO_ROOT/db/migrations" \
|
|
93
|
+
-baselineOnMigrate=true -baselineVersion=0 migrate "$@"
|
|
94
|
+
else
|
|
95
|
+
# Relative to the repo root (the cwd here): an absolute path through a
|
|
96
|
+
# symlinked directory (e.g. macOS /tmp -> /private/tmp) makes MSBuild see
|
|
97
|
+
# two different project paths and dotnet ef then loses the build output.
|
|
98
|
+
_csproj="$(grep -l "Microsoft.EntityFrameworkCore.Design" \
|
|
99
|
+
$(find . -maxdepth 3 -name '*.csproj' -not -path '*/tests/*' -not -path '*/test/*' \
|
|
100
|
+
-not -path '*/client/*' -not -path '*/bin/*' -not -path '*/obj/*' -not -path '*/node_modules/*' | sort) \
|
|
101
|
+
2>/dev/null | head -1)"
|
|
102
|
+
[ -n "$_csproj" ] || { echo "No *.csproj references Microsoft.EntityFrameworkCore.Design." >&2; exit 1; }
|
|
103
|
+
# dotnet ef reads project metadata before it builds, so restore first
|
|
104
|
+
# (a fresh clone or a cleaned obj/ has no assets file).
|
|
105
|
+
if [ -f .config/dotnet-tools.json ]; then dotnet tool restore >/dev/null; fi
|
|
106
|
+
dotnet restore "$_csproj" >/dev/null
|
|
107
|
+
# The design-time DbContext factory reads DATABASE_URL, so no password
|
|
108
|
+
# is passed on the command line.
|
|
109
|
+
dotnet ef database update --project "$_csproj" "$@"
|
|
110
|
+
fi
|
|
111
|
+
else
|
|
112
|
+
# Paired branch from .env metadata: the kit's tool-agnostic migrate CLI
|
|
113
|
+
# picks the tool, mints a fresh credential, and refuses protected tiers,
|
|
114
|
+
# exactly as CI does.
|
|
115
|
+
if [ ! -x "$SCRIPT_DIR/lk" ] || [ -z "${LAKEBASE_PROJECT_ID:-}" ] || [ -z "${LAKEBASE_BRANCH_ID:-}" ]; then
|
|
116
|
+
echo "Cannot migrate: need scripts/lk plus LAKEBASE_PROJECT_ID and LAKEBASE_BRANCH_ID (written to .env by the post-checkout hook), or DATABASE_URL." >&2
|
|
117
|
+
exit 1
|
|
118
|
+
fi
|
|
119
|
+
"$SCRIPT_DIR/lk" lakebase-schema-migrate apply \
|
|
120
|
+
--instance "$LAKEBASE_PROJECT_ID" --branch "$LAKEBASE_BRANCH_ID" "$@"
|
|
121
|
+
fi
|
|
69
122
|
elif [ -f "$REPO_ROOT/package.json" ]; then
|
|
70
123
|
# Node.js / Knex
|
|
71
124
|
npx knex migrate:latest "$@"
|
|
72
125
|
else
|
|
73
|
-
echo "Could not detect project language. Expected pom.xml (Java), pyproject.toml/requirements.txt (Python), or package.json (Node.js)."
|
|
126
|
+
echo "Could not detect project language. Expected pom.xml (Java), pyproject.toml/requirements.txt (Python), *.sln/*.csproj (.NET), or package.json (Node.js)."
|
|
74
127
|
exit 1
|
|
75
128
|
fi
|
|
@@ -107,6 +107,11 @@ if [ -d src/main/resources/db/migration ]; then
|
|
|
107
107
|
desc="$(echo "$base" | sed -n 's/^V[0-9.]*__\(.*\)\.sql$/\1/p' | tr '_' ' ')"
|
|
108
108
|
[ -n "$ver" ] && echo "| V$ver | $desc |" >> "$MD"
|
|
109
109
|
done
|
|
110
|
+
elif [ -n "$(find . -maxdepth 1 \( -name '*.sln' -o -name '*.slnx' -o -name '*.csproj' \) -print -quit 2>/dev/null)" ] \
|
|
111
|
+
&& [ -x "$WORK_TREE/scripts/lk" ]; then
|
|
112
|
+
# .NET (EF Core or Flyway): the kit's canonical discovery picks the tool + files.
|
|
113
|
+
"$WORK_TREE/scripts/lk" lakebase-schema-migrate list 2>/dev/null \
|
|
114
|
+
| jq -r '.[] | if .tool == "flyway" then "| V\(.version) | \(.description) |" else "| \(.version) | \(.description) (EF Core) |" end' >> "$MD" || true
|
|
110
115
|
elif [ -d alembic/versions ]; then
|
|
111
116
|
# Alembic / Python
|
|
112
117
|
for f in alembic/versions/*.py; do
|
|
@@ -209,6 +209,15 @@ for r in getattr(app, 'routes', []):
|
|
|
209
209
|
fi
|
|
210
210
|
|
|
211
211
|
uv run uvicorn app.main:app --reload --host "$HOST" --port "$PORT" "$@"
|
|
212
|
+
elif [ -n "$(find "$REPO_ROOT" -maxdepth 1 \( -name '*.sln' -o -name '*.slnx' -o -name '*.csproj' \) -print -quit 2>/dev/null)" ]; then
|
|
213
|
+
# .NET / ASP.NET Core. The app reads .env itself and mints its own credential.
|
|
214
|
+
PORT="$(resolve_port 8000)"
|
|
215
|
+
export PORT HOST
|
|
216
|
+
# Relative paths (cwd is the repo root): see the symlink note in flyway-migrate.sh.
|
|
217
|
+
_app="$(find src -maxdepth 2 -name '*.csproj' 2>/dev/null | head -1)"
|
|
218
|
+
_app="${_app:-$(find . -maxdepth 1 -name '*.csproj' 2>/dev/null | head -1)}"
|
|
219
|
+
echo "Serving on http://${HOST}:${PORT} (Ctrl-C to stop). Open it in your browser."
|
|
220
|
+
dotnet watch --project "$_app" run -- --urls "http://${HOST}:${PORT}" "$@"
|
|
212
221
|
elif [ -f "$REPO_ROOT/package.json" ]; then
|
|
213
222
|
# Node.js – prefer a "dev" script, fall back to "start".
|
|
214
223
|
PORT="$(resolve_port 8000)"
|
|
@@ -220,6 +229,6 @@ elif [ -f "$REPO_ROOT/package.json" ]; then
|
|
|
220
229
|
npm start -- "$@"
|
|
221
230
|
fi
|
|
222
231
|
else
|
|
223
|
-
echo "Could not detect project language. Expected pom.xml (Java), pyproject.toml/requirements.txt (Python), or package.json (Node.js)."
|
|
232
|
+
echo "Could not detect project language. Expected pom.xml (Java), pyproject.toml/requirements.txt (Python), *.sln/*.csproj (.NET), or package.json (Node.js)."
|
|
224
233
|
exit 1
|
|
225
234
|
fi
|
|
@@ -140,13 +140,18 @@ elif [ -f "$REPO_ROOT/requirements.txt" ] || [ -f "$REPO_ROOT/pyproject.toml" ];
|
|
|
140
140
|
else
|
|
141
141
|
uv run --extra dev pytest "$@"
|
|
142
142
|
fi
|
|
143
|
+
elif [ -n "$(find "$REPO_ROOT" -maxdepth 1 \( -name '*.sln' -o -name '*.slnx' -o -name '*.csproj' \) -print -quit 2>/dev/null)" ]; then
|
|
144
|
+
# .NET / EF Core or Flyway + xUnit
|
|
145
|
+
echo "Running migrations..."
|
|
146
|
+
"$REPO_ROOT/scripts/flyway-migrate.sh"
|
|
147
|
+
dotnet test "$@"
|
|
143
148
|
elif [ -f "$REPO_ROOT/package.json" ]; then
|
|
144
149
|
# Node.js / Knex + Jest
|
|
145
150
|
echo "Running Knex migrations..."
|
|
146
151
|
npx knex migrate:latest
|
|
147
152
|
npm test "$@"
|
|
148
153
|
else
|
|
149
|
-
echo "Could not detect project language. Expected pom.xml (Java), pyproject.toml/requirements.txt (Python), or package.json (Node.js)."
|
|
154
|
+
echo "Could not detect project language. Expected pom.xml (Java), pyproject.toml/requirements.txt (Python), *.sln/*.csproj (.NET), or package.json (Node.js)."
|
|
150
155
|
exit 1
|
|
151
156
|
fi
|
|
152
157
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
3
|
+
# Visual Studio Version 17
|
|
4
|
+
VisualStudioVersion = 17.0.31903.59
|
|
5
|
+
MinimumVisualStudioVersion = 10.0.40219.1
|
|
6
|
+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
|
|
7
|
+
EndProject
|
|
8
|
+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}"
|
|
9
|
+
EndProject
|
|
10
|
+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}"
|
|
11
|
+
EndProject
|
|
12
|
+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App.Tests", "tests\App.Tests\App.Tests.csproj", "{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}"
|
|
13
|
+
EndProject
|
|
14
|
+
Global
|
|
15
|
+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
16
|
+
Debug|Any CPU = Debug|Any CPU
|
|
17
|
+
Debug|x64 = Debug|x64
|
|
18
|
+
Debug|x86 = Debug|x86
|
|
19
|
+
Release|Any CPU = Release|Any CPU
|
|
20
|
+
Release|x64 = Release|x64
|
|
21
|
+
Release|x86 = Release|x86
|
|
22
|
+
EndGlobalSection
|
|
23
|
+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
24
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
25
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
26
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
27
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Debug|x64.Build.0 = Debug|Any CPU
|
|
28
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
29
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Debug|x86.Build.0 = Debug|Any CPU
|
|
30
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
31
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
32
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Release|x64.ActiveCfg = Release|Any CPU
|
|
33
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Release|x64.Build.0 = Release|Any CPU
|
|
34
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Release|x86.ActiveCfg = Release|Any CPU
|
|
35
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2}.Release|x86.Build.0 = Release|Any CPU
|
|
36
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
37
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
38
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
39
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Debug|x64.Build.0 = Debug|Any CPU
|
|
40
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
41
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Debug|x86.Build.0 = Debug|Any CPU
|
|
42
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
43
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
44
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Release|x64.ActiveCfg = Release|Any CPU
|
|
45
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Release|x64.Build.0 = Release|Any CPU
|
|
46
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Release|x86.ActiveCfg = Release|Any CPU
|
|
47
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E}.Release|x86.Build.0 = Release|Any CPU
|
|
48
|
+
EndGlobalSection
|
|
49
|
+
GlobalSection(SolutionProperties) = preSolution
|
|
50
|
+
HideSolutionNode = FALSE
|
|
51
|
+
EndGlobalSection
|
|
52
|
+
GlobalSection(NestedProjects) = preSolution
|
|
53
|
+
{DCBDD7E2-BB16-483D-92E7-913AB5681AA2} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
|
54
|
+
{3E88FEDA-D8D3-4939-BD9C-CFDD1EEBBC1E} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
|
|
55
|
+
EndGlobalSection
|
|
56
|
+
EndGlobal
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
using Microsoft.EntityFrameworkCore;
|
|
2
|
+
|
|
3
|
+
namespace App.Data;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// Application DbContext. Add DbSet<TEntity> properties for your tables.
|
|
7
|
+
/// Schema changes go through migrations (see the project README), never
|
|
8
|
+
/// EnsureCreated().
|
|
9
|
+
/// </summary>
|
|
10
|
+
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
|
|
11
|
+
{
|
|
12
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
namespace App.Lakebase;
|
|
2
|
+
|
|
3
|
+
/// <summary>
|
|
4
|
+
/// Minimal .env loader (KEY=VALUE lines, # comments, optional quotes). Never
|
|
5
|
+
/// overwrites variables already set in the process environment.
|
|
6
|
+
/// </summary>
|
|
7
|
+
public static class DotEnv
|
|
8
|
+
{
|
|
9
|
+
public static void LoadFromRepoRoot()
|
|
10
|
+
{
|
|
11
|
+
foreach (var start in new[] { Directory.GetCurrentDirectory(), AppContext.BaseDirectory })
|
|
12
|
+
{
|
|
13
|
+
for (var dir = new DirectoryInfo(start); dir is not null; dir = dir.Parent)
|
|
14
|
+
{
|
|
15
|
+
var candidate = Path.Combine(dir.FullName, ".env");
|
|
16
|
+
if (File.Exists(candidate))
|
|
17
|
+
{
|
|
18
|
+
Load(candidate);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static void Load(string path)
|
|
26
|
+
{
|
|
27
|
+
foreach (var raw in File.ReadAllLines(path))
|
|
28
|
+
{
|
|
29
|
+
var line = raw.Trim();
|
|
30
|
+
if (line.Length == 0 || line.StartsWith('#'))
|
|
31
|
+
continue;
|
|
32
|
+
if (line.StartsWith("export ", StringComparison.Ordinal))
|
|
33
|
+
line = line[7..].TrimStart();
|
|
34
|
+
|
|
35
|
+
var eq = line.IndexOf('=');
|
|
36
|
+
if (eq <= 0)
|
|
37
|
+
continue;
|
|
38
|
+
|
|
39
|
+
var key = line[..eq].Trim();
|
|
40
|
+
var value = line[(eq + 1)..].Trim();
|
|
41
|
+
if (value.Length >= 2 && (value[0] == '"' || value[0] == '\'') && value[^1] == value[0])
|
|
42
|
+
value = value[1..^1];
|
|
43
|
+
|
|
44
|
+
if (Environment.GetEnvironmentVariable(key) is null)
|
|
45
|
+
Environment.SetEnvironmentVariable(key, value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|