Skip to content

Commit

Permalink
chore: improve release command
Browse files Browse the repository at this point in the history
  • Loading branch information
Barrior committed Jan 22, 2024
1 parent 6026ae6 commit 5eb66e6
Showing 1 changed file with 100 additions and 5 deletions.
105 changes: 100 additions & 5 deletions scripts/release.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { execSync } from 'child_process'
import { execaCommand, execaCommandSync } from 'execa'
import { readdirSync, readFileSync, writeFileSync } from 'fs'
import inquirer from 'inquirer'
import { forEach } from 'lodash-es'
import ora from 'ora'
import path from 'path'
import { fileURLToPath } from 'url'

Expand All @@ -10,6 +11,7 @@ import logger from './logger.mjs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const packages = path.resolve(__dirname, '../packages')
const projectNames = readdirSync(packages)
const spinner = ora()

const projectMap = {
'core-react': {
Expand All @@ -24,16 +26,69 @@ const projectMap = {
}

class Release {
newVersion = ''

constructor() {
this.run()
}

async run() {
this.catchErrorAndCleanWorkspace()
this.checkBranchAndStatus()
await this.runLintAndTest()
await this.askReleaseVersion()
this.bumpVersion()
await this.buildProduct()
await this.publishToNpm()
this.commit()
}

/**
* 命令过程出现错误时,清除构建过程产生的文件,还原到命令执行前的状态
*/
catchErrorAndCleanWorkspace() {
process.on('uncaughtException', () => {
logger.error('命令过程执行存在错误,还原文件变更至初始状态')
execaCommandSync('git checkout .', { stdio: 'inherit' })
})
}

/**
* 检查分支名称是否正确:必须是 master 或者 main 分支才允许
* 检查分支状态是否正确:必须是干净的分支,不存在未提交的内容
*/
checkBranchAndStatus() {
// 检查分支名称
const branchName = execaCommandSync('git symbolic-ref HEAD --short').stdout
if (!['master', 'main'].includes(branchName)) {
logger.error('命令执行分支不正确,只允许 master 或者 main 分支')
process.exit(1)
}

// 检查分支状态
const status = execaCommandSync('git status --porcelain').stdout
if (status) {
logger.error('分支状态不正确,存在未提交的文件')
process.exit(1)
}
}

/**
* 校验代码风格与运行测试用例
*/
async runLintAndTest() {
spinner.start('代码风格校验')
await execaCommand('yarn lint')
spinner.succeed()

spinner.start('测试用例验证')
await execaCommand('yarn test --verbose=false')
spinner.succeed()
}

/**
* 咨询发布版本号
*/
async askReleaseVersion() {
// 读取 core package.json
const filePath = path.resolve(packages, './core-react/package.json')
Expand All @@ -51,7 +106,7 @@ class Release {

const answers = await inquirer.prompt(questions)

// Trim the answers of input
// 去除输入内容首尾空白
forEach(answers, (value, key) => {
answers[key] = value.trim()
})
Expand All @@ -63,6 +118,11 @@ class Release {
* 将每个项目自身的版本号、依赖项的版本号更新为最新的
*/
bumpVersion() {
if (!this.newVersion) {
logger.error('发布版本号不存在')
process.exit(1)
}

projectNames.forEach((projectName) => {
// 读取内容
const filePath = path.resolve(packages, `./${projectName}/package.json`)
Expand All @@ -86,13 +146,48 @@ class Release {
})
}

/**
* 构建产品,将源码编译到 dist 目录
*/
async buildProduct() {
for (let i = 0; i < projectNames.length; i++) {
const projectName = projectNames[i]
const dirPath = path.resolve(packages, `./${projectName}`)

spinner.start(`执行 ${projectName} 构建命令`)
await execaCommand('npm run build', { cwd: dirPath })
spinner.succeed()
}
}

/**
* 发布到 npm
*/
async publishToNpm() {
for (let i = 0; i < projectNames.length; i++) {
const projectName = projectNames[i]
const dirPath = path.resolve(packages, `./${projectName}`)

spinner.start(`发布 ${projectName}`)
await execaCommand('npm publish', { cwd: dirPath })
spinner.succeed()
}
}

/**
* 提交 git
*/
commit() {
execSync(`git commit -am "build: v${this.newVersion}" -n`, {
stdio: 'inherit',
})
const commitFiles = projectNames
.map((projectName) => `packages/${projectName}/package.json`)
.join(' ')
execaCommandSync(`git add ${commitFiles}`)
execaCommandSync(`git commit -m chore(release):\\ v${this.newVersion} -n`)
execaCommandSync(`git tag v${this.newVersion}`)
logger.log(`文件变更提交 Git 完成`)

// execaCommandSync('git push origin --tags')
// logger.log(`推送 Git 到远程 origin 仓库完成`)
}
}

Expand Down

0 comments on commit 5eb66e6

Please sign in to comment.