platform-tooling/scripts/database/snapshot-all.ts
2026-03-02 21:06:53 -08:00

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);
});