forked from UKSOURCE/cms.hailearning.edu.vn
first commit
This commit is contained in:
204
scripts/migrate-all.js
Normal file
204
scripts/migrate-all.js
Normal file
@@ -0,0 +1,204 @@
|
||||
require("dotenv").config();
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const {execSync} = require("child_process");
|
||||
const connectDB = require("../config/database");
|
||||
const migrationHelper = require("../utils/migrationHelper");
|
||||
|
||||
/**
|
||||
* Tự động phát hiện tất cả các file script trong thư mục scripts
|
||||
* Loại trừ các file quản lý migration và file không phải .js
|
||||
*/
|
||||
function discoverMigrations() {
|
||||
const scriptsDir = __dirname;
|
||||
const files = fs.readdirSync(scriptsDir);
|
||||
|
||||
// Danh sách các file quản lý migration cần loại trừ
|
||||
const excludeFiles = [
|
||||
"migrate-all.js",
|
||||
"migrate-status.js",
|
||||
"migrate-rollback.js",
|
||||
"migrate-fresh.js",
|
||||
"make-migration.js",
|
||||
];
|
||||
|
||||
const migrations = files
|
||||
.filter((file) => {
|
||||
// Lấy tất cả file .js, trừ các file quản lý
|
||||
return file.endsWith(".js") && !excludeFiles.includes(file);
|
||||
})
|
||||
.map((file) => {
|
||||
// Tạo tên migration từ tên file (bỏ .js)
|
||||
const name = file.replace(".js", "");
|
||||
return {
|
||||
name: name,
|
||||
script: file,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sắp xếp theo tên để đảm bảo thứ tự nhất quán
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
return migrations;
|
||||
}
|
||||
|
||||
// Tự động phát hiện migrations
|
||||
const migrations = discoverMigrations();
|
||||
|
||||
/**
|
||||
* Chạy migration script (suppress output)
|
||||
* Sử dụng child_process để chạy script độc lập vì các script tự quản lý DB connection
|
||||
* Output từ script sẽ bị suppress để chỉ hiển thị status
|
||||
*/
|
||||
async function runMigrationScript(migration) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
// Chạy script bằng child_process với stdio: 'pipe' để suppress output
|
||||
// Nhưng vẫn capture stderr để có thể hiển thị lỗi nếu cần
|
||||
const result = execSync(`node scripts/${migration.script}`, {
|
||||
stdio: ["ignore", "pipe", "pipe"], // stdin: ignore, stdout: pipe, stderr: pipe
|
||||
cwd: path.join(__dirname, ".."),
|
||||
encoding: "utf8",
|
||||
});
|
||||
resolve();
|
||||
} catch (error) {
|
||||
// Attach stderr vào error để có thể hiển thị sau
|
||||
if (error.stderr) {
|
||||
error.stderr = error.stderr;
|
||||
}
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hàm chính để chạy tất cả migrations với tracking
|
||||
*/
|
||||
async function runAllMigrations() {
|
||||
const mongoose = require("mongoose");
|
||||
let ownConn = false;
|
||||
|
||||
try {
|
||||
const wasConnected = mongoose.connection.readyState === 1;
|
||||
await connectDB();
|
||||
if (!wasConnected) ownConn = true;
|
||||
|
||||
const batch = (await migrationHelper.getLastBatch()) + 1;
|
||||
const results = [];
|
||||
|
||||
// Kiểm tra và chạy từng migration
|
||||
for (let i = 0; i < migrations.length; i++) {
|
||||
const migration = migrations[i];
|
||||
|
||||
try {
|
||||
// Kiểm tra xem migration đã chạy chưa
|
||||
const hasRun = await migrationHelper.hasRun(migration.name);
|
||||
|
||||
if (hasRun) {
|
||||
results.push({name: migration.name, status: "SKIPPED"});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Chạy migration script (output bị suppress)
|
||||
await runMigrationScript(migration);
|
||||
|
||||
if (mongoose.connection.readyState !== 1) {
|
||||
await connectDB();
|
||||
}
|
||||
await migrationHelper.markAsRun(migration.name, batch);
|
||||
|
||||
results.push({name: migration.name, status: "DONE"});
|
||||
} catch (error) {
|
||||
results.push({
|
||||
name: migration.name,
|
||||
status: "FAIL",
|
||||
error: error.message,
|
||||
});
|
||||
// Hiển thị bảng kết quả trước khi exit
|
||||
displayResults(results);
|
||||
console.error(
|
||||
`\n❌ Migration "${migration.name}" failed: ${error.message}`
|
||||
);
|
||||
if (error.stderr) {
|
||||
console.error(error.stderr.toString());
|
||||
}
|
||||
if (ownConn && mongoose.connection.readyState === 1) {
|
||||
await mongoose.disconnect();
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Hiển thị bảng kết quả
|
||||
displayResults(results);
|
||||
|
||||
if (ownConn && mongoose.connection.readyState === 1) {
|
||||
await mongoose.disconnect();
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error("\n❌ Error:", error.message);
|
||||
if (ownConn && mongoose.connection.readyState === 1) {
|
||||
await mongoose.disconnect();
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hiển thị bảng kết quả migration đơn giản
|
||||
*/
|
||||
function displayResults(results) {
|
||||
console.log("\nRunning migrations...\n");
|
||||
|
||||
// Tìm độ dài tên migration dài nhất để format bảng
|
||||
const maxNameLength = Math.max(...results.map((r) => r.name.length), 20);
|
||||
const statusWidth = 10;
|
||||
const totalWidth = maxNameLength + statusWidth + 7; // 7 = spaces and separators
|
||||
|
||||
// Header
|
||||
console.log("=".repeat(totalWidth));
|
||||
console.log(
|
||||
`${"Migration".padEnd(maxNameLength)} | ${"Status".padEnd(statusWidth)}`
|
||||
);
|
||||
console.log("=".repeat(totalWidth));
|
||||
|
||||
// Rows
|
||||
results.forEach((result) => {
|
||||
let statusText = "";
|
||||
if (result.status === "DONE") {
|
||||
statusText = "DONE".padEnd(statusWidth);
|
||||
} else if (result.status === "SKIPPED") {
|
||||
statusText = "SKIPPED".padEnd(statusWidth);
|
||||
} else if (result.status === "FAIL") {
|
||||
statusText = "FAIL".padEnd(statusWidth);
|
||||
}
|
||||
|
||||
console.log(`${result.name.padEnd(maxNameLength)} | ${statusText}`);
|
||||
});
|
||||
|
||||
// Footer
|
||||
console.log("=".repeat(totalWidth));
|
||||
|
||||
// Summary
|
||||
const doneCount = results.filter((r) => r.status === "DONE").length;
|
||||
const skippedCount = results.filter((r) => r.status === "SKIPPED").length;
|
||||
const failCount = results.filter((r) => r.status === "FAIL").length;
|
||||
|
||||
console.log("");
|
||||
if (doneCount > 0) {
|
||||
console.log(`${doneCount} migration(s) completed`);
|
||||
}
|
||||
if (skippedCount > 0) {
|
||||
console.log(`${skippedCount} migration(s) skipped`);
|
||||
}
|
||||
if (failCount > 0) {
|
||||
console.log(`${failCount} migration(s) failed`);
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
// Chạy hàm chính
|
||||
runAllMigrations();
|
||||
Reference in New Issue
Block a user