mirror of https://github.com/djteang/OrangeTV.git
230 lines
6.3 KiB
JavaScript
230 lines
6.3 KiB
JavaScript
#!/usr/bin / env node
|
||
|
||
/* eslint-disable */
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
function parseChangelog(content) {
|
||
const lines = content.split('\n');
|
||
const versions = [];
|
||
let currentVersion = null;
|
||
let currentSection = null;
|
||
let inVersionContent = false;
|
||
|
||
for (const line of lines) {
|
||
const trimmedLine = line.trim();
|
||
|
||
// 匹配版本行: ## [X.Y.Z] - YYYY-MM-DD
|
||
const versionMatch = trimmedLine.match(
|
||
/^## \[([\d.]+)\] - (\d{4}-\d{2}-\d{2})$/
|
||
);
|
||
if (versionMatch) {
|
||
if (currentVersion) {
|
||
versions.push(currentVersion);
|
||
}
|
||
|
||
currentVersion = {
|
||
version: versionMatch[1],
|
||
date: versionMatch[2],
|
||
added: [],
|
||
changed: [],
|
||
fixed: [],
|
||
content: [], // 用于存储原始内容,当没有分类时使用
|
||
};
|
||
currentSection = null;
|
||
inVersionContent = true;
|
||
continue;
|
||
}
|
||
|
||
// 如果遇到下一个版本或到达文件末尾,停止处理当前版本
|
||
if (inVersionContent && currentVersion) {
|
||
// 匹配章节标题
|
||
if (trimmedLine === '### Added') {
|
||
currentSection = 'added';
|
||
continue;
|
||
} else if (trimmedLine === '### Changed') {
|
||
currentSection = 'changed';
|
||
continue;
|
||
} else if (trimmedLine === '### Fixed') {
|
||
currentSection = 'fixed';
|
||
continue;
|
||
}
|
||
|
||
// 匹配条目: - 内容
|
||
if (trimmedLine.startsWith('- ') && currentSection) {
|
||
const entry = trimmedLine.substring(2);
|
||
currentVersion[currentSection].push(entry);
|
||
} else if (
|
||
trimmedLine &&
|
||
!trimmedLine.startsWith('#') &&
|
||
!trimmedLine.startsWith('###')
|
||
) {
|
||
currentVersion.content.push(trimmedLine);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加最后一个版本
|
||
if (currentVersion) {
|
||
versions.push(currentVersion);
|
||
}
|
||
|
||
// 后处理:如果某个版本没有分类内容,但有 content,则将 content 放到 changed 中
|
||
versions.forEach((version) => {
|
||
const hasCategories =
|
||
version.added.length > 0 ||
|
||
version.changed.length > 0 ||
|
||
version.fixed.length > 0;
|
||
if (!hasCategories && version.content.length > 0) {
|
||
version.changed = version.content;
|
||
}
|
||
// 清理 content 字段
|
||
delete version.content;
|
||
});
|
||
|
||
return { versions };
|
||
}
|
||
|
||
function generateTypeScript(changelogData) {
|
||
const entries = changelogData.versions
|
||
.map((version) => {
|
||
const addedEntries = version.added
|
||
.map((entry) => ` "${entry}"`)
|
||
.join(',\n');
|
||
const changedEntries = version.changed
|
||
.map((entry) => ` "${entry}"`)
|
||
.join(',\n');
|
||
const fixedEntries = version.fixed
|
||
.map((entry) => ` "${entry}"`)
|
||
.join(',\n');
|
||
|
||
return ` {
|
||
version: "${version.version}",
|
||
date: "${version.date}",
|
||
added: [
|
||
${addedEntries || ' // 无新增内容'}
|
||
],
|
||
changed: [
|
||
${changedEntries || ' // 无变更内容'}
|
||
],
|
||
fixed: [
|
||
${fixedEntries || ' // 无修复内容'}
|
||
]
|
||
}`;
|
||
})
|
||
.join(',\n');
|
||
|
||
return `// 此文件由 scripts/convert-changelog.js 自动生成
|
||
// 请勿手动编辑
|
||
|
||
export interface ChangelogEntry {
|
||
version: string;
|
||
date: string;
|
||
added: string[];
|
||
changed: string[];
|
||
fixed: string[];
|
||
}
|
||
|
||
export const changelog: ChangelogEntry[] = [
|
||
${entries}
|
||
];
|
||
|
||
export default changelog;
|
||
`;
|
||
}
|
||
|
||
function updateVersionFile(version) {
|
||
const versionTxtPath = path.join(process.cwd(), 'VERSION.txt');
|
||
try {
|
||
fs.writeFileSync(versionTxtPath, version, 'utf8');
|
||
console.log(`✅ 已更新 VERSION.txt: ${version}`);
|
||
} catch (error) {
|
||
console.error(`❌ 无法更新 VERSION.txt:`, error.message);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
function updateVersionTs(version) {
|
||
const versionTsPath = path.join(process.cwd(), 'src/lib/version.ts');
|
||
try {
|
||
let content = fs.readFileSync(versionTsPath, 'utf8');
|
||
|
||
// 替换 CURRENT_VERSION 常量
|
||
const updatedContent = content.replace(
|
||
/const CURRENT_VERSION = ['"`][^'"`]+['"`];/,
|
||
`const CURRENT_VERSION = '${version}';`
|
||
);
|
||
|
||
fs.writeFileSync(versionTsPath, updatedContent, 'utf8');
|
||
console.log(`✅ 已更新 version.ts: ${version}`);
|
||
} catch (error) {
|
||
console.error(`❌ 无法更新 version.ts:`, error.message);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
function main() {
|
||
try {
|
||
const changelogPath = path.join(process.cwd(), 'CHANGELOG');
|
||
const outputPath = path.join(process.cwd(), 'src/lib/changelog.ts');
|
||
|
||
console.log('正在读取 CHANGELOG 文件...');
|
||
const changelogContent = fs.readFileSync(changelogPath, 'utf-8');
|
||
|
||
console.log('正在解析 CHANGELOG 内容...');
|
||
const changelogData = parseChangelog(changelogContent);
|
||
|
||
if (changelogData.versions.length === 0) {
|
||
console.error('❌ 未在 CHANGELOG 中找到任何版本');
|
||
process.exit(1);
|
||
}
|
||
|
||
// 获取最新版本号(CHANGELOG中的第一个版本)
|
||
const latestVersion = changelogData.versions[0].version;
|
||
console.log(`🔢 最新版本: ${latestVersion}`);
|
||
|
||
console.log('正在生成 TypeScript 文件...');
|
||
const tsContent = generateTypeScript(changelogData);
|
||
|
||
// 确保输出目录存在
|
||
const outputDir = path.dirname(outputPath);
|
||
if (!fs.existsSync(outputDir)) {
|
||
fs.mkdirSync(outputDir, { recursive: true });
|
||
}
|
||
|
||
fs.writeFileSync(outputPath, tsContent, 'utf-8');
|
||
|
||
// 检查是否在 GitHub Actions 环境中运行
|
||
const isGitHubActions = process.env.GITHUB_ACTIONS === 'true';
|
||
|
||
if (isGitHubActions) {
|
||
// 在 GitHub Actions 中,更新版本文件
|
||
console.log('正在更新版本文件...');
|
||
updateVersionFile(latestVersion);
|
||
updateVersionTs(latestVersion);
|
||
} else {
|
||
// 在本地运行时,只提示但不更新版本文件
|
||
console.log('🔧 本地运行模式:跳过版本文件更新');
|
||
console.log('💡 版本文件更新将在 git tag 触发的 release 工作流中完成');
|
||
}
|
||
|
||
console.log(`✅ 成功生成 ${outputPath}`);
|
||
console.log(`📊 版本统计:`);
|
||
changelogData.versions.forEach((version) => {
|
||
console.log(
|
||
` ${version.version} (${version.date}): +${version.added.length} ~${version.changed.length} !${version.fixed.length}`
|
||
);
|
||
});
|
||
|
||
console.log('\n🎉 转换完成!');
|
||
} catch (error) {
|
||
console.error('❌ 转换失败:', error);
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
if (require.main === module) {
|
||
main();
|
||
}
|