85 lines
2.7 KiB
JavaScript
85 lines
2.7 KiB
JavaScript
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const projectRoot = path.resolve(__dirname, "..");
|
|
const sourceDir = path.join(projectRoot, "..", "servers", "fastapi", "alembic", "versions");
|
|
const targetDir = path.join(projectRoot, "servers", "fastapi", "alembic", "versions");
|
|
|
|
function listPythonMigrations(dirPath) {
|
|
return fs
|
|
.readdirSync(dirPath, { withFileTypes: true })
|
|
.filter((entry) => entry.isFile() && entry.name.endsWith(".py"))
|
|
.map((entry) => entry.name)
|
|
.sort();
|
|
}
|
|
|
|
function extractRevisionInfo(filePath) {
|
|
const content = fs.readFileSync(filePath, "utf8");
|
|
const revisionMatch = content.match(/revision:\s*str\s*=\s*['"]([^'"]+)['"]/);
|
|
const downRevisionMatch = content.match(
|
|
/down_revision:\s*[^=]*=\s*(None|['"][^'"]+['"])/
|
|
);
|
|
|
|
if (!revisionMatch) {
|
|
throw new Error(`Missing revision id in ${filePath}`);
|
|
}
|
|
if (!downRevisionMatch) {
|
|
throw new Error(`Missing down_revision in ${filePath}`);
|
|
}
|
|
|
|
const revision = revisionMatch[1];
|
|
const downRaw = downRevisionMatch[1];
|
|
const downRevision = downRaw === "None" ? null : downRaw.slice(1, -1);
|
|
return { revision, downRevision };
|
|
}
|
|
|
|
function validateSingleHead(dirPath, filenames) {
|
|
const revisions = new Map();
|
|
const downRevisions = new Set();
|
|
|
|
for (const filename of filenames) {
|
|
const filePath = path.join(dirPath, filename);
|
|
const { revision, downRevision } = extractRevisionInfo(filePath);
|
|
if (revisions.has(revision)) {
|
|
throw new Error(`Duplicate revision id ${revision} in ${filename}`);
|
|
}
|
|
revisions.set(revision, filename);
|
|
if (downRevision) {
|
|
downRevisions.add(downRevision);
|
|
}
|
|
}
|
|
|
|
const heads = [...revisions.keys()].filter((revision) => !downRevisions.has(revision));
|
|
if (heads.length !== 1) {
|
|
throw new Error(
|
|
`Expected exactly one Alembic head, found ${heads.length}: ${heads.join(", ")}`
|
|
);
|
|
}
|
|
}
|
|
|
|
function syncMigrations() {
|
|
if (!fs.existsSync(sourceDir)) {
|
|
throw new Error(`Source migrations directory not found: ${sourceDir}`);
|
|
}
|
|
if (!fs.existsSync(targetDir)) {
|
|
throw new Error(`Target migrations directory not found: ${targetDir}`);
|
|
}
|
|
|
|
const sourceFiles = listPythonMigrations(sourceDir);
|
|
if (sourceFiles.length === 0) {
|
|
throw new Error(`No migration files found in source directory: ${sourceDir}`);
|
|
}
|
|
|
|
for (const filename of sourceFiles) {
|
|
fs.copyFileSync(path.join(sourceDir, filename), path.join(targetDir, filename));
|
|
}
|
|
|
|
const targetFiles = listPythonMigrations(targetDir);
|
|
validateSingleHead(targetDir, targetFiles);
|
|
|
|
console.log(
|
|
`Synced ${sourceFiles.length} migration files into ${targetFiles.length} target migrations and verified a single Alembic head.`
|
|
);
|
|
}
|
|
|
|
syncMigrations();
|