#!/usr/bin/env node /* eslint-disable @typescript-eslint/no-var-requires, no-console, unused-imports/no-unused-vars */ /** * MoonTV 版本管理脚本 * 用于自动化版本号更新、CHANGELOG 生成和发布管理 */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); // 配置文件路径 const PACKAGE_JSON = path.join(__dirname, '../package.json'); const VERSION_TXT = path.join(__dirname, '../VERSION.txt'); const CHANGELOG_MD = path.join(__dirname, '../CHANGELOG.md'); const _README_MD = path.join(__dirname, '../README.md'); // 版本类型 const VERSION_TYPES = { MAJOR: 'major', // 主版本号 (x.0.0) MINOR: 'minor', // 次版本号 (0.x.0) PATCH: 'patch', // 修订版本号 (0.0.x) PRE: 'pre', // 预发布版本 BUILD: 'build' // 构建版本 }; // 颜色输出 const colors = { reset: '\x1b[0m', bright: '\x1b[1m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m' }; function log(message, color = 'reset') { console.log(`${colors[color]}${message}${colors.reset}`); } function error(message) { log(`❌ ${message}`, 'red'); process.exit(1); } function success(message) { log(`✅ ${message}`, 'green'); } function info(message) { log(`ℹ️ ${message}`, 'blue'); } function warning(message) { log(`⚠️ ${message}`, 'yellow'); } // 读取当前版本 function getCurrentVersion() { try { const packageJson = JSON.parse(fs.readFileSync(PACKAGE_JSON, 'utf8')); return packageJson.version; } catch (err) { error('无法读取 package.json 文件'); } } // 读取 VERSION.txt function getVersionTxt() { try { return fs.readFileSync(VERSION_TXT, 'utf8').trim(); } catch (err) { error('无法读取 VERSION.txt 文件'); } } // 更新版本号 function updateVersion(type, preRelease = null) { const currentVersion = getCurrentVersion(); const [major, minor, patch] = currentVersion.split('.').map(Number); let newVersion; let newVersionTxt; switch (type) { case VERSION_TYPES.MAJOR: newVersion = `${major + 1}.0.0`; break; case VERSION_TYPES.MINOR: newVersion = `${major}.${minor + 1}.0`; break; case VERSION_TYPES.PATCH: newVersion = `${major}.${minor}.${patch + 1}`; break; case VERSION_TYPES.PRE: if (!preRelease) { error('预发布版本需要指定标识符 (如: alpha, beta, rc)'); } newVersion = `${major}.${minor}.${patch + 1}-${preRelease}.1`; break; case VERSION_TYPES.BUILD: newVersion = `${major}.${minor}.${patch + 1}`; break; default: error(`不支持的版本类型: ${type}`); } // 生成新的版本时间戳 const now = new Date(); newVersionTxt = now.getFullYear().toString() + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0') + String(now.getHours()).padStart(2, '0') + String(now.getMinutes()).padStart(2, '0') + String(now.getSeconds()).padStart(2, '0'); return { newVersion, newVersionTxt }; } // 更新 package.json function updatePackageJson(newVersion) { try { const packageJson = JSON.parse(fs.readFileSync(PACKAGE_JSON, 'utf8')); packageJson.version = newVersion; fs.writeFileSync(PACKAGE_JSON, JSON.stringify(packageJson, null, 2) + '\n'); success(`package.json 版本已更新为 ${newVersion}`); } catch (err) { error(`更新 package.json 失败: ${err.message}`); } } // 更新 VERSION.txt function updateVersionTxt(newVersionTxt) { try { fs.writeFileSync(VERSION_TXT, newVersionTxt + '\n'); success(`VERSION.txt 已更新为 ${newVersionTxt}`); } catch (err) { error(`更新 VERSION.txt 失败: ${err.message}`); } } // 更新 CHANGELOG.md function updateChangelog(newVersion, type) { try { const changelog = fs.readFileSync(CHANGELOG_MD, 'utf8'); const today = new Date().toISOString().split('T')[0]; // 创建新版本条目 const newEntry = `## [${newVersion}] - ${today} ### ✨ 新功能 - 新增功能描述 ### 🐛 问题修复 - 修复问题描述 ### 🔧 改进 - 改进内容描述 ### 📝 文档更新 - 文档更新内容 ### 🚀 部署说明 #### Docker 部署 \`\`\`bash docker pull ghcr.io/senshinya/moontv:v${newVersion} docker run -d --name moontv -p 3000:3000 --env PASSWORD=your_password ghcr.io/senshinya/moontv:v${newVersion} \`\`\` #### 环境变量更新 请查看 [README.md](README.md) 了解最新的环境变量配置。 ### 📋 完整更新日志 查看 [CHANGELOG.md](CHANGELOG.md) 了解详细的更新历史。 ### 🔗 相关链接 - [项目主页](https://github.com/senshinya/moontv) - [在线演示](https://moontv.vercel.app) - [问题反馈](https://github.com/senshinya/moontv/issues) - [功能建议](https://github.com/senshinya/moontv/discussions) `; // 在未发布部分后插入新版本 const updatedChangelog = changelog.replace( '## [未发布]', `## [未发布]\n\n### 计划中\n- 弹幕系统支持\n- 字幕文件支持\n- 下载功能\n- 社交分享功能\n- 用户评分系统\n\n${newEntry}` ); fs.writeFileSync(CHANGELOG_MD, updatedChangelog); success('CHANGELOG.md 已更新'); } catch (err) { error(`更新 CHANGELOG.md 失败: ${err.message}`); } } // 创建 Git 标签 function createGitTag(version) { try { execSync(`git tag v${version}`, { stdio: 'inherit' }); success(`Git 标签 v${version} 已创建`); } catch (err) { warning(`创建 Git 标签失败: ${err.message}`); } } // 提交更改 function commitChanges(version) { try { execSync('git add .', { stdio: 'inherit' }); execSync(`git commit -m "chore: bump version to ${version}"`, { stdio: 'inherit' }); success('版本更改已提交到 Git'); } catch (err) { warning(`Git 提交失败: ${err.message}`); } } // 显示帮助信息 function showHelp() { console.log(` ${colors.bright}MoonTV 版本管理脚本${colors.reset} 用法: node scripts/version-manager.js <命令> [选项] 命令: ${colors.cyan}major${colors.reset} 增加主版本号 (x.0.0) ${colors.cyan}minor${colors.reset} 增加次版本号 (0.x.0) ${colors.cyan}patch${colors.reset} 增加修订版本号 (0.0.x) ${colors.cyan}pre <标识符>${colors.reset} 创建预发布版本 (如: alpha, beta, rc) ${colors.cyan}build${colors.reset} 增加构建版本号 ${colors.cyan}show${colors.reset} 显示当前版本信息 ${colors.cyan}help${colors.reset} 显示此帮助信息 选项: --no-commit 不自动提交 Git 更改 --no-tag 不自动创建 Git 标签 --no-changelog 不更新 CHANGELOG.md 示例: node scripts/version-manager.js patch node scripts/version-manager.js minor --no-commit node scripts/version-manager.js pre alpha node scripts/version-manager.js show 注意: 此脚本会自动更新以下文件: - package.json - VERSION.txt - CHANGELOG.md `); } // 显示当前版本信息 function showVersionInfo() { const packageVersion = getCurrentVersion(); const versionTxt = getVersionTxt(); console.log(` ${colors.bright}当前版本信息:${colors.reset} 📦 Package.json 版本: ${colors.green}${packageVersion}${colors.reset} 📅 VERSION.txt: ${colors.blue}${versionTxt}${colors.reset} 📋 版本类型: ${colors.yellow}${packageVersion.includes('-') ? '预发布版本' : '正式版本'}${colors.reset} 💡 使用 'node scripts/version-manager.js help' 查看所有可用命令 `); } // 主函数 function main() { const args = process.argv.slice(2); if (args.length === 0 || args.includes('help') || args.includes('--help') || args.includes('-h')) { showHelp(); return; } if (args.includes('show')) { showVersionInfo(); return; } const command = args[0]; const options = { noCommit: args.includes('--no-commit'), noTag: args.includes('--no-tag'), noChangelog: args.includes('--no-changelog') }; // 验证命令 if (!Object.values(VERSION_TYPES).includes(command)) { error(`无效的命令: ${command}`); } // 获取预发布标识符 let preRelease = null; if (command === VERSION_TYPES.PRE) { if (args.length < 2) { error('预发布版本需要指定标识符 (如: alpha, beta, rc)'); } preRelease = args[1]; } info(`开始更新版本...`); info(`当前版本: ${getCurrentVersion()}`); // 更新版本 const { newVersion, newVersionTxt } = updateVersion(command, preRelease); info(`新版本: ${newVersion}`); // 更新文件 updatePackageJson(newVersion); updateVersionTxt(newVersionTxt); if (!options.noChangelog) { updateChangelog(newVersion, command); } // Git 操作 if (!options.noCommit) { commitChanges(newVersion); } if (!options.noTag) { createGitTag(newVersion); } success(`\n🎉 版本更新完成!`); success(`新版本: ${newVersion}`); success(`时间戳: ${newVersionTxt}`); if (!options.noCommit) { info('提示: 使用 "git push --tags" 推送标签到远程仓库'); } } // 运行脚本 if (require.main === module) { main(); } module.exports = { VERSION_TYPES, getCurrentVersion, getVersionTxt, updateVersion, updatePackageJson, updateVersionTxt, updateChangelog };