103 lines
3.2 KiB
TypeScript
Executable file
103 lines
3.2 KiB
TypeScript
Executable file
#!/usr/bin/env tsx
|
|
/**
|
|
* Generate database schema snapshots for all features
|
|
*
|
|
* Usage:
|
|
* bun run db:snapshot:all
|
|
*
|
|
* Generates snapshots for all features with databases configured in services.yaml
|
|
*/
|
|
|
|
import { join } from 'node:path';
|
|
import { readdir } from 'node:fs/promises';
|
|
import { existsSync } from 'node:fs';
|
|
import { exec } from 'node:child_process';
|
|
import { promisify } from 'node:util';
|
|
import { homedir } from 'node:os';
|
|
import { PATHS } from '../../configs/paths';
|
|
|
|
const execAsync = promisify(exec);
|
|
|
|
// Bun binary location (for spawned processes)
|
|
const BUN_BIN_DIR = join(homedir(), '.bun/bin');
|
|
const PATH_WITH_BUN = `${BUN_BIN_DIR}:${process.env.PATH}`;
|
|
|
|
async function main() {
|
|
const featuresDir = PATHS.features;
|
|
|
|
// Get all features
|
|
const features = await readdir(featuresDir, { withFileTypes: true });
|
|
const featureNames = features
|
|
.filter((dirent) => dirent.isDirectory())
|
|
.map((dirent) => dirent.name);
|
|
|
|
// Filter features with databases
|
|
const featuresWithDbs: string[] = [];
|
|
|
|
for (const featureName of featureNames) {
|
|
const servicesConfigPath = join(featuresDir, featureName, 'services.yaml');
|
|
const dockerComposePath = join(featuresDir, featureName, 'docker-compose.yml');
|
|
|
|
// Feature has database if it has docker-compose.yml or databases in services.yaml
|
|
if (existsSync(servicesConfigPath) || existsSync(dockerComposePath)) {
|
|
featuresWithDbs.push(featureName);
|
|
}
|
|
}
|
|
|
|
console.log(`📊 Found ${featuresWithDbs.length} features with databases:`);
|
|
featuresWithDbs.forEach((f) => console.log(` - ${f}`));
|
|
console.log('');
|
|
|
|
let successCount = 0;
|
|
let failCount = 0;
|
|
const failures: string[] = [];
|
|
|
|
// Generate snapshots sequentially (parallel might overwhelm system)
|
|
for (const featureName of featuresWithDbs) {
|
|
console.log(`🔄 Generating snapshot for: ${featureName}`);
|
|
|
|
try {
|
|
const { stdout, stderr } = await execAsync(`bun run db:snapshot ${featureName}`, {
|
|
cwd: process.cwd(),
|
|
env: { ...process.env, PATH: PATH_WITH_BUN },
|
|
});
|
|
|
|
if (stdout) console.log(stdout);
|
|
if (stderr && !stderr.includes('NOTICE')) console.warn(stderr);
|
|
|
|
successCount++;
|
|
} catch (error: unknown) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
console.error(` ❌ Failed: ${message}`);
|
|
if (error && typeof error === 'object') {
|
|
if ('stdout' in error && error.stdout) console.log(error.stdout);
|
|
if ('stderr' in error && error.stderr) console.error(error.stderr);
|
|
}
|
|
failCount++;
|
|
failures.push(featureName);
|
|
}
|
|
|
|
console.log('');
|
|
}
|
|
|
|
// Summary
|
|
console.log('================================================================================');
|
|
console.log('Summary');
|
|
console.log('================================================================================');
|
|
console.log(`✅ Success: ${successCount}/${featuresWithDbs.length}`);
|
|
if (failCount > 0) {
|
|
console.log(`❌ Failed: ${failCount}`);
|
|
console.log(' Features:');
|
|
failures.forEach((f) => console.log(` - ${f}`));
|
|
}
|
|
console.log('');
|
|
|
|
if (failCount > 0) {
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error('❌ Fatal error:', error);
|
|
process.exit(1);
|
|
});
|