GitHub Actions是啥

简单介绍下这个组件,GitHub Actions 是一个持续集成 (Continuous integration)和持续交付的平台,可以做到自动化构建、测试、部署。你可以创建出工作流,构建和测试每一个 pull request(拉取请求) 或者部署合并(merge) 后的代码到生产环境里面。
githu actions自动化操作 - 图1
GitHub Actions 可以在你的代码仓库发生某个事件时运行一个工作流。当有人给你的代码仓库新建了一个 issue(问题),你可以跑一个工作流自动的添加合适的标签了,是不是很方便。
GitHub 提供了 Linux、Windows、和 macOS 虚拟机运行你的工作流,当然你也可以自定义自己的运行环境。

GitHub Actions 组件

你可以配置一个 GitHub Actions 工作流(workflow),它会在你的仓库发生某个事件时被触发,就比如一个 pull request 或者一个 issue 被创建的时候。
你的工作流包含了一个或者多个任务, 它们可以并行或者串行执行。每一个任务(jobs)都会在它自己的虚拟机运行器(vmare Operator)上,任务可以有一个或者多个步骤,可以运行一个自定义的脚本(script)或者可运行一个动作(action),所谓这个动作(action)说白点就是一个可复用的扩展,用于简化你的工作流,结构上看就像个套娃。

1 Workflows(工作流)

工作流是一个可配置的自动化的程序。创建一个工作流,你需要定义一个 YAML 文件,当你的仓库触发某个事件的时候,工作流自动的跑起来,当然也可以手动触发,或者定义一个时间表。
一个仓库可以创建多个工作流,每一个都会执行不同的步骤,举个例子,一个工作流用于构建和测试 pull request,另外一个用于部署你的应用(APP),再来一个,当有人新建 issue(问题) 的时候自动添加一个标签上。
你也可以在一个工作流中引用另外一个工作流,具体查看文档「可复用工作流」。

2 事件(Events)

事件是指仓库触发运行工作流的具体的行为,如你创建一个 pull request(推送请求),新建一个 issue、或者推送一个 commit。你也可以使用时间表触发一个工作流,或者通过请求一个 REST API,再或者手动触发,都是可以的。
事件完整的列表,可以查看文档「触发工作流的事件」。

3 任务(Jobs)

任务是在同一个运行器上执行的一组步骤,就是示意图的白框。一个步骤(steps)要么是一个 shell 脚本(script)要么是一个动作(action)。步骤肯定会顺序执行,并彼此独立。因为每一个步骤都在同一个运行器上被执行,所以你可以从一个步骤(step)传递数据到另一个步骤(step) 。
你可以配置一个任务依赖其他任务,默认情况下,任务没有依赖,并行执行的。当一个任务需要另外一个任务的时候,它会等到依赖的任务完成了再执行。

4 动作(Actions)

动作是 GitHub Actions 平台的一个自定义的应用,它会执行一个复杂但是需要频繁重复的作业。使用动作可以减少重复代码。比如一个 action 可以实现从 GitHub 拉取你的 git 仓库,为你的构建环境创建合适的工具链等。
你可以写自己的动作,或者在 GitHub 市场里面去找已经实现好的动作。
工作流中定义的持续集成意思是由很多操作组成,比如说抓取代码、运行测试、登录远程服务器,发布到第三方服务等等。GitHub 都把这些操作就称为 actions。
很多操作在不同项目里面是类似的,完全可以共享的。GitHub团队 注意到了这一点,想出了一个很妙的点子,允许每个开发者把每个操作写成独立的脚本文件,存放到代码仓库,使得其他开发者可以引用。
如果你需要某个 action,不必自己写复杂的脚本,直接引用他人写好的 action 即可,整个持续集成过程,就变成了一个 actions 的组合。这就是 GitHub Actions 最特别的地方了。
GitHub 做了一个官方市场,可以搜索到他人提交的 actions。另外,还有一个 awesome actions 的仓库,也可以找到不少 action 如下图。
githu actions自动化操作 - 图2
上面说了,每个 action 就是一个独立脚本,因此可以做成代码仓库,使用 userName/repoName 的语法引用 action。事实上,GitHub 官方的 actions 都放在 github.com/actions 里面。
既然 actions 是代码仓库,当然就有了版本的概念,用户可以引用某个具体版本的 action。下面都是合法的 action 引用,用的就是 Git 的指针概念,详见官方文档。

  1. actions/setup-node@74bc508# 指向一个 commit
  2. actions/setup-node@v1.0 # 指向一个标签
  3. actions/setup-node@master # 指向一个分支

5 运行器(vmare Operator)

一个运行器是一个可以运行任务的服务。每一个运行器一次只运行一个单独的任务。GitHub 提供 Ubuntu Linux,Microsoft Windows 和 macOS 运行器,每一个工作流都运行在一个独立新建的虚拟机中。如果说你需要一个不同的操作系统,你可以自定义运行器。具体请查看「自定义运行器」。

6 创建一个工作流

GitHub Actions 使用 YAML 语法定义工作流。每一个工作流具体保存为一个独立的 YAML 文件,目录是 .github/workflows。
现在我们在代码仓库创建一个示例工作流,当代码被推送的时候,肯定会自动执行一系列的命令。在这个示例工作流中,GitHub Actions 会检测出提交的代码,安装依赖,运行 bats -v:
(1) 在你的仓库,首先要创建一个 .github/workflows/ 目录
(2) 在 .github/workflows/ 目录,创建一个文件,名为 learn-github-actions.yml ,添加下面的代码:

  1. name: learn-github-actions
  2. on: [push]
  3. jobs:
  4. check-bats-version:
  5. runs-on: ubuntu-latest
  6. steps:
  7. - uses: actions/checkout@v2
  8. - uses: actions/setup-node@v2
  9. with:
  10. node-version: '14'
  11. - run: npm install -g bats
  12. - run: bats -v

(3) 提交这些改动,在 windows 本地推送到你的 GitHub 仓库。
你的新 GitHub Actions 工作流文件就会被安装在你的仓库,当有人提交代码的时候,工作流就会自动执行。关于一个任务的执行历史,具体查看「查看工作流活动」章节。

7 理解工作流文件

为了帮助你理解 YAML 语法,这节会解释例子中的每行代码:

  1. name: learn-github-actions

这个你可选,是工作流的名字,会出现在 GitHub 仓库的 Actions 选项栏里。

  1. on: [push]

指定工作流的触发事件。这个例子里,使用是 push 事件,当有人提交了一个代码修改或者合并了一个 pull request ,工作流就会触发。提交到每个分支都会被触发,如果你想在指定分支、路径、标签,需要查看 「GitHub Actions 工作流语法」;

  1. jobs:

将运行在 learn-github-actions 工作流的所有任务分组在一起。

  1. check-bats-version:

这个定义了一个名为 check-bats-version 的任务,子键(child key)会定义该任务的属性。

  1. runs-on: ubuntu-latest

配置任务运行在最新的 Ubuntu Linux 运行器,你看的懂这个。

  1. steps:

将 check-bats-version 任务下的所有步骤分为一组,嵌套的每一个条目都是一个独立的 action 或者 shell 脚本。

  1. - uses: actions/checkout@v2

uses 关键字指定了这个步骤运行 actions/checkout 动作的 v2 大版本 。这是一个可以检出仓库代码到运行器的动作,它允许你运行脚本或者其他动作侵入你的代码(比如说构建或者测试工具)。

  1. - uses: actions/setup-node@v2
  2. with:
  3. node-version: '14'

这个步骤会使用 actions/setup-node@v2 动作安装指定版本的 Node.js ,自动在你的 PATH 加上 node 和 npm 命令。

  1. run: npm install -g bats

run 关键字会告诉任务在运行器上执行一个命令。在这个例子中,你正在使用 npm 安装 bats 软件测试包。

  1. - run: bats -v

最终,你运行 bats 命令,传一个可以打印软件版本的参数。

8 可视化工作流文件

在这个图表,你可以看到你刚创建的工作流文件,以及这些 GitHub Actions 组件是如何组织的。每一个步骤都会执行一个独立的动作或者脚本文件。任务1 和 2 是运行命令,任务3 和 任务4 是运行脚本文件。找到更多预构建的动作,查看 「查找和自定义动作」。
githu actions自动化操作 - 图3

9 查看工作流活动

一旦你的工作流开始运行,你可以在 GitHub 看到一个可视化的运行进度图表 ,查看每一个步骤的执行情况。
在 GitHub.com ,导航至仓库主主页 在你的仓库名下,点击 Actions。
githu actions自动化操作 - 图4
在左侧 sidebar,点击你想查看的工作流
在 Workflow runs,点击你想查看的运行记录的名称:
在 Jobs 或者在可视化图表中,点击你想看到的任务:
githu actions自动化操作 - 图5
查看每一个步骤的结果:
githu actions自动化操作 - 图6

完成自动同步

我们也可以利用 Github Actions,写一个工作流,在发现 Github 博客仓库的 gh-pages 分支代码更新后,自动同步当前代码到 Gitee 上。
关于 Github Actions 的详细介绍,可以参考阮一峰老师的 《GitHub Actions 入门教程》。
详细介绍可以看这里(https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html)
为了实现 Gitee 和 Github 的同步,我们需要借助叫 action 的东西,还好业界已经有现成的实现了,这里我采用的是 Hub Mirror Action,其实就在actions市场找的,我们可以看到使用的示例代码:

  1. steps:
  2. - name: Mirror the Github organization repos to Gitee.
  3. uses: Yikun/hub-mirror-action@master
  4. with:
  5. src: github/shenshuai89
  6. dst: gitee/shenshuai89
  7. dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
  8. dst_token: ${{ secrets.GITEE_TOKEN }}
  9. account_type: org

其中有四个必填项:

  • src 表示需要被同步的源端账户名,即我们 Github 的账户名,因为我的 Github ID 是 shenshuai89,所以这里我应该改成 github/shenshuai89。
  • dst 表示需要同步到的目的端账户名,即我们 Gitee 的账户名,因为我的 Gitee ID 也是 shenshuai89,所以这里我应该改成 gitee/shenshuai89。
  • dst_key 表示用于在目的端上传代码的私钥,然后将其保存在 Secrets 中。

具体的操作步骤如下:
获取私钥:
cat ~/.ssh/id_rsa

githu actions自动化操作 - 图7
复制你的私钥内容,然后在要同步的 Github 仓库中,选择 “Setting” -> “Secrets” -> “New repository secret”
githu actions自动化操作 - 图8
填入 Secret 内容,Name 命名为 “GITEE_PRIVATE_KEY”,Value 为复制的内容
然后点击 Add secret 即可。
githu actions自动化操作 - 图9
dst_token 创建仓库的API tokens, 用于自动创建不存在的仓库。这里我们从 Gitee 上获取,具体地址为 https://gitee.com/profile/personal_access_tokens。生成并复制 Token,然后同样的步骤。
保存在 Github 的 Secrets 中,Name 为 “GITEE_TOKEN” 那么我们就可以在仓库建立的根目录下,建立目录 .github/workflows ,然后创建一个名为syncToGitee.yml 的文件如下:

  1. name: syncToGitee
  2. on:
  3. push:
  4. branches:
  5. - gh-pages
  6. jobs:
  7. repo-sync:
  8. runs-on: ubuntu-latest
  9. steps:
  10. - name: Mirror the Github organization repos to Gitee.
  11. uses: Yikun/hub-mirror-action@master
  12. with:
  13. src: 'github/mqyqingfeng'
  14. dst: 'gitee/mqyqingfeng'
  15. dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
  16. dst_token: ${{ secrets.GITEE_TOKEN }}
  17. static_list: "blog"
  18. force_update: true
  19. debug: true

这个里面,我们定义了一个名为 syncToGitee 的工作流,指定代码提交到分支 gh-pages 才能触发工作流。
任务下只有一个名为 repo-sync 的任务,运行在 ubuntu-latest, 具体的步骤下,也只有一个名为 Mirror the Github organization repos to Gitee 的步骤,使用了 Yikun/hub-mirror-action@master 动作,而 with 里的内容则是该动作需要的一些参数。
其中,static_list 表示单一仓库同步,force_update 为 true 表示启用 git push -f 强制同步,debug 为 true 表示启用 debug 开关,会显示所有执行命令。
当我们把这样的文件提交到 Github,Github 会自动检测并运行该脚本。但是现在还有几个问题要注意:
因为咱们是提交到 Github 的 gh-pages 分支上,这个文件和目录需要写在 gh-pages 分支, 观察咱们的脚本代码,我们就会发现,每次我们 sh deploy.sh 的时候,都是编译代码到 dist 目录,然后重新 git init ,最后强制提交。所以我们在项目的根目录建立 .github/woorkflows/syncToGitee.yml 并没有什么卵用,一来提交的是 dist 目录里的代码,二来是每次还都会清空重新编译生成代码提交。
为此,我们可以在脚本里添加代码,每次编译完后,再拷贝外层的 .github/woorkflows/syncToGitee.yml 到 dist 目录里,再提交到 Github 上,完美了。
所以我们依然在项目根目录添加目录和文件,此时的文件结构如下:

  1. .
  2. ├─ docs
  3. ├─ README.md
  4. └─ .vuepress
  5. └─ config.js
  6. └─ .github
  7. └─ workflows
  8. └─ syncToGitee.yml
  9. └─ package.json
  10. └─ deploy.sh

脚本文件代码如下:

  1. #!/usr/bin/env sh
  2. # 确保脚本抛出遇到的错误
  3. set -e
  4. # 生成静态文件
  5. npm run docs:build
  6. # 进入生成的文件夹
  7. cd docs/.vuepress/dist
  8. # 拷贝目录和文件
  9. cp -r ../../../.github ./
  10. git init
  11. git add -A
  12. git commit -m 'deploy'
  13. # 如果发布到 https://<USERNAME>.github.io/<REPO>
  14. git push -f git@github.com:Datalong/blog.git master:gh-pages
  15. cd -

此时我们再运行 sh deploy.sh 代码提交到 Github,就可以在仓库的 Actions 中看到运行记录
执行时间大概一分钟左右,Gitee 的代码就会自动同步。
到此这里,我们完成了 Github 代码自动同步 Gitee 的问题

Gitee如何部署Pages

在上面,咱们使用 GitHub Actions 解决了 GitHub 代码自动同步 Gitee 的问题,但我们的博客仓库代码同步到 Gitee 后,并不能像 GitHub 一样自动部署 Pages,如果不使用付费的 Gitee Pages Pro 服务,那我们该怎么实现 Gitee 自动部署 Pages 呢?

GitHub Actions

答案还是接着使用 GitHub Actions!你可能会想,Gitee 也有 GitHub Actions 服务吗? Gitee 也会像 GitHub 一样检测 .github/workflows/ 目录下的 YAML 文件,然后执行吗?
这当然是不可能的啦,Gitee 并不会支持 GitHub 的这套方式,但我们为什么一定要借用 Gitee 的能力呢?我们在 GitHub Actions 中,模拟登陆 Gitee,点击项目的部署按钮,不也是一种实现方式吗?

搜索 Actions

我们接下来去找一些合适的 GitHub Actions,我们可以在 GitHub 的官方市场【1】,或者 awesome actions仓库【2】,再或者直接在 GitHub 搜索比如 gitee pages actions 之类的关键词。
githu actions自动化操作 - 图10
最终,我们决定使用 Gitee Pages Action【4】,查看一下主页的示例代码:

  1. name: Sync
  2. on:
  3. push:
  4. branches: [main]
  5. workflow_dispatch:
  6. jobs:
  7. build:
  8. runs-on: ubuntu-latest
  9. steps:
  10. - name: Sync to Gitee
  11. uses: wearerequired/git-mirror-action@master
  12. env:
  13. # 注意在 Settings->Secrets 配置 GITEE_RSA_PRIVATE_KEY
  14. SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }}
  15. with:
  16. # 注意替换为你的 GitHub 源仓库地址
  17. source-repo: git@github.com:doocs/leetcode.git
  18. # 注意替换为你的 Gitee 目标仓库地址
  19. destination-repo: git@gitee.com:Doocs/leetcode.git
  20. - name: Build Gitee Pages
  21. uses: yanglbme/gitee-pages-action@main
  22. with:
  23. # 注意替换为你的 Gitee 用户名
  24. gitee-username: yanglbme
  25. # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
  26. gitee-password: ${{ secrets.GITEE_PASSWORD }}
  27. # 注意替换为你的 Gitee 仓库,仓库名严格区分大小写,请准确填写,否则会出错
  28. gitee-repo: doocs/leetcode
  29. # 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在)
  30. branch: main

我们之前已经实现了 GitHub 代码同步 Gitee,这里我们直接使用后半部分的自动部署 actions,结合上篇的 YAML 文件代码,最终的修改如下:

  1. name: syncToGitee
  2. on:
  3. push:
  4. branches:
  5. - gh-pages
  6. jobs:
  7. repo-sync:
  8. runs-on: ubuntu-latest
  9. steps:
  10. - name: Mirror the Github organization repos to Gitee.
  11. uses: Yikun/hub-mirror-action@master
  12. with:
  13. src: 'github/dist'
  14. dst: 'gitee/dist'
  15. dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
  16. dst_token: ${{ secrets.GITEE_TOKEN }}
  17. static_list: "blog"
  18. force_update: true
  19. debug: true
  20. - name: Build Gitee Pages
  21. uses: yanglbme/gitee-pages-action@main
  22. with:
  23. # 注意替换为你的 Gitee 用户名
  24. gitee-username: Datalong
  25. # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
  26. gitee-password: ${{ secrets.GITEE_PASSWORD }}
  27. # 注意替换为你的 Gitee 仓库,仓库名严格区分大小写,请准确填写,否则会出错
  28. gitee-repo: Datalong/blog
  29. # 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在)
  30. branch: gh-pages

注意不要忘了在仓库的设置里添加 Secrets,输入 Gitee 的登陆密码,然后保存名为 GITEE_PASSWORD
githu actions自动化操作 - 图11
YAML 文件语法报错 如果 Actions 运行失败并出现了这种错误:
githu actions自动化操作 - 图12
这是因为你的 YAML 语法写的有问题,可能是哪里没有对齐。可以在这个网址[5]校验下你的 YAML 文件,也可以顺便看下阮一峰老师的 YAML 语言教程[6]。
再次运行 修改了代码之后,我们可以再执行一遍 sh deploy.sh,然后在 GitHub 上查看运行情况:
githu actions自动化操作 - 图13
当运行成功,我们再查看 Gitee 的地址,就会发现已经部署为最新的版本了。
githu actions自动化操作 - 图14
至此,实现了 GitHub 和 Gitee 代码的同步与自动部署。

10个 GitHub Actions 进阶技巧

1. workflow 执行时,传入参数

在执行 workflow 时, 允许在 GitHub Actions 页面输入参数,控制执行逻辑。我们可以将人工处理的逻辑,在 GitHub Actions 参数化执行,适用于持续部署场景。

  1. on:
  2. workflow_dispatch:
  3. inputs:
  4. logLevel:
  5. description: 'Log level'
  6. required: true
  7. default: 'warning'
  8. tags:
  9. description: 'Test scenario tags'
  10. jobs:
  11. printInputs:
  12. runs-on: ubuntu-latest
  13. steps:
  14. - run: |
  15. echo "Log level: ${{ github.event.inputs.logLevel }}"
  16. echo "Tags: ${{ github.event.inputs.tags }}"

上面的 workflow 执行时,会弹出如下对话框。
image.png

2. Job 编排控制执行顺序

一个 workflow 由很多个 job 组成,借助于 needs 参数,我们可以管理这些 job 之间的依赖,控制其执行流程。

  1. on: push
  2. jobs:
  3. job1:
  4. runs-on: ubuntu-latest
  5. steps:
  6. - run: echo "job1"
  7. job2:
  8. runs-on: ubuntu-latest
  9. steps:
  10. - run: sleep 5
  11. needs: job1
  12. job3:
  13. runs-on: ubuntu-latest
  14. steps:
  15. - run: sleep 10
  16. needs: job1
  17. job4:
  18. runs-on: ubuntu-latest
  19. steps:
  20. - run: echo "job4"
  21. needs: [job2, job3]

上面的 workflows 执行时,job2 和 job3 会等 job1 执行成功时才执行,job4 会等 job2 和 job3 执行成功时才执行。
image.png

3. 用于项目管理

Kubernetes 基于 ChatOps 使用 Prow 协调社区有序协作。但并不是每个团队,都愿意搭建并维护一套 Prow 机器人系统。ChatOps 实现的核心是事件驱动,这在 GitHub 中使用 Actions 也能实现。
下面是几个项目管理相关的 action

  • 根据修改的目录添加标签 ```yaml
  • uses: actions/labeler@main with: repo-token: “${{ secrets.GITHUB_TOKEN }}”

    1. 在配置文件 .github/workflows/labeler.yml 中添加规则,给对 docs 目录进行修改的 Pull Requests(以下简称 PR) 自动添加 docs_label 标签:
    2. ```yaml
    3. docs_label:
    4. - ./docs/*
  • 根据标签添加 Issues 到 Projects

使用 srggrs/assign-one-project-github-action , 我们可以将新增的 Issues 或者 PR 添加到指定的 Projects 中。

  1. - name: Assign NEW issues and NEW pull requests to project 2
  2. uses: srggrs/assign-one-project-github-action@1.2.0
  3. if: github.event.action == 'opened'
  4. with:
  5. project: 'https://github.com/srggrs/assign-one-project-github-action/projects/2'

也可以将包含指定标签的 Issues 或 PR 添加到指定 Project 的指定 Column 中。

  1. - name: Assign issues and pull requests with `bug` label to project 3
  2. uses: srggrs/assign-one-project-github-action@1.2.0
  3. if: |
  4. contains(github.event.issue.labels.*.name, 'bug') ||
  5. contains(github.event.pull_request.labels.*.name, 'bug')
  6. with:
  7. project: 'https://github.com/srggrs/assign-one-project-github-action/projects/3'
  8. column_name: 'Labeled'
  • 清理长时间无人跟进的 Issues

如果一个 Issue 长达 30 天没有更新,那么下面的 workflow 将会再等 5 天,然后将其关闭。

  1. name: 'Close stale issues and PRs'
  2. on:
  3. schedule:
  4. - cron: '30 1 * * *'
  5. jobs:
  6. stale:
  7. runs-on: ubuntu-latest
  8. steps:
  9. - uses: actions/stale@v3
  10. with:
  11. stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
  12. days-before-stale: 30
  13. days-before-close: 5

GitHub 上的项目管理,主要是围绕 Issues、Projects、Labels、Pull Requests 展开,可以在 GitHub Actions 的 Marketplace 中搜索相关的 Action 使用。

4. 在线调试

在使用 GitHub Actions 的过程中,如果需要登录到 Runner 上调试命令,那么下面这个技巧你一定会感兴趣。

  1. - uses: shaowenchen/debugger-action@v2
  2. name: debugger
  3. timeout-minutes: 30
  4. continue-on-error: true
  5. with:
  6. ngrok_token: ${{ secrets.NGROK_TOKEN }}

只需要去 Ngrok 官网申请一个 token,就可以通过 ssh 远程登录到 Runner。当然,也可以暴露 Runner 上的服务,提供外网访问的链接,最长可达 6 小时。
image.png
在执行日志中,我们可以找到 ssh 的登录链接,使用 root/root 即可登录 Runner。如果配置了 web 的端口映射,还可以查看到相关的服务链接。

5. 设置缓存

缓存能有效地加快构建速度,减少网络请求,复用中间码。这对于 Java、Nodejs、Python 等项目,非常有用。

  1. - name: Get yarn cache directory path
  2. id: yarn-cache-dir-path
  3. run: echo "::set-output name=dir::$(yarn cache dir)"
  4. - uses: actions/cache@v2
  5. id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
  6. with:
  7. path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
  8. key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
  9. restore-keys: |
  10. ${{ runner.os }}-yarn-

6. 检测项目中的问题链接

项目维护时间长了之后,最令人头疼的就是文档。研发、测试跟进的是代码、功能,而文档却时常无人更新。缺少维护的文档,会让潜在参与者流失。下面这个 Action 能检测文档中的 Broken 链接。

  1. name: Check Markdown links
  2. on: push
  3. jobs:
  4. markdown-link-check:
  5. runs-on: ubuntu-latest
  6. steps:
  7. - uses: actions/checkout@master
  8. - uses: gaurav-nelson/github-action-markdown-link-check@v1
  9. with:
  10. use-quiet-mode: 'yes'
  11. config-file: '.github/workflows/checklink_config.json'
  12. max-depth: 3

gaurav-nelson/github-action-markdown-link-check 支持自定义配置,非常灵活易用,堪称必备 Action。
下面是一个 .github/workflows/checklink_config.json 的示例:

  1. {
  2. "replacementPatterns": [
  3. {
  4. "pattern": "^/",
  5. "replacement": "/github/workspace/"
  6. }
  7. ],
  8. "aliveStatusCodes": [
  9. 429,
  10. 200
  11. ]
  12. }

最后在 GitHub Actions 日志页面,会输出这样的检测结果:

  1. =========================> MARKDOWN LINK CHECK <=========================
  2. FILE: ./docs/governance.md
  3. 4 links checked.
  4. FILE: ./docs/configuration/cri.md
  5. [✖] https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable
  6. 7 links checked.
  7. ERROR: 1 dead links found!
  8. [✖] https://build.opensuse.org/project/show/devel:kubic:libcontainers:stable → Status: 404
  9. FILE: ./docs/configuration/kubeedge.md
  10. 21 links checked.
  11. =========================================================================

7. Job 批量执行,参数排列组合执行任务

数据驱动测试的场景下,可以通过输入的参数控制测试的流程。在 GitHub Actions 中,我们也可以通过参数化的方式,批量地执行或编排流程。
GitHub Actions 会将 matrix 中的每个参数排列组合,产生一个新的运行实例。

  1. on: push
  2. jobs:
  3. node:
  4. runs-on: ${{ matrix.os }}
  5. strategy:
  6. matrix:
  7. os: [ubuntu-16.04, ubuntu-18.04]
  8. node: [6, 8, 10]
  9. steps:
  10. - uses: actions/setup-node@v1
  11. with:
  12. node-version: ${{ matrix.node }}
  13. - run: node --version

上面的 workflow 执行时, 会执行 6 个 job。
image.png
无论是用来测试兼容性, 还是批量执行 Job, 都是非常好的。

8. 拷贝 Action 的 Badge 状态显示在文档中

通常,我们使用 GitHub Actions 对项目进行代码分析、执行测试、编译、打包、构建、推送镜像等。这些行为对于保证项目的稳定,至关重要。
但并不是每个人都会关注 Actions 的执行细节。我们可以在显眼的地方,给出这些过程的最终实时状态,以提醒用户和开发者。如果 main 分支构建失败了,能提醒用户谨慎使用,能提醒研发尽快修复问题。
在 GitHub Actions 页面中, 点击 Create status badge。
image.png
将弹框中的 URL 链接,增加在 Readme 文档中,即可实时快速地查看到 workflow 的执行结果。
image.png

9. 精准 hook GitHub 上的行为

workflow 通过 on 关键字定义触发条件。 主要有三类触发事件:

  • 人工触发

    1. on: workflow_dispatch
  • 定时触发

    1. on:
    2. schedule:
    3. - cron: '*/15 * * * *'
  • Webhook 触发

在 GitHub 上的操作,比如创建 Issues、新增 Deployment 等,都能够通过 API 获取到相关的事件。通过这些事件,我们可以精准地定制 workflow 的行为。通常我们都是基于 push 或者 pull requests 触发,下面列举几个不常见的示例:

  1. on:
  2. fork
  1. on:
  2. watch:
  3. types: [started]
  1. on:
  2. issues:
  3. types: [opened]

10. 开发一个 Action 很简单

如果在 Marketplace 找不到合适的 Action,那么自己开发 Action 也是一个不错的选择。
其实,开发一个 Action 没有想象中那么难。一个 Action 就是一个处理逻辑,接收输入参数,执行一定的逻辑,然后输出参数。有三种类型的 Action:

  • Docker container, 适用 Linux 系统
  • JavaScript, 适用 Linux、macOS、Windows 系统
  • Composite run steps, 适用 Linux, macOS, Windows 系统

    Docker container

    通过 Docker 容器,提供 Action 的执行逻辑处理。比如下面这个例子:
    Dockerfile ```dockerfile FROM appleboy/drone-scp:1.6.2-linux-amd64

ADD entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT [“/entrypoint.sh”]

  1. **entrypoint.sh**
  2. ```shell
  3. #!/bin/sh
  4. set -eu
  5. [ -n "$INPUT_STRIP_COMPONENTS" ] && export INPUT_STRIP_COMPONENTS=$((INPUT_STRIP_COMPONENTS + 0))
  6. sh -c "/bin/drone-scp $*"

通过 dron-scp 镜像,快速开发了一个提供 scp 文件拷贝的 Action。

JavaScript

通过执行 JavaScript 处理 Action 逻辑。官方提供了 JavaScript 和 TypeScript 的 Action 模板。在创建项目时,使用模板创建,然后编写处理逻辑,发布自己的 Action 即可。
GitHub Actions 提供了工具包,以支持这种方式的扩展,例如执行命令、操作 GitHub 等,都可以通过引用包,直接调用相关函数实现。下面是其中几个工具包:

  1. @actions/exec, 执行命令
  2. @actions/core, 输入、输出、日志、秘钥相关
  3. @actions/io, 操作文件

Composite run steps

这种类型,允许将一连串的 Shell 操作作为一个 Action 使用。

  1. name: 'Hello World'
  2. description: 'Greet someone'
  3. inputs:
  4. who-to-greet: # id of input
  5. description: 'Who to greet'
  6. required: true
  7. default: 'World'
  8. outputs:
  9. random-number:
  10. description: "Random number"
  11. value: ${{ steps.random-number-generator.outputs.random-id }}
  12. runs:
  13. using: "composite"
  14. steps:
  15. - run: echo Hello ${{ inputs.who-to-greet }}.
  16. shell: bash
  17. - id: random-number-generator
  18. run: echo "::set-output name=random-id::$(echo $RANDOM)"
  19. shell: bash
  20. - run: ${{ github.action_path }}/goodbye.sh
  21. shell: bash

https://github.com/actions/typescript-action
https://github.com/shaowenchen/debugger-action