192 lines
5.8 KiB
JavaScript
192 lines
5.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const fs = require('fs')
|
|
const path = require('path')
|
|
const { execSync } = require('child_process')
|
|
|
|
const rootDir = path.resolve(__dirname, '..')
|
|
|
|
function readJson(relPath) {
|
|
return JSON.parse(fs.readFileSync(path.join(rootDir, relPath), 'utf8'))
|
|
}
|
|
|
|
function writeJson(relPath, data) {
|
|
fs.writeFileSync(path.join(rootDir, relPath), JSON.stringify(data, null, 2) + '\n')
|
|
}
|
|
|
|
function run(cmd, options = {}) {
|
|
execSync(cmd, { stdio: 'inherit', cwd: rootDir, ...options })
|
|
}
|
|
|
|
function runQuiet(cmd) {
|
|
return execSync(cmd, { encoding: 'utf8', cwd: rootDir }).trim()
|
|
}
|
|
|
|
const SEMVER_RE = /^\d+\.\d+\.\d+$/
|
|
|
|
const args = process.argv.slice(2)
|
|
let newVersion = null
|
|
|
|
for (const arg of args) {
|
|
if (arg === '--patch' || arg === '--minor' || arg === '--major') {
|
|
const rootPkg = readJson('package.json')
|
|
const parts = rootPkg.version.split('.').map(Number)
|
|
if (arg === '--patch') { parts[2]++; }
|
|
else if (arg === '--minor') { parts[1]++; parts[2] = 0; }
|
|
else if (arg === '--major') { parts[0]++; parts[1] = 0; parts[2] = 0; }
|
|
newVersion = parts.join('.')
|
|
} else if (SEMVER_RE.test(arg)) {
|
|
newVersion = arg
|
|
}
|
|
}
|
|
|
|
if (!newVersion) {
|
|
console.error('❌ 请指定版本号')
|
|
console.log('')
|
|
console.log('用法:')
|
|
console.log(' pnpm release <version> 指定版本号,如 pnpm release 1.3.0')
|
|
console.log(' pnpm release --patch 递增补丁版本 1.2.1 → 1.2.2')
|
|
console.log(' pnpm release --minor 递增次版本 1.2.1 → 1.3.0')
|
|
console.log(' pnpm release --major 递增主版本 1.2.1 → 2.0.0')
|
|
process.exit(1)
|
|
}
|
|
|
|
const tag = `v${newVersion}`
|
|
|
|
console.log('==========================================')
|
|
console.log(` XAGI Frontend Templates Release`)
|
|
console.log(` Target version: ${newVersion}`)
|
|
console.log(` Tag: ${tag}`)
|
|
console.log('==========================================')
|
|
console.log('')
|
|
|
|
// 1. Check working tree clean
|
|
try {
|
|
const status = runQuiet('git status --porcelain')
|
|
if (status) {
|
|
console.error('❌ 工作区有未提交的变更,请先 commit 或 stash')
|
|
console.log(status)
|
|
process.exit(1)
|
|
}
|
|
} catch {
|
|
console.error('❌ 无法检查 git 状态')
|
|
process.exit(1)
|
|
}
|
|
|
|
// 2. Check tag doesn't already exist
|
|
const existingTags = runQuiet('git tag -l').split('\n').filter(Boolean)
|
|
if (existingTags.includes(tag)) {
|
|
console.error(`❌ Tag ${tag} 已存在`)
|
|
process.exit(1)
|
|
}
|
|
|
|
// 3. Update all version numbers
|
|
console.log('📝 更新版本号...')
|
|
const templateSpecs = [
|
|
{ id: 'react-vite', packagePath: 'packages/react-vite/package.json', metaPath: 'packages/react-vite/meta.json' },
|
|
{ id: 'vue3-vite', packagePath: 'packages/vue3-vite/package.json', metaPath: 'packages/vue3-vite/meta.json' },
|
|
{ id: 'react-next', packagePath: 'packages/react-next/package.json', metaPath: 'packages/react-next/meta.json' },
|
|
]
|
|
|
|
// Update root package.json
|
|
const rootPkg = readJson('package.json')
|
|
rootPkg.version = newVersion
|
|
writeJson('package.json', rootPkg)
|
|
console.log(` ✓ root package.json → ${newVersion}`)
|
|
|
|
// Update templates.json
|
|
const templatesRegistry = readJson('templates.json')
|
|
templatesRegistry.version = newVersion
|
|
templatesRegistry.updatedAt = new Date().toISOString()
|
|
for (const spec of templateSpecs) {
|
|
const entry = templatesRegistry.templates.find(t => t.id === spec.id)
|
|
if (entry) {
|
|
entry.version = newVersion
|
|
console.log(` ✓ templates.json[${spec.id}] → ${newVersion}`)
|
|
}
|
|
}
|
|
writeJson('templates.json', templatesRegistry)
|
|
|
|
// Update each template package.json and meta.json
|
|
for (const spec of templateSpecs) {
|
|
const pkg = readJson(spec.packagePath)
|
|
pkg.version = newVersion
|
|
writeJson(spec.packagePath, pkg)
|
|
console.log(` ✓ ${spec.packagePath} → ${newVersion}`)
|
|
|
|
const meta = readJson(spec.metaPath)
|
|
meta.version = newVersion
|
|
writeJson(spec.metaPath, meta)
|
|
console.log(` ✓ ${spec.metaPath} → ${newVersion}`)
|
|
}
|
|
|
|
console.log('')
|
|
|
|
// 4. Run version consistency check
|
|
console.log('🔍 校验版本一致性...')
|
|
try {
|
|
run('node scripts/check-versions.js')
|
|
console.log('✅ 版本一致性校验通过')
|
|
} catch {
|
|
console.error('❌ 版本一致性校验失败')
|
|
process.exit(1)
|
|
}
|
|
console.log('')
|
|
|
|
// 5. Git commit
|
|
console.log('📦 创建 release commit...')
|
|
try {
|
|
run('git add package.json templates.json latest.json packages/*/package.json packages/*/meta.json')
|
|
run(`git commit -m "release: ${tag}"`)
|
|
console.log(` ✓ Committed: release: ${tag}`)
|
|
} catch {
|
|
console.error('❌ Git commit 失败')
|
|
process.exit(1)
|
|
}
|
|
console.log('')
|
|
|
|
// 6. Git tag
|
|
console.log(`🏷️ 创建 tag: ${tag}...`)
|
|
try {
|
|
run(`git tag -a ${tag} -m "Release ${tag}"`)
|
|
console.log(` ✓ Tag created: ${tag}`)
|
|
} catch {
|
|
console.error('❌ Git tag 创建失败')
|
|
process.exit(1)
|
|
}
|
|
console.log('')
|
|
|
|
// 7. Push
|
|
console.log('🚀 推送到远程...')
|
|
try {
|
|
run('git push')
|
|
run(`git push origin ${tag}`)
|
|
console.log(' ✓ Pushed commit and tag')
|
|
} catch {
|
|
console.error('❌ Push 失败')
|
|
console.log('')
|
|
console.log('你可以手动执行:')
|
|
console.log(` git push`)
|
|
console.log(` git push origin ${tag}`)
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('')
|
|
console.log('==========================================')
|
|
console.log(' ✅ Release 流程完成!')
|
|
console.log('==========================================')
|
|
console.log('')
|
|
console.log(` 版本: ${newVersion}`)
|
|
console.log(` Tag: ${tag}`)
|
|
console.log('')
|
|
console.log(' GitHub Actions 将自动:')
|
|
console.log(' 1. 打包所有模板')
|
|
console.log(' 2. 创建 GitHub Release')
|
|
console.log(' 3. 上传 zip 文件')
|
|
console.log(' 4. 更新 latest.json')
|
|
console.log('')
|
|
console.log(' 下载地址:')
|
|
console.log(` https://github.com/nuwax-ai/xagi-frontend-templates/releases/tag/${tag}`)
|
|
console.log(` https://raw.githubusercontent.com/nuwax-ai/xagi-frontend-templates/main/latest.json`)
|
|
console.log('')
|