File size: 4,239 Bytes
da819ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
 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);
})();