热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

githubrelease_轮子改造:githubreleasenotes

背景github-release-notes,以下简称gren,是用来一键向github发布releasenotes的工具。基本步骤如下:
8320f2c1aaa36f75a7f0c7cd7ac3eb82.png

背景

github-release-notes,以下简称 gren ,是用来一键向 github 发布 release notes 的工具。基本步骤如下:

  1. 拉取 github 仓库的 tags 记录
  2. 拉取最新两个 tag 之间的 pr(或 issue)记录,总结成 release notes
  3. 将 release notes 推送到 github 仓库,作为最新 tag 的发布日志
ff3985e1ebf703c7e519d8e39f9f32b8.png

就是这么简单。不管你是想要:

  • 一次生成所有 tag 的发布日志
  • 定制化日志来源。选择是从 pr 还是 issue 获取;根据其中的 label 生成特定格式的文案
  • 其他功能

这一切都可以一条命令来实现。是不是很棒呢?

自动化发布流程

这里顺带提一下我们组件的自动化发布流程,看看 gren 在其中扮演的角色吧~

  1. 经过测试和实际项目检验的 dev 代码,合并到 master 啦
  2. 触发 travis-ci,做两件事
  3. 发版
  4. yarn build,生成可发布的代码
  5. 部署到 github page
  6. 发布到 npm
  7. 发更新日志
  8. 用 standard-version 根据 semver 和最新的 commit-msg 来更新 package 版本并打 tag
  9. 推送新 commit 和 tag 到 github 仓库
  10. 用 github-release-notes 生成 release-log
  11. 调用钉钉服务发群通知

遇到的问题

前面说了,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"
}

这是个好主意:可以统一管理配置文件了;但还有个问题:每次更新并发布配置后依然需要手动更新每个组件。

因此,我们的方案需要解决两个问题:

  1. 所有组件共享一份 gren 配置
  2. 更新 gren 配置时不需要再去更新每个组件

实践

首先,我们需要支持远程配置。

// 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"
}

步骤如下:

  1. 从 package.json 的 gren 字段拿到配置包名 packageName
  2. 通过请求 https://registry.npmjs.org/-/package/@femessage/grenrc/dist-tags 拿到最新版本 version
  3. 组合后请求 https://cdn.jsdelivr.net/npm/${packageName}@${version}/index.js 拿到最新的配置

结果

最终我们一劳永逸地实现了:

  1. 统一管理配置
  2. 更新配置组件不用发版

这两个需求。另外,github-release-notes 官方仓库也已接受了 pr。

插曲——如何在 node 中同步执行异步操作

一般的异步操作可以通过 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());

善后

用脚本批量更新组件 & 提交 pr

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()

补充:为组件提交 pr 的流程

1、从 femessage/{component} 组件仓库 fork 一份到自己的仓库

2、从自己仓库拉代码到本地,基于 dev 分支切功能分支或 hotfix 分支,修改代码

3、push 分支,向 femessage 仓库提交 pr

4、写好 pr 的 title 和 content

  • title 格式与 commit 规范相同:feat: 某某功能。这样机器人 auto-add-label 就会自动打 label。不同 label 的 pr 会被 gren 归类,生成 release-log
a4f86385bee7886750a666d9757da099.png
  • content 可以参考模板填写内容
  1. why,需求场景是什么,或解决了什么 issue
  2. how,如果实现方式比较有技巧,那可以简单讲解一下,方便 maintainer 早点合 pr
  3. test,这个其实也很简单。你本地调试完肯定会跑跑看。
  4. 如果是新功能,截下新功能的图
  5. 如果是修复 bug,则需要截下修复前和修复后的对比图
  6. docs,如果是补充文档内容的 pr,则在这里文字或截图说明一下
02735740af35993237676415c94736a5.png

5、等待被添加为 contributors

f7811b1b8ad245bb6d6451a7c747a83a.png

鸣谢

  • Han,完成了初期迭代版本,找到了同步请求资源的方案
  • EVILLT,提供了批量更新组件依赖 & 提 pr 的脚本方案
  • levy,推动了整个方案的进行

参考

  • github-release-notes 官方概念详解
  • 揭秘vue-sfc-cli: 组件研发利器



推荐阅读
  • 本文介绍了JavaScript进化到TypeScript的历史和背景,解释了TypeScript相对于JavaScript的优势和特点。作者分享了自己对TypeScript的观察和认识,并提到了在项目开发中使用TypeScript的好处。最后,作者表示对TypeScript进行尝试和探索的态度。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
  • 微信民众号商城/小顺序商城开源项目介绍及使用教程
    本文介绍了一个基于WeiPHP5.0开发的微信民众号商城/小顺序商城的开源项目,包括前端和后端的目录结构,以及所使用的技术栈。同时提供了项目的运行和打包方法,并分享了一些调试和开发经验。最后还附上了在线预览和GitHub商城源码的链接,以及加入前端交流QQ群的方式。 ... [详细]
  • 一、路由首先需要配置路由,就是点击good组件进入goodDetail组件配置路由如下{path:goodDetail,component:goodDetail}同时在good组件中写入如下点击事件,路由中加入 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
  • 怀疑是每次都在新建文件,具体代码如下 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
author-avatar
罗然8_907
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有