TransHub_backend / create-release-bundle.js
linguabot's picture
Upload folder using huggingface_hub
da819ac verified
/*
Creates a complete release bundle for fast restore:
- Tags frontend and backend repos with an annotated tag
- Copies code snapshots (tar.gz) for frontend and backend
- Dumps MongoDB collections to JSON (users, sourcetexts, submissions, subtitles, subtitlesubmissions)
- Writes a manifest.json with commit SHAs, tag, counts, and timestamps
Usage: node create-release-bundle.js [--tag TAG_NAME]
Requires: MONGODB_URI env (or falls back to local), git available
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const mongoose = require('mongoose');
const ROOT = path.resolve(__dirname, '..', '..');
const BACKEND_DIR = path.resolve(__dirname);
const FRONTEND_DIR = path.resolve(__dirname, '../frontend');
const BACKUPS_DIR = path.join(BACKEND_DIR, 'backups');
const RELEASES_DIR = path.join(BACKUPS_DIR, 'releases');
const argTag = process.argv.includes('--tag') ? process.argv[process.argv.indexOf('--tag') + 1] : null;
const ts = new Date().toISOString().replace(/[:.]/g, '-');
const tagName = argTag || `prod-${ts}`;
function ensureDir(p) {
fs.mkdirSync(p, { recursive: true });
}
function getGitInfo(repoDir) {
const sha = execSync('git rev-parse HEAD', { cwd: repoDir }).toString().trim();
const branch = execSync('git rev-parse --abbrev-ref HEAD', { cwd: repoDir }).toString().trim();
return { sha, branch };
}
function tagAndPush(repoDir, tag) {
try {
execSync(`git tag -a ${tag} -m "Release ${tag}"`, { cwd: repoDir, stdio: 'inherit' });
} catch (e) {
// if tag exists, continue
}
// Prefer pushing to 'huggingface' remote if present, else default
try {
const remotes = execSync('git remote', { cwd: repoDir }).toString().split('\n').map(r => r.trim()).filter(Boolean);
if (remotes.includes('huggingface')) {
execSync('git push --tags huggingface', { cwd: repoDir, stdio: 'inherit' });
} else {
execSync('git push --tags', { cwd: repoDir, stdio: 'inherit' });
}
} catch (e) {
console.warn('⚠️ Warning: failed to push tags for', repoDir, '- continuing');
}
}
async function dumpCollections(outDir) {
const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/transcreation-sandbox';
await mongoose.connect(uri, { serverSelectionTimeoutMS: 5000 });
const conn = mongoose.connection;
const collections = ['users', 'sourcetexts', 'submissions', 'subtitles', 'subtitlesubmissions'];
const counts = {};
for (const name of collections) {
try {
const docs = await conn.db.collection(name).find({}).toArray();
fs.writeFileSync(path.join(outDir, `${name}.json`), JSON.stringify(docs, null, 2));
counts[name] = docs.length;
} catch (e) {
counts[name] = 0;
}
}
await mongoose.disconnect();
return counts;
}
(async () => {
console.log('πŸ“¦ Creating release bundle...');
ensureDir(RELEASES_DIR);
const bundleDir = path.join(RELEASES_DIR, `release-${ts}`);
ensureDir(bundleDir);
// Git info and tags
console.log('πŸ”– Tagging repositories...');
const feInfo = getGitInfo(FRONTEND_DIR);
const beInfo = getGitInfo(BACKEND_DIR);
tagAndPush(FRONTEND_DIR, tagName);
tagAndPush(BACKEND_DIR, tagName);
// Code archives
console.log('πŸ—œοΈ Archiving code...');
const feTar = path.join(bundleDir, `frontend-${feInfo.sha.slice(0,7)}.tar.gz`);
const beTar = path.join(bundleDir, `backend-${beInfo.sha.slice(0,7)}.tar.gz`);
execSync(`tar -czf "${feTar}" -C "${FRONTEND_DIR}" .`);
execSync(`tar -czf "${beTar}" -C "${BACKEND_DIR}" .`);
// DB dump
console.log('πŸ’Ύ Dumping database...');
const dbDir = path.join(bundleDir, 'db');
ensureDir(dbDir);
const counts = await dumpCollections(dbDir);
// Manifest
const manifest = {
createdAt: new Date().toISOString(),
tag: tagName,
frontend: feInfo,
backend: beInfo,
archives: {
frontend: path.basename(feTar),
backend: path.basename(beTar)
},
db: {
path: 'db',
counts
}
};
fs.writeFileSync(path.join(bundleDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
console.log('\nπŸŽ‰ Release bundle created');
console.log('πŸ“ Location:', bundleDir);
console.log('πŸ”– Tag:', tagName);
})();