diff --git a/Help.md b/Help.md index 4c813e3..583b6ab 100644 --- a/Help.md +++ b/Help.md @@ -8,20 +8,37 @@ pnpm test core main pnpm test -- -p core,main --coverage ``` - - # Release ## 版本发布 -1. `pnpm changeset` -2. `pnpm changeset:version` - - 然后执行 `pnpm changelog` 打印版本日志 -3. 更改`change log`后, `git add & commit` -4. `git push` 后触发 github release,自动发布 +```bash +# 1. 创建变更集 +pnpm changeset + + +# 2. 更新版本、编辑变更日志、读取和删除变更集的命令 +# 注: 该步骤放在本地手动操作 +pnpm changeset:version + + +# 3. 生成日志记录 +pnpm changelog core cli +# 查看日志记录 +pnpm changelog + + +# 4. 提交 commit +git add . +git commit -m 'Version Packages' +# 5. 提交远程仓库并发布 (触发 github-action 自动发布) +git push +``` + ## 语义化版本 + 严格遵循 [semver](https://semver.org/) 规范。 ``` @@ -31,24 +48,23 @@ pnpm test -- -p core,main --coverage - `Major` - 主版本号:当你做了不兼容的 API 修改 - `Minor` - 次版本号:当你做了向下兼容的功能性新增 - `Patch` - 修订号:当你做了向下兼容的问题修正 -先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。 + 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。 > **Tag** +> > - `alpha` - alpha 版本, 内部测试版,一般不向外部发布; > - `beta` - beta 版本, 测试版,该版本会一直加入新的功能; -> - `rc` - rc 版本 (Release Candidate) 发行候选版本。不再加新功能,着重于除错。 +> - `rc` - rc 版本 (Release Candidate) 发行候选版本。不再加新功能,着重于除错。 > > 优先层级: > 例如:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0。 - ## refs -- [pnpm构建monorepo工程](https://github.com/astonishqft/pnpm-monorepo-demo) + +- [pnpm 构建 monorepo 工程](https://github.com/astonishqft/pnpm-monorepo-demo) - [webpack5 的多页脚手架](https://github.com/kailong321200875/webpack-multi-page-cli) - [pnpm-workspaces-example & changeset](https://github.com/DavidWells/pnpm-workspaces-example/) - # Todo - # Help diff --git a/scripts/changelog.js b/scripts/changelog.js index 68400aa..84c3ead 100644 --- a/scripts/changelog.js +++ b/scripts/changelog.js @@ -1,7 +1,11 @@ const simpleGit = require('simple-git') const { promisify } = require('util') const log = require('diy-log') +const minimist = require('minimist') +const { readPackageJson, readPackageFile, writePackageFile, updateChangelog } = require('./utils') +const rawArgs = process.argv.slice(2) +const args = minimist(rawArgs) const git = simpleGit() // 获取从特定 commit ID 开始的所有最新记录 @@ -62,10 +66,20 @@ function formatCommits(commits, filter = (commit) => commit) { }) } +// 生成日志记录 +async function generateLogs(name, logs) { + const pkg = await readPackageJson(name) + const content = await readPackageFile(name) + const result = updateChangelog(content, pkg.version, logs[name]) + await writePackageFile(name, result) + + return result +} + ;(async () => { const moduleRegex = /^[a-z]{1,10}\(\w+\).*/i try { - // const commits = await getCommitsSince('4ac1e7a') + // const commits = await getCommitsSince('d9acb96') const commits = await getCommitsSinceLatestTag() const formattedCommits = formatCommits(commits, (commit) => { return moduleRegex.test(commit.message) @@ -81,14 +95,22 @@ function formatCommits(commits, filter = (commit) => commit) { ) return acc }, {}) + console.log( 'Commit messages:', formatCommits(commits).map((commit) => commit.message) ) + Object.entries(formattedCommits).forEach(([key, value]) => { log.tag.warn('\n' + value.join('\n'), key) }) - } catch (error) { - console.error('error:', error.message) + + if (args._.length) { + for (const name of args._) { + await generateLogs(name, formattedCommits) + } + } + } catch (err) { + console.error('error:', err.message) } })() diff --git a/scripts/config.js b/scripts/config.js new file mode 100644 index 0000000..1dc610b --- /dev/null +++ b/scripts/config.js @@ -0,0 +1,37 @@ +/** + * 模块及对应路径 + */ +const packagesMap = { + core: 'packages/core', + cli: 'packages/cli', + main: 'packages/main', + utils: 'packages/utils', + renew: 'plugins/renew', +} + +/** + * 版本 emoji 标识 + */ +const semverSymbol = { + Major: '🎉', + Minor: '🚀', + Patch: '🌟', +} + +/** + * 显示的日志类型 + * // (revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip) + */ +const messagesType = ['feat', 'fix', 'perf', 'refactor', 'docs'] + +/** + * changeset 默认变更日志 (待替换) + */ +const defaultChangeLog = `- update.` + +module.exports = { + packagesMap, + semverSymbol, + messagesType, + defaultChangeLog, +} diff --git a/scripts/test.js b/scripts/test.js index 81f55bc..27f35ab 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -1,13 +1,7 @@ const minimist = require('minimist') const rawArgs = process.argv.slice(2) const args = minimist(rawArgs) -const packagesMap = { - core: 'packages/core', - cli: 'packages/cli', - main: 'packages/main', - utils: 'packages/utils', - renew: 'plugins/renew', -} +const { packagesMap } = require('./config') let regex if (args.p) { diff --git a/scripts/utils.js b/scripts/utils.js new file mode 100644 index 0000000..df34a7a --- /dev/null +++ b/scripts/utils.js @@ -0,0 +1,105 @@ +const fs = require('fs') +const path = require('path') +const { packagesMap, semverSymbol, messagesType, defaultChangeLog } = require('./config') + +/** + * 读取模块文件内容 + * + * @param {string} name 模块名 + * @param {string} filename 文件名 + * @returns {Promise} + */ +function readPackageFile(name, filename) { + return new Promise((resolve, reject) => { + const filePath = path.resolve(__dirname, '../', packagesMap[name], filename || 'CHANGELOG.md') + fs.readFile(filePath, 'utf8', (err, data) => { + if (err) { + reject(err) + } + resolve(data) + }) + }) +} + +/** + * 写入模块文件内容 + * + * @param {string} name 模块名 + * @param {string} filename 文件名 + * @returns {Promise} + */ +function writePackageFile(name, data, filename) { + return new Promise((resolve, reject) => { + fs.writeFile( + path.resolve(__dirname, '../', packagesMap[name], filename || 'CHANGELOG.md'), + data, + (err) => { + if (err) { + reject(err) + } + resolve() + } + ) + }) +} + +/** + * 日志排序 + * + * @param {Array.} logs 日志列表 + * @returns {Array.} + */ +function sortLogsByType(logs) { + const msgRegex = new RegExp(`- (${messagesType.join('|')}):[\\s\\S]+`) + return logs + .reduce((acc, cur) => { + const type = cur.match(msgRegex)?.[1] + const index = messagesType.indexOf(type) + if (index > -1) { + acc[index].push(cur) + } + return acc + }, messagesType.map(() => []).concat([[]])) + .reduce((acc, cur) => acc.concat(cur), []) +} + +/** + * 更新日志内容 + * + * @param {string} content 日志内容 + * @param {string} version 版本号 + * @param {Array.} logs 日志列表 + * @returns {Promise} + */ +function updateChangelog(content, version, logs) { + const [v1, v2, v3] = version.split('.') + const regex = new RegExp(`## ${v1}\\.${v2}\\.${v3}[\\s]*### (Patch|Minor|Major) Changes\\n`) + logStr = sortLogsByType(logs).join('\n') + + return content + .replace(regex, (match, p1) => { + // console.log('replace : ', match, p1) + return match.replace('Changes', 'Changes ' + semverSymbol[p1]) + // return match + ' ' + semverSymbol[p1] + }) + .replace(defaultChangeLog, logStr) +} + +/** + * 读取JSON文件内容 + * + * @param {string} name 模块名 + * @param {string} filename 文件名 + * @returns {Promise} + */ +function readPackageJson(name, filename) { + return readPackageFile(name, filename || 'package.json').then((data) => JSON.parse(data)) +} + +module.exports = { + readPackageFile, + writePackageFile, + readPackageJson, + updateChangelog, + sortLogsByType, +}