赞
踩
github-release-notes,以下简称 gren ,是用来一键向 github 发布 release notes 的工具。基本步骤如下:
就是这么简单。不管你是想要:
这一切都可以一条命令来实现。是不是很棒呢?
这里顺带提一下我们组件的自动化发布流程,看看 gren 在其中扮演的角色吧~
前面说了,github-release-notes 发布日志的格式是高度可配置的。那么具体配置来源于以下这样的配置文件。
- // .grenrc.js
- module.exports = {
- dataSource: 'prs',
- groupBy: {
- '✨ New Features:': ['enhancement'],
- ' Bug Fixes:': ['bug'],
- ' Documentation:': ['documentation'],
- ' Refactors:': ['refactor'],
- '♻️ Tests:': ['test'],
- ' Performance:': ['performance'],
- '⚓ Dependency upgrades:': ['dependencies'],
- ' Chore:': ['chore'],
- ' Style:': ['style'],
- ' Hack': ['hack'],
- ' Breaking Changes': ['breaking-change']
- }
- }
而这个配置是放置在每个项目之内的。假设我们需要更新这份配置,比如更换 dataSource,或新增了一个 label;组件维护者得一个一个地去组件提 pr。这样既容易遗漏,也很麻烦。
prettier 是允许用户将配置放在 npm 模块里,然后在 package.json 里引入
- // package.json
- {
- "devDependencies": {
- "@company/prettier-config": "1.0.0"
- },
- "prettier": "@company/prettier-config"
- }
这是个好主意:可以统一管理配置文件了;但还有个问题:每次更新并发布配置后依然需要手动更新每个组件。
因此,我们的方案需要解决两个问题:
首先,我们需要支持远程配置。
- // package.json
- {
- "gren": "https://raw.githubusercontent.com/FEMessage/.github/master/.grenrc.js"
- }
github-release-notes 先判断 package.json 是否有 gren 这个字段;有则优先去请求网络资源。这里我们先在团队 github 中管理资源。
但 github 不是用来做 cdn 的。这样的资源请求会极容易被拒绝(加 token也不行)。听说 jsdelivr 能缓存 github 资源,那么:
- // package.json
- {
- "gren": "https://cdn.jsdelivr.net/gh/FEMessage/.github/master/.grenrc.js"
- }
问题出现在了缓存上:我们希望每次更新配置就能立即被使用。所以最后还是用发 npm 包的形式来管理。
- // package.json
- {
- "gren": "@femessage/grenrc"
- }
步骤如下:
最终我们一劳永逸地实现了:
这两个需求。另外,github-release-notes 官方仓库也已接受了 pr。
一般的异步操作可以通过 async/await 来写“同步”形式的代码;但 github-release-notes 获取配置的过程是放在 class constructor 函数中的,不能简单地用 async/await 重构。那该怎么办?
我们参考了 request-from-url 库(像 require 本地仓库一样 require 远程仓库)的实现方案,使用 child_process 库,将网络请求放在子进程中进行来阻塞主进程,从而使得主进程的代码可以以同步执行的方式书写。
- // 子进程获取 npm 包版本
- const packageName = process.argv[2];
- const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
- require('https').get(url, res => {
- const buffers = [];
- res.on('data', (data) => {
- buffers.push(data);
- }).on('end', () => {
- const { latest } = JSON.parse(Buffer.concat(buffers).toString());
- const result = [null, latest];
- process.stdout.write(JSON.stringify(result));
- });
- });
-
- // 主进程同步执行代码
- const { spawnSync } = require('child_process');
- const { stdout } = spawnSync('node', ['get-package-latest-version.js', gren], {
- cwd: __dirname
- });
- const [errMsg, version] = JSON.parse(stdout.toString());
- const components = [
- 'v-img',
- 'vue-sfc-cli',
- 'el-data-table',
- 'el-form-renderer',
- 'upload-to-ali',
- 'el-select-area',
- 'data-list',
- 'v-editor',
- 'el-semver-input',
- 'el-number-range',
- 'el-data-tree',
- 'excel-it',
- 'log-viewer',
- 'count-down',
- 'img-preview',
- 'create-nuxt-app',
- 'element',
- 'vant',
- 'direct-mail'
- ]
-
- function exec(cwd, wholeCommand) {
- if (Array.isArray(wholeCommand)) {
- wholeCommand.forEach(c => exec(cwd, c))
- return
- }
- const [command, ...args] = wholeCommand.split(' ').map(arg => arg.replace(/%s/g, ' '))
- const {stdout, stderr} = require('child_process').spawnSync(command, args, {cwd})
- const errMsg = stderr.toString()
- if (errMsg) {
- console.error(`stderr:n${errMsg}`)
- // process.exit(1) // 许多用 stderr 来传递普通消息的……
- }
- }
-
- function addGrenToPackageJson(cwd) {
- const packageJsonPath = `${cwd}/package.json`
- const packageJson = require(packageJsonPath)
- packageJson.gren = '@femessage/grenrc'
- require('fs').writeFileSync(
- packageJsonPath,
- JSON.stringify(packageJson, null, 2) + 'n'
- )
- }
-
- function work() {
- components.forEach(c => {
- console.log('component:', c)
- const cwd = `/Users/donald-work/projects/${c}`
- const branch = 'chore-gren'
- exec(cwd, [
- 'git checkout dev',
- 'git pull upstream dev',
- `git checkout -b ${branch}`,
- 'rm .grenrc.js',
- 'yarn remove github-release-notes',
- 'yarn add -D @femessage/github-release-notes',
- ])
- addGrenToPackageJson(cwd)
- const commitMsg = 'chore(deps):%supgrade%sgren'
- exec(cwd, [
- `git commit -am ${commitMsg}`,
- `git push --set-upstream origin ${branch}`,
- `hub pull-request -b femessage:dev -m ${commitMsg}`,
- ])
- })
- }
-
- work()
1、从 femessage/{component} 组件仓库 fork 一份到自己的仓库
2、从自己仓库拉代码到本地,基于 dev 分支切功能分支或 hotfix 分支,修改代码
3、push 分支,向 femessage 仓库提交 pr
4、写好 pr 的 title 和 content
5、等待被添加为 contributors
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。