使用GitHub Actions实现自动化部署
我实现的一个小工具genCode4Swagger,这个工具的作用是使用swagger文档在项目中生成接口方法,通过构建Github Actions
工作流,我实现了:
- 推送分支到远程主分支时,自动生成README.md文档,如果README.md修改了,将修改push到主分支中。
- 在版本修改时,自动执行构建,并且通过
npm publish
发布为npm
包
关于GitHub Actions
GitHub Actions 是 GitHub 提供的一项持续集成(CI)和持续部署(CD)服务,它使您可以在 GitHub 仓库中自动化执行各种工作流程。使用 GitHub Actions,您可以创建自动化流程,以响应存储库事件,例如代码推送、拉取请求、标签创建等。这些工作流程可以帮助您构建、测试、部署和其他与项目相关的任务。
在GitHub Actions中,每一个运行的步骤的步骤都由workflow (工作流程)来定义,存放在代码仓库的.github/workflows
目录下。
workflow文件采用YAML格式,一个仓库下可以定义多个workflow文件。GitHub会自动发现.github/workflows
目录下的*.yml
文件,然后自动运行该文件。
workflow通过on字段设置触发条件,如在push到主分支时触发:
on:
push:
branches:
- main
workflow中可以定义多个 job (任务),换而言之,workflow其实就是多个job的集合,而job是由多个step(步骤)构成,一步步执行;然后每个step又能执行多个action (动作),比如定义一个job检出代码:
jobs:
checkout:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v2
jobs字段下的每一项都表示一项任务,然后runs-on定义了运行环境,steps表示开始定义步骤,然后使用name标注step的名称,uses是使用已经定义好的action,step还有配置,常用的有:
run
:执行脚本命令;with
:向步骤提供参数配置,将会被传递给使用的action,和uses
一起使用;env
:用于设置环境变量,这些环境变量将会在run
执行的脚本命令中使用;
使用name字段,为workflow定义一个名字,组合上面的代码,就可以得到一个在push到主分支时,自动检出代码的工作流:
name: 我的第一个workflow
on:
push:
branches:
- main
jobs:
checkout:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v2
这个工作流没有实际的意义,只是做一个示例来说明workflow的基本配置,有了一定了解后,再让我们来实现一下实际项目中的工作流吧!
生成文档
我的基本诉求是生成文档;生成文档的时机是在项目推送到远程分支上时,附加的需求是希望在生成文档和原本的文档有差别时,将更新通过git推送到远程分支上。
首先,我们创建文件.github/workflows/documentation.yml
,将name定义为文档构建,然后定义工作流触发时机:
name: 文档构建
on:
push:
branches:
- main
使用jsdoc生成文档
生成文档我使用的是jsdoc-to-markdown,这个工具可以使用文件中的jsdoc注释来生成文档,配置为npm script:
"build:doc": "jsdoc2md --files ./src/index.ts --configure ./jsdoc2md.json > README.md"
从./src/index.ts
的jsdoc注释中,生成文档到README.md文件中。
在工作流中,生成文档直接使用pnpm run build:doc
命令即可,执行命令之前,我们需要一些步骤来构建执行命令的环境:
- 检出代码
- name: 检出代码
uses: actions/checkout@v2
- 设置Node.js并指定版本
- name: 设置 Node.js
uses: actions/setup-node@v2
with:
node-version: 'v16.18.0'
- 因为项目中使用的是
pnpm
所以需要安装
- name: 安装 pnpm
run: npm install -g pnpm
- 然后安装项目依赖
- name: 安装依赖
run: pnpm install
- 最后,再运行
pnpm run build:doc
命令构建文档
- name: 构建文档
run: pnpm run build:doc
检测新文档并且push
再来分析一下我们的附加需求,生成新文档时,git push到远程分支,推送到远程分支简单,git push
命令就可以了,我们先确定最后的步骤:
- name: 提交并推送更改
run: git push
然后我们再考虑如何检测新文档,使用git命令想要检测文件是否修改其实很简单,使用git diff
就可以, git diff
可以显示两个 Git 树之间的更改,如果没有指定树(例如提交或分支),则默认比较工作目录和暂存区。如果发现文件改动就可以执行git add和git commit提交代码了,完整的脚本如下:
git diff --quiet --exit-code README.md || (git add README.md && git commit -m 'Update README.md')
选项--quiet
使 git diff
在发现有更改时立即退出,而不显示这些更改,选项 --exit-code
使 git diff
在发现有更改时返回非零退出码,git diff --quiet --exit-code README.md
就是在发现有更改时返回非零退出码,||
是一个 shell 操作符,用于在前一个命令失败时(即返回非零退出码)执行后一个命令。
将脚本配置为npm script:
"postbuild:doc": "git diff --quiet --exit-code README.md || (git add README.md && git commit -m 'Update README.md')",
然后在git push的步骤之前添加:
- name: 提交修改
run: pnpm postbuild:doc
这里有一点需要注意,如果我们的包管理工具使用的是npm,那其实是不需要这一步的,因为pre
、post
都是特殊的前置,prebuild
会在npm build
执行前触发,postbuild
会在npm build
执行后触发,所以使用npm run build:doc
之后会自动执行npm run postbuild:doc
,pnpm
并没有这样的规则,所以需要手动触发。
在workflow中,我们不需要安装git,但我们需要设置git账号信息:
- name: 设置git信息
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
现在可以把我们的工作流推送到远端,就能够自动执行,如果文档有更新,会自动生成,然后更新README.md
文件。
GitHub Token
在上文我们将工作流推送到远端后,工作流并没有成功执行,而是在执行git push时报错:
Permission denied to github-actions[bot]
这是因为我们当前的工作流没有权限去推送代码,我们需要先去项目中进行设置,在项目地址中的Settings->Actions->General下的Workflow permissions菜单下,我们可以看到两个选项:
项目默认选中的是第二个选项,此时工作流程在存储库中仅具有内容和包范围的读取权限,我们需要选中第一个选项,工作流才能中具有读取和写入权限。
再尝试执行工作流就能够正常运行了。
自动发布
第二个需求,是在版本更新时,自动发布为npm包;版本更新时,我们需要修改package.json的version,这是npm发版的需求,在我们的项目管理中,我们需要标记不同版本的代码,方法在发生问题时,进行回滚和检测,比较常见的方式就是实用git标记tag,我们使用standard-version
来实现这些功能。
standard-version
实现版本更新
standard-version
是一个用于版本管理和发布的工具,它遵循语义化版本(Semantic Versioning)规范,并自动生成 CHANGELOG。在package.json
中添加release脚本:
"scripts": { "update:version": "standard-version" }
然后使用npm run update:version
运行脚本,standard-version
会执行一下操作:
- 更新版本号:
standard-version
会根据你的 git 提交历史自动更新package.json
中的版本号。 - 生成或更新 CHANGELOG:
standard-version
会根据你的 git 提交历史自动生成或更新 CHANGELOG.md 文件。 - 创建一个新的 git tag:
standard-version
会创建一个与新版本号对应的 git tag。 - 提交更改和 tag:
standard-version
会将更改提交到 git。
standard-version
不会提交tag到远端,我们需要添加一段git脚本,来实现完整的发布功能:
"scripts": {
"release": "npm run update:version && git push --follow-tags origin main"
}
需要发布版本时,运行pnpm run release
命令,然后剩下的交给工作流即可。
构建发布工作流
明确工作流触发时间,在推送tag时触发:
on:
push:
tags:
- v* # 触发工作流的 tag 模式,v* 表示所有以 v 开头的 tag
npm publish
发布的准备工作:
- 检出代码
- 设置Node.js版本及需要发布npm的registry
- 安装
pnpm
- 执行构建
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 检出代码
uses: actions/checkout@v2
- name: 设置 Node.js
uses: actions/setup-node@v2
with:
node-version: 'v16.18.0' # 使用你喜欢的 Node.js 版本
registry-url: 'https://registry.npmjs.org'
- name: 安装 pnpm
run: npm install -g pnpm
- name: 安装依赖
run: pnpm install # 或者根据你的包管理器使用 'npm ci' 或 'yarn'
- name: 构建
run: pnpm run build # 替换为你用来构建项目的命令
最后就是发布任务,但是发布到npm仓库是需要鉴权的,所以我们需要使用env
设置NODE_AUTH_TOKEN
:
- name: 发布 npm 包
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
在你登录过npm
账号的电脑上(没有登录过使用npm login
登录你的账号),执行cat ~/.npmrc
,然后_authToken
之后的值就是我们需要的Token;在你的GitHub项目中,Settings-> Secrets and variables-> Actions,Secrets选项卡下,点击New repository secret按钮,添加NPM_TOKEN。
最后本地执行pnpm run release
,项目推送到远端,工作流自动运行,npm
包就能够自动发布了。
总结
在本文中,我们配合git命令,使用jsdoc-to-markdown
将项目中的jsdoc注释生成文档,使用standard-version
进行版本更新 还是自动发布,使用Github Action
工作流编排任务,然后在合适的时机触发来实现了项目的自动化部署。
Github Action
本质上是一个编排工具,实现自动化部署我们也可以选择其他工具来实现,使用这类工具时,我们可以将需求告诉chatgpt,借助AI来快速编写workflow。
在生成文档的工作流中,最后git push到远端,理论上会再次出发工作流,在一些情况下可能进入死循环,所以如果需要再工作流中推送代码要额外注意,生成文档这个需求更好的方式应该是在本地git push
之前,自动生成,跟随本地的修改一起提交,但是在本文就不再讨论了。
最后是国内github访问不稳定的问题,我已经配置好了本地host,但是依旧不稳定,然后通过 git 配置代理来实现的(前提是你有稳定的代理):
git config --global http.https://github.com.proxy socks5://127.0.0.1:1080
转载自:https://juejin.cn/post/7258173427340247077