Git
校验
你记得这次打包是不是当前调试的代码么?
const sh = require('shelljs')
const chalk = require('chalk')
const uncommit = sh.exec('git status --porcelain').stdout
const lines = uncommit.toString().split('\n').filter(item => item).length
if (lines) {
console.log(chalk.red('note: 有代码未提交或缓存,请慎重发版!!!'))
console.log('----------------------------------------------------')
console.log('recommend: 使用git push提交 或 git stash缓存后再发版.')
process.exit(1)
}
process.exit(0)
每次打包没有日志,强制开发者必须上传或缓存后才能打包,利用Git为打包做日志服务。
const sh = require('shelljs')
const chalk = require('chalk')
const inquirer = require('inquirer')
const log = console.log
async function permission () {
const uncommit = sh.exec('git status --porcelain').stdout
const lines = uncommit.toString().split('\n').filter(item => item).length
if (lines) {
log(chalk.redBright(chalk.bold('note: ') + '有代码未提交或缓存,请慎重发版!!!'))
log('----------------------------------------------------')
log(chalk.blueBright('recommend: ') + '使用git push提交 或 git stash缓存后再发版.')
const { isSkip } = (await inquirer.prompt({
type: 'expand',
name: 'isSkip',
choices: [
{
key: 'y',
name: 'Yes',
value: true
},
{
key: 'n',
name: 'No',
value: false
}
],
message: '是否一意孤行?'
}))
if (isSkip) {
process.env.custom_uncommit_skip = isSkip
process.exit(0)
}
process.exit(1)
}
process.exit(0)
}
permission()
使用场景
"prerelease": "node bin/index.js"
自动版本号【简约版】
const fs = require('fs')
const path = require('path')
const handleFile = path.resolve(process.cwd(), 'src', 'manifest.json')
const rawText = fs.readFileSync(handleFile)
const manifestJson = JSON.parse(rawText)
console.log(manifestJson)
manifestJson.versionCode++
fs.writeFileSync(handleFile, JSON.stringify(manifestJson, '', 2))
JSON.stringify
的使用
JSON.stringify()
接受三个参数
- data:JSON数据
- function:序列化函数——执行序列化时,被序列化的每个属性都会经过该函数的转换和处理。
- Number | String:指定缩进用的空白字符串来美化输出——Number标识新行空格的个数;字符串标识
\t
、\n
之类
使用场景
"prerelease": "node bin/git-uncommit.js && node bin/auto-version.js",
完善自动版本号
参考
lerna version
- 通过命令行交互选择版本更新级别
- 根据对应的版本级别借助
semver.inc
升级版本
const fs = require('fs')
const path = require('path')
const sh = require('shelljs')
const chalk = require('chalk')
const semver = require('semver')
const inquirer = require('inquirer')
const terminal = inquirer.prompt
const quickJSONFile = path.resolve(process.cwd(), 'src', 'manifest.json')
const manifestJson = JSON.parse(fs.readFileSync(quickJSONFile))
function customVersion(message, { filter, validate } = {}) {
return terminal([
{
type: "input",
name: "input",
message,
filter,
validate,
},
])
.then(answers => {
return answers.input;
});
}
/**
* @param {PackageGraphNode|Object} node The metadata to process
* @property {String} currentVersion
* @property {String} name (Only used in independent mode)
* @property {String} prereleaseId
*/
function promptVersion(currentVersion, name, prereleaseId) {
const patch = semver.inc(currentVersion, "patch");
const minor = semver.inc(currentVersion, "minor");
const major = semver.inc(currentVersion, "major");
const prepatch = semver.inc(currentVersion, "prepatch", prereleaseId);
const preminor = semver.inc(currentVersion, "preminor", prereleaseId);
const premajor = semver.inc(currentVersion, "premajor", prereleaseId);
const message = `Select a new version ${name ? `for ${name} ` : ""}(currently ${currentVersion})`;
return terminal({
type: 'list',
message,
name: 'choice',
choices: [
{ value: patch, name: `Patch (${patch})` },
{ value: minor, name: `Minor (${minor})` },
{ value: major, name: `Major (${major})` },
{ value: prepatch, name: `Prepatch (${prepatch})` },
{ value: preminor, name: `Preminor (${preminor})` },
{ value: premajor, name: `Premajor (${premajor})` },
{ value: "PRERELEASE", name: "Custom Prerelease" },
{ value: "CUSTOM", name: "Custom Version" },
]
}).then(({choice}) => {
if (choice === "CUSTOM") {
return customVersion("Enter a custom version", {
filter: semver.valid,
// semver.valid() always returns null with invalid input
validate: v => v !== null || "Must be a valid semver version",
});
}
if (choice === "PRERELEASE") {
const defaultVersion = semver.inc(currentVersion, "prerelease", prereleaseId);
const prompt = `(default: "${prereleaseId}", yielding ${defaultVersion})`;
return customVersion(`Enter a prerelease identifier ${prompt}`, {
filter: v => semver.inc(currentVersion, "prerelease", v || prereleaseId),
});
}
return choice;
});
}
promptVersion(manifestJson.versionName).then(nextVersion => {
try {
manifestJson.versionName = nextVersion
manifestJson.versionCode++
fs.writeFileSync(quickJSONFile, JSON.stringify(manifestJson, '', 2))
console.log(chalk.whiteBright(`--------------path:${quickJSONFile}--------------------`))
console.log(`${chalk.whiteBright(chalk.bold('Has been configured a new version:'))}${chalk.blueBright(nextVersion)}`)
console.log(chalk.whiteBright(`--------------releasing-releasing-releasing------------------`))
if (!process.env.custom_uncommit_skip) {
sh.exec('git commit --amend --no-edit')
}
process.exit(0)
} catch (e) {
console.log(chalk.redBright(JSON.stringify(e)))
process.exit(1)
}
})
自动生成更新日志
第三方工具
standard-version:
执行npx standard-version
,会进行以下步骤:
- 在
packageFiles
文件中查询当前版本号 - 基于当前版本号 &
commit
(的type
)升级bumpFiles & packageFiles
文件中的版本号 - 生成提交日志(底层借助
conventional-changelog
) - 生成新的commit
- 生成新的tag
bumpFiles vs. packageFiles概念介绍:可以借助文章后续的定制化理解,简单来说,packageFiles
是输入,packageFiles
+ bumpFiles
是输出
用法
基础用法
npx standard-version
指定Tag前缀
默认是'v-*'
standard-version -t
首次提交
指定首次提交,不会自动升级版本号
npx standard-version --first-release
指定预发版及Tag前缀
格式
standard-version --prerelease
示例
# npm run script
npm run release -- --prerelease alpha
指定版本号
忽略自动升级版本功能
# npm run script
npm run release -- --release-as minor
# Or
npm run release -- --release-as 1.1.0
忽略Git钩子校验
standard-version --no-verify
定制化
默认配置
在项目根目录下创建.versionrc | .versionrc.js | .versionrc.json
定制使用standard-version
。
在这之前,需要了解默认配置,默认项是以下的合集
以package.json
文件为例:standard-version
默认修改的是顶层的version
字段,如果想要修改其它结构中的其它字段,除了配置bumpFiles & packageFiles
,还需要自定义updater
。
快应用场景示例:
// .versionrc.js
const handleFile = [
{
"filename": "src/manifest.json",
"type": "json",
"updater": require('./bin/custom-version-updater')
}
]
module.exports = {
"packageFiles": handleFile,
"bumpFiles": handleFile
}
// bin/custom-version-updater.js
const stringifyPackage = require('stringify-package')
const detectIndent = require('detect-indent')
const detectNewline = require('detect-newline')
module.exports.readVersion = function (contents) {
return JSON.parse(contents).versionName
}
module.exports.writeVersion = function (contents, version) {
const json = JSON.parse(contents)
let indent = detectIndent(contents).indent
let newline = detectNewline(contents)
json.versionCode++
json.versionName = version
return stringifyPackage(json, indent, newline)
}