/* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-check import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import { createRequire } from 'node:module' import { execSync } from 'node:child_process' import enquirer from 'enquirer' import semver from 'semver' import minimist from 'minimist' import chalk from 'chalk' const step = msg => console.log(chalk.cyan(msg)) // 获取当前目录 const __dirname = path.dirname(fileURLToPath(import.meta.url)) const { prompt } = enquirer const require = createRequire(import.meta.url) // 获取当前版本 const currentVersion = require('../package.json').version const args = minimist(process.argv.slice(2)) const preId = args.preid || semver.prerelease(currentVersion)?.[0] // 如果已经定义的版本号直接跳过 let targetVersion = args._[0] // 如果未定义版本号,则生成推测版本号选项 if (!targetVersion) { const versionIncrements = [ 'patch', 'minor', 'major', ...(preId ? ['prepatch', 'preminor', 'premajor', 'prerelease'] : []) ] const inc = i => semver.inc(currentVersion, i, preId) // @ts-ignore const { release } = await prompt({ type: 'select', name: 'release', message: '请选择 release type', choices: versionIncrements.map(i => `${i} (${inc(i)})`).concat(['custom']) }) // 目标版本号 if (release === 'custom') { const result = await prompt({ type: 'input', name: 'version', message: '请自定义你的想要 release 的版本号', initial: currentVersion }) // @ts-ignore targetVersion = result.version } else { targetVersion = release.match(/\((.*)\)/)[1] } } // 再次确认版本号是否正确 // @ts-ignore const { yes: confirmRelease } = await prompt({ type: 'confirm', name: 'yes', message: `你确认 release 版本号 v${targetVersion} 吗?` }) if (confirmRelease) { await updateVersions(targetVersion) // 仅正式版本号生成 changelog if (/^\d+(\.\d+)*$/.test(targetVersion)) { await generateChangelog() } else { await pushCommit() } } else { console.warn( `${chalk.bgYellow.white(' WARN ')} ${chalk.yellow( `你已经取消了 v${targetVersion} 版本的 release` )}` ) } function updateVersions(version) { step('\nUpdate Versions...') // 更新根目录 updatePackage(path.resolve(__dirname, '..'), version) } // 更新 package.json 的 version 字段 function updatePackage(pkgRoot, version) { const pkgPath = path.resolve(pkgRoot, 'package.json') const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) pkg.version = version fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n') step(`\nUpdate Versions Success ${pkg.name} ${version}`) } // 生成更新日志 async function generateChangelog() { step('\nGenerating Changelog...') await execSync('yarn changelog') // @ts-ignore const { yes: changelogOk } = await prompt({ type: 'confirm', name: 'yes', message: `Changelog 已经生成完毕,请你检查是否 OK?` }) if (changelogOk) { step('\nGenerating Changelog Success') await pushCommit() } else { console.warn( `${chalk.bgYellow.white(' WARN ')} ${chalk.yellow( `你已经取消了 v${targetVersion} 版本的代码推送` )}` ) } } // 推送 release 的版本号 function pushCommit() { step('\nPush Commit...') const releaseMsg = `release(version): v${targetVersion}` try { execSync('git add .') execSync(`git commit -m '${releaseMsg}'`) execSync('git push') console.log( `${chalk.bgGreen.white(' SUCCESS ')} ${chalk.green( `你成功推送了 v${targetVersion} 版本的 release 到远程仓库` )}` ) } catch (error) { if (String(error).includes('No staged files found')) { console.error( `${chalk.bgRed.white(' ERROR ')} ${chalk.red( `版本号重复且 SDK 内容没有变更!` )}` ) } else { console.error( `${chalk.bgRed.white(' ERROR ')} ${chalk.red( `推送 release 的版本号时发生错误: ${error.message}` )}` ) } } }