Open hacker0limbo opened 3 years ago
Github Action 是 Github 官方出的持续集成服务, 挺早之前就推出了, 这次正好遇到一点需求, 看了一下文档自己写了一个 workflow 和 action 脚本
workflow
action
文档还是很全的, 但是细节有点多, 写的时候不注意的话很容易踩坑, 而且这个东西无法在本地进行调试, 我只能每次更新了代码后手动 run 一次 workflow, 虽然有一个叫 act 的库貌似支持本地跑的, 但是又要用到 docker 啥的, 我电脑比较旧带不动, 就算了
阮一峰老师写过一篇还挺清晰的教程介绍基本概念: GitHub Actions 入门教程. 最基本的几个概念为:
以官方给的一个 workflow 文件为例, 所有的 workflow 都存放在 .github/workflows 目录下:
.github/workflows
# .github/workflows/learn-github-actions.yml name: learn-github-actions on: [push] jobs: check-bats-version: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '14'
该 workflow 的含义为:
push
check-bats-version
actions/setup-node@v2
node-version
14
触发 workflow 的事件还有很多, 可以是多个事件, 也可以手动触发, 也可以细分具体到一个事件的不同类型, 具体需要参考官方文档: Events that trigger workflows
关于 workflow 的语法具体也参考官方文档: Workflow syntax for GitHub Actions
虽然 github marketplace 有很多已经写好的 action, 但是还是免不了自己有特质需求需要自定义 action. 比如我的需求是, 我的博客全部写在 issue 里, README.md 通常作为目录按照时间分类放置每篇文章的标题和对应到 issue 的链接, 大致格式是这样:
README.md
# 个人博客 ## 2019 - [第一篇博客](https://github.com/owner/repo/issues/1) - [第二篇博客](https://github.com/owner/repo/issues/2) ## 2020 ...
但是每次更新 issue 之后就需要手动去更新 README, 我所希望的时候能有 workflow 能帮我自动处理这些事情, 在博客更新之后通过 github 提供的 API 手动提交一次 commit 更新我的 README 目录
官方有关于自定义 action 的文档: About custom actions. 以及如何自定义 JavaScript action: Creating a JavaScript action 还算详细. 不过有一些细节需要注意:
action.yml
action.yaml
.github
action.yml 的大致语法可以参考: Metadata syntax for GitHub Actions. 这里简略罗列一下我的:
name: 'Action Name' description: 'Description for custom action' inputs: repoToken: description: 'github access token' required: true runs: using: 'node12' main: 'dist/index.js'
说明一下:
name
descript
inputs
repoToken
runs
node12
dist/index.js
关于 token, 官方有提到: Automatic token authentication. 如文中所述, 在编写 workflow 时, 需要使用 with 语法提供对应的参数, 这个参数就是自动生成的 token.
对应我的 workflow 文件内容如下:
name: My Workflow on: workflow_dispatch: issues: types: [opened, edited, deleted] jobs: sync-readme: runs-on: ubuntu-latest name: My job name steps: - name: use my custom action uses: owner/repo@master with: repoToken: ${{ secrets.GITHUB_TOKEN }}
这里 on 监听了两个事件, 一个是 workflow_dispatch, 一个是 issues 具体的类型. workflow_dispatch 是为了允许手动跑 workflow, 方便线上调试. 具体可以看: Manually running a workflow. issues 我提供了三个类型分别在新增一条 issue, 编辑一条 issue 和删除一条 issue 时触发该 workflow.
on
workflow_dispatch
issues
最后是绑定自定义的 action, 注意这里 with 下的 repoToken 和上面 action.yml 中的 inputs 里对应
with
需要用到两个库:
@actions/core
@actions/github
第一个库主要用于获取输入输出, 比如上文提到的 token. 打日志. 第二个库提供了 Github API 的接口, 返回的是一个已经 auth 过的 Octokit REST 客户端
由于我的需求是根据在我更新完 issue 之后根据最新的 issue 信息更新我的 README. 所有思路也很简单, 发一次请求获取所有的 issue 信息, 然后再根据 issue 信息做一次 commit 更新 readme. 需要用到 3 个 API:
octokit.rest.issues.listForRepo
octokit.rest.repos.getContent
octokit.rest.repos.createOrUpdateFileContents
这里注意一下, 由于在使用第三个 api 即 createOrUpdateFileContents 时候, 如果是更新文件内容需要提供该文件的 sha 值, 所以只能先通过 getContent 获取到 sha 值之后再更新, 同时更新的内容必须使用 Base64 encoding 加密.
createOrUpdateFileContents
sha
getContent
Base64
最后的文件大体思路为:
const core = require('@actions/core'); const github = require('@actions/github'); const { Buffer } = require('buffer'); function run() { const repoToken = core.getInput('repoToken'); const octokit = github.getOctokit(repoToken); octokit.rest.issues .listForRepo({ owner: 'xxx', repo: 'yyy', }) .then(({ data: issues }) => { const content = contentFromIssues(issues) octokit.rest.repos .getContent({ owner: 'xxx', repo: 'yyy', filePath: 'README.md' }) .then(({ data }) => { const { sha } = data octokit.rest.repos .createOrUpdateFileContents({ ...config, path: 'README.md', message: 'feat: xxx', content: Buffer.from(content).toString('base64'), sha, }) .then((res) => core.info('success to update')) .catch(error => core.setFailed(error.response.data.message)) }) .catch(error => core.setFailed(error.response.data.message)) }) .catch(error => core.setFailed(error.response.data.message)) } run()
最后, 官方文档建议使用 @vercel/ncc 对 action 脚本进行打包, 这么做也是为了避免上传 node_modules. 或者另一种做法是在 workflow 跑的时候手动安装需要的依赖. 这里我选择前一种方法. 这里 npm i -g @vercel/ncc 后使用 ncc build action.js 即可打包文件到 dist/index.js 中. 遗憾的是貌似无法指定对应的文件名.
node_modules
npm i -g @vercel/ncc
ncc build action.js
简单聊一聊 github action
Github Action 是 Github 官方出的持续集成服务, 挺早之前就推出了, 这次正好遇到一点需求, 看了一下文档自己写了一个
workflow
和action
脚本文档还是很全的, 但是细节有点多, 写的时候不注意的话很容易踩坑, 而且这个东西无法在本地进行调试, 我只能每次更新了代码后手动 run 一次
workflow
, 虽然有一个叫 act 的库貌似支持本地跑的, 但是又要用到 docker 啥的, 我电脑比较旧带不动, 就算了基本概念
阮一峰老师写过一篇还挺清晰的教程介绍基本概念: GitHub Actions 入门教程. 最基本的几个概念为:
以官方给的一个 workflow 文件为例, 所有的 workflow 都存放在
.github/workflows
目录下:该 workflow 的含义为:
push
事件触发时激活该 workflowcheck-bats-version
, 该 job 跑在最新的 ubuntu 上actions/setup-node@v2
action 运行时需要传递参数, 参数名node-version
, 参数值14
触发 workflow 的事件还有很多, 可以是多个事件, 也可以手动触发, 也可以细分具体到一个事件的不同类型, 具体需要参考官方文档: Events that trigger workflows
关于 workflow 的语法具体也参考官方文档: Workflow syntax for GitHub Actions
需求
虽然 github marketplace 有很多已经写好的 action, 但是还是免不了自己有特质需求需要自定义 action. 比如我的需求是, 我的博客全部写在 issue 里,
README.md
通常作为目录按照时间分类放置每篇文章的标题和对应到 issue 的链接, 大致格式是这样:但是每次更新 issue 之后就需要手动去更新 README, 我所希望的时候能有 workflow 能帮我自动处理这些事情, 在博客更新之后通过 github 提供的 API 手动提交一次 commit 更新我的 README 目录
实现
action.yml 和 workflow.yml
官方有关于自定义 action 的文档: About custom actions. 以及如何自定义 JavaScript action: Creating a JavaScript action 还算详细. 不过有一些细节需要注意:
action.yml
或者是action.yaml
.github
文件夹下也行, 不过在workflow
的时候还需要 checkout 定位到 repo 上. 而且只有在根目录下的 action 才能发布到 github marketplace.action.yml
的大致语法可以参考: Metadata syntax for GitHub Actions. 这里简略罗列一下我的:说明一下:
name
和descript
分别是自定义 action 的名字和描述inputs
是该 action 的输入源, 可以有多个. 由于我的需求需要用到 github 的 API, 使用过程需要 token 来 authentication. 这个 token 每次 workflow 运行时会自动生成, 不需要手动输入. 因此在编写 workflow 的时候要注明. 这里我给的输入源名字为repoToken
runs
注明了使用node12
, 同时对应的 JavaSctipt action 文件为根目录下的dist/index.js
关于 token, 官方有提到: Automatic token authentication. 如文中所述, 在编写 workflow 时, 需要使用 with 语法提供对应的参数, 这个参数就是自动生成的 token.
对应我的 workflow 文件内容如下:
这里
on
监听了两个事件, 一个是workflow_dispatch
, 一个是issues
具体的类型.workflow_dispatch
是为了允许手动跑 workflow, 方便线上调试. 具体可以看: Manually running a workflow. issues 我提供了三个类型分别在新增一条 issue, 编辑一条 issue 和删除一条 issue 时触发该 workflow.最后是绑定自定义的 action, 注意这里
with
下的repoToken
和上面action.yml
中的inputs
里对应编写脚本
需要用到两个库:
@actions/core
@actions/github
第一个库主要用于获取输入输出, 比如上文提到的 token. 打日志. 第二个库提供了 Github API 的接口, 返回的是一个已经 auth 过的 Octokit REST 客户端
由于我的需求是根据在我更新完 issue 之后根据最新的 issue 信息更新我的 README. 所有思路也很简单, 发一次请求获取所有的 issue 信息, 然后再根据 issue 信息做一次 commit 更新 readme. 需要用到 3 个 API:
octokit.rest.issues.listForRepo
octokit.rest.repos.getContent
octokit.rest.repos.createOrUpdateFileContents
这里注意一下, 由于在使用第三个 api 即
createOrUpdateFileContents
时候, 如果是更新文件内容需要提供该文件的sha
值, 所以只能先通过getContent
获取到sha
值之后再更新, 同时更新的内容必须使用Base64
encoding 加密.最后的文件大体思路为:
最后, 官方文档建议使用 @vercel/ncc 对
action
脚本进行打包, 这么做也是为了避免上传node_modules
. 或者另一种做法是在 workflow 跑的时候手动安装需要的依赖. 这里我选择前一种方法. 这里npm i -g @vercel/ncc
后使用ncc build action.js
即可打包文件到dist/index.js
中. 遗憾的是貌似无法指定对应的文件名.参考