import { spawnSync } from 'node:child_process'; import fs from 'node:fs'; import path from 'node:path'; import dotenv from 'dotenv'; dotenv.config(); const root = process.cwd(); const win = process.platform === 'win32'; const androidDir = path.join(root, 'android'); const run = (cmd, args, cwd = root) => { const r = spawnSync(cmd, args, { cwd, stdio: 'inherit', shell: win }); if (r.status !== 0) process.exit(r.status || 1); }; const token = process.env.GITLAB_TOKEN; if (!token) { console.error('GITLAB_TOKEN not found in environment or .env file.'); process.exit(1); } const projectPath = encodeURIComponent('vyla-entertainment/TV'); const gitlabApi = 'https://gitlab.com/api/v4'; const sdk = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT; const lp = path.join(androidDir, 'local.properties'); if (!fs.existsSync(lp)) { if (!sdk) { console.error('Set ANDROID_HOME environment variable.'); process.exit(1); } fs.writeFileSync(lp, 'sdk.dir=' + sdk.replace(/\\/g, '\\\\') + '\n'); } const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); const version = pkg.version || '1.0.0'; const tag = `v${version}`; run('node', ['scripts/build-android.mjs']); run(win ? 'gradlew.bat' : './gradlew', ['assembleRelease'], androidDir); const relDir = path.join(androidDir, 'app/build/outputs/apk/release'); const apkCandidates = [ path.join(relDir, 'app-release.apk'), path.join(relDir, 'app-release-unsigned.apk'), path.join(androidDir, 'app/build/outputs/apk/debug/app-debug.apk') ]; const sourceApk = apkCandidates.find(p => fs.existsSync(p)); if (!sourceApk) { console.error('Build succeeded but no output APK was found.'); process.exit(1); } const distDir = path.join(root, 'release'); fs.rmSync(distDir, { recursive: true, force: true }); fs.mkdirSync(distDir, { recursive: true }); const targetApkName = `Vyla-TV_${version}.apk`; const targetApk = path.join(distDir, targetApkName); fs.copyFileSync(sourceApk, targetApk); const manifest = { name: 'Vyla TV', version, package: targetApkName, releaseDate: new Date().toISOString() }; const manifestPath = path.join(distDir, 'manifest.json'); fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); const branch = spawnSync('git', ['branch', '--show-current'], { shell: win, encoding: 'utf8' }).stdout.trim() || 'main'; const commitSha = spawnSync('git', ['rev-parse', 'HEAD'], { shell: win, encoding: 'utf8' }).stdout.trim(); spawnSync('git', ['tag', '-fa', tag, '-m', `Release ${tag}`], { shell: win, stdio: 'inherit' }); spawnSync('git', ['push', 'origin', tag, '--force'], { shell: win, stdio: 'inherit' }); const uploadGenericPackage = async (filePath, fileName) => { const fileBytes = fs.readFileSync(filePath); const uploadUrl = `${gitlabApi}/projects/${projectPath}/packages/generic/vyla-tv/${version}/${fileName}`; const res = await fetch(uploadUrl, { method: 'PUT', headers: { 'PRIVATE-TOKEN': token, 'Content-Type': 'application/octet-stream' }, body: fileBytes }); if (!res.ok) { console.error(`Failed uploading ${fileName} to GitLab Package Registry:`, await res.text()); process.exit(1); } console.log(`Uploaded ${fileName} to GitLab Packages.`); return uploadUrl; }; const apkUrl = await uploadGenericPackage(targetApk, targetApkName); const manifestUrl = await uploadGenericPackage(manifestPath, 'manifest.json'); const releasePayload = { name: `Vyla TV Release ${tag}`, tag_name: tag, ref: commitSha || branch, description: `Automated Release ${tag}`, assets: { links: [ { name: targetApkName, url: apkUrl, link_type: 'package' }, { name: 'manifest.json', url: manifestUrl, link_type: 'other' } ] } }; const releaseRes = await fetch(`${gitlabApi}/projects/${projectPath}/releases`, { method: 'POST', headers: { 'PRIVATE-TOKEN': token, 'Content-Type': 'application/json' }, body: JSON.stringify(releasePayload) }); if (!releaseRes.ok) { console.error('Failed to create GitLab Release:', await releaseRes.text()); process.exit(1); } console.log(`\nSuccessfully released ${tag}: https://gitlab.com/vyla-entertainment/TV/-/releases/${tag}`);