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 <prefix>
首次提交
指定首次提交,不會自動升級版本號
npx standard-version --first-release
指定預發版及Tag前綴
格式
standard-version --prerelease <prefix>
示例
# 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)
}
相關文檔
-
standard-version:
standard-version
文檔 - Conventional-Commits: 一個語義化的Commit Messages規范(A specification for adding human and machine readable meaning to commit messages)
-
tooling-for-conventional-commits: Commit Messages規范范的工具庫
- conventional-changelog: a set of tools for parsing Conventional Commits messages from git histories.
- Conventional Changelog Configuration Spec: 日志規范