目录
GitHub Actions教程与自动同步Fork仓库

前言

Github Ac­tions 是 GitHub 推出的持续集成 (Con­tin­u­ous in­te­gra­tion,简称 CI) 服务,它提供了配置非常不错的虚拟服务器环境,基于它可以进行构建、测试、打包、部署项目。简单来讲就是将软件开发中的一些流程交给云服务器自动化处理,比方说开发者把代码 push 到 GitHub 后它会自动测试、编译、发布。有了持续集成服务开发者就可以专心于写代码,其它乱七八糟的事情就不用管了,这样可以大大提高开发效率。本篇文章将介绍 GitHub Ac­tions 的基本使用方法。

基本概念

  • workflow (工作流程):持续集成一次运行的过程。

  • job (任务):一个 workflow 由一个或多个 job 构成,含义是一次持续集成的运行,可以完成多个任务。

  • step(步骤):每个 job 由多个 step 构成,一步步完成。

  • action (动作):每个 step 可以依次执行一个或多个命令(action)

虚拟环境

GitHub Ac­tions 为每个任务 (job) 都提供了一个虚拟机来执行,每台虚拟机都有相同的硬件资源:

  • 2-core CPU

  • 7 GB RAM 内存

  • 14 GB SSD 硬盘空间

使用限制:

  • 每个仓库只能同时支持20个 workflow 并行。

  • 每小时可以调用1000次 GitHub API 。

  • 每个 job 最多可以执行6个小时。

  • 免费版的用户最大支持20个 job 并发执行,macOS 最大只支持5个。

  • 私有仓库每月累计使用时间为2000分钟,超过后$ 0.008/分钟,公共仓库则无限制

操作系统方面可选择 Win­dows server、Linux、ma­cOS,并预装了大量软件包和工具。

虽然名称叫持续集成,但当所有任务终止和完成时,虚拟环境内的数据会随之清空,并不会持续。即每个新任务都是一个全新的虚拟环境。

workflow文件

GitHub Ac­tions 的配置文件叫做 work­flow 文件(官方中文翻译为 “工作流程文件”),存放在代码仓库的.github/workflows 目录中。work­flow 文件采用 YAML 格式,文件名可以任意取,但是后缀名统一为.yml。一个库可以有多个 work­flow 文件,GitHub 只要发现.github/workflows 目录里面有.yml 文件,就会按照文件中所指定的触发条件在符合条件时自动运行该文件中的工作流程。在 Ac­tions 页面可以看到很多种语言的 work­flow 文件的模版,可以用于简单的构建与测试。

下面是一个简单的 work­flow 文件示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
name: Hello World
on: push
jobs:
my_first_job:
name: My first job
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master
- name: Run a single-line script
run: echo "Hello World!"
my_second_job:
name: My second job
runs-on: macos-latest
steps:
- name: Run a multi-line script
env:
MY_VAR: Hello World!
MY_NAME: P3TERX
run: |
echo $MY_VAR
echo My name is $MY_NAME

name

name 字段是 work­flow 的名称。若忽略此字段,则默认会设置为 work­flow 文件名。

on

on 字段指定 work­flow 的触发条件,通常是某些事件,比如示例中的触发事件是 push,即在代码 push 到仓库后被触发。on 字段也可以是事件的数组,多种事件触发,比如在 pushpull_request 时触发:

1
on: [push, pull_request]

完整的事件列表,请查看官方文档。下面是一些比较常见的事件:

push 指定分支触发

1
2
3
4
on:
push:
 branches:
  - master

push tag 时触发

1
2
3
4
on:
push:
 tags:
 - 'v*'

定时触发

1
2
schedule:
- cron: 0 */6 * * *

发布 re­lease 触发

1
2
3
on:
release:
types: [published]

仓库被 star 时触发

1
2
3
on:
watch:
types: [started]

jobs

jobs 表示要执行的一项或多项任务。每一项任务必须关联一个 ID (job_id),比如示例中的 my_first_job 和 my_second_job。job_id 里面的 name 字段是任务的名称。job_id 不能有空格,只能使用数字、英文字母和 -_符号,而 name 可以随意,若忽略 name 字段,则默认会设置为 job_id

当有多个任务时,可以指定任务的依赖关系,即运行顺序,否则是同时运行。

1
2
3
4
5
6
jobs:
job1:
job2:
needs: job1
job3:
needs: [job1, job2]

上面代码中,job1 必须先于 job2 完成,而 job3 等待 job1job2 的完成才能运行。因此,这个 work­flow 的运行顺序依次为:job1job2job3

runs-on

runs-on 字段指定任务运行所需要的虚拟服务器环境,是必填字段,每个任务的虚拟环境都是独立的。目前可用的虚拟机如下:

虚拟环境 YAML workflow 标签
Windows Server 2019 windows-latest
Ubuntu 18.04 ubuntu-latest or ubuntu-18.04
Ubuntu 16.04 ubuntu-16.04
macOS X Catalina 10.15 macos-latest

steps

steps 字段指定每个任务的运行步骤,可以包含一个或多个步骤。步骤开头使用 - 符号。每个步骤可以指定以下字段:

  • name:步骤名称。

  • uses:该步骤引用的action或 Docker 镜像。

  • run:该步骤运行的 bash 命令。

  • env:该步骤所需的环境变量。

其中 usesrun 是必填字段,每个步骤只能有其一。同样名称也是可以忽略的。

action

action 是 GitHub Ac­tions 中的重要组成部分,这点从名称中就可以看出,actionsaction 的复数形式。它是已经编写好的步骤脚本,存放在 GitHub 仓库中。

对于初学者来说可以直接引用其它开发者已经写好的 action,可以在官方 action仓库或者 GitHub Marketplace去获取。此外Awesome Actions这个项目收集了很多非常不错的 action

既然 action 是代码仓库,当然就有版本的概念。引用某个具体版本的 action

1
2
3
4
steps:
- uses: actions/setup-node@74bc508 # 指定一个 commit
- uses: actions/setup-node@v1.2 # 指定一个 tag
- uses: actions/setup-node@master # 指定一个分支

一般来说 action 的开发者会说明建议使用的版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# .github/workflow/文件名.yml
# 这是基础模板
# 这个 workflow 的名字,可以随意命名
name: Node.js CI
# on触发条件
on: [push]
# 1.push事件触发workflow
# 2.如果多个事件(on: [push,pull])
# 3.指定触发事件,可以限定分支、tag、指定文件路径(on.<push|pull_request>.<tags|branches|paths>)
# 在master分支push时触发
# push:
# branches:
# - master
# tags:
# - v1.0.0 # 指定tags版本更新
# - v1.*.* #指tags版本为1.n.n都会更新
# paths:
# - '**.js' # 所有的js文件更新时提交触发
# - 'doc/**' # doc下文件发生改动触发
# 4.忽略分支、tag、某一文件 branches-ignore、tags-ignore 、paths-ignore
# branches-ignore:
# - dev #当提交时分支为dev 不触发
# tags-ignore:
# - v2 #tag为v2时不触发
# 5. 计划的工作流在默认或基本分支上的最新提交上运行。可以运行计划的工作流程的最短间隔是每5分钟一次
# schedule:
# - cron: '*/5 * * * *'
# # * * * * * (minute (0 - 59)、hour (0 - 23)、day of the month (1 - 31)、month (1 - 12 or JAN-DEC)、day of the week (0 - 6 or SUN-SAT))
# # * 任何值 * * * * * 每天每一分钟运行。
# # , 值列表分隔符 2,10 4,5 * * * 在每天的第4和5小时的第2分钟和第10分钟运行。
# # -- 取值范围 0 4-6 * * * 在第4、5和6小时的第0分钟运行。
# # / 步长值 20/15 * * * * 从20分钟到59(每20、35和50分钟)开始,每15分钟运行一次。
jobs:
# 所有的 job 都是并行的,但往往会有依赖关系
# test:
# link:
# needs: test link依赖test
# 一个名为 build 的 job
build:
# runs-on指定运行所需要的虚拟机环境,必填
# ubuntu-latest指定Ubuntu GitHub托管的运行程序的最新版本。
# 也可以自己定义托管环境[self-hosted, linux, ARM32]
runs-on: ubuntu-latest
strategy: #strategy 定义一些矩阵供 job 使用
matrix:
node-version: [8.x, 10.x, 12.x]
steps:
# 获取源码
- name: Checkout
uses: actions/checkout@master # 获取master代码
with:
persist-credentials: false
- name: Install and Build
run: | #执行多个命令
npm install
npm run build
- name: Deploy
uses: JamesIves/github-pages-deploy-action@releases/v3 # 写好的action
with: #with为uses 的 action 传入参数,具体看你使用的 action 的说明
ACCESS_TOKEN: ${{ secrets.DEPLOY_KEY }} #自定义生成key 生成步骤在下面
BRANCH: gh-pages #操作应部署到的分支。
FOLDER: dist #操作应部署的文件夹。

自动同步Fork仓库

GitHub仓库上fork别人的项目,同步更新的时候就比较麻烦,要么是通过网页操作,要么克隆仓库后通过命令行操作等。利用GitHub Actions自动同步Fork仓库是个不错的选择。其中需要在项目Settings内Secrets添加GH_PERSONAL_ACCESS_TOKEN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
on:
push:
branches:
-master
schedule:
- cron: 0 */12 * * * # 每隔12小时
jobs:
update_external_airflow_fork:
runs-on: ubuntu-latest
steps:
- uses: TobKed/github-forks-sync-action@master
with:
github_token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} # 令牌
upstream_repository: luolongfei/freenom # 上游仓库
target_repository: leicancun/freenom # 你要推送的仓库
upstream_branch: master # 默认是拉取上游仓库的master分支
target_branch: master # 默认推送到你的仓库master分支
force: true # 是否强制推送
tags: true # 确定是否使用-tags

定时自动同步任务,亦可将Github的仓库镜像备份到Gitee,只需将GH_TOKEN改为Gitee生成的TOKEN。若报错Unshallow On Failed,删除run: git -C repo.git push --all downstream && git -C repo.git push --tags downstream这步,修改DEPTH值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
name: test

on:
push:
branches:
- master
# 忽略README.md
paths-ignore:
- 'README.md'
- 'LICENSE'
jobs:
sync:
name: Sync
runs-on: ubuntu-latest
steps:
- name: Clone
run: git clone --mirror --no-single-branch --depth=$DEPTH $SRC_REPO repo.git
env:
SRC_REPO: https://github.com/用户名/仓库名.git
DEPTH: 10
- name: Config DownStream
run: git -C repo.git remote add downstream "$PUSH_TARGET"
env:
PUSH_TARGET: https://用户名:${{ secrets.GH_TOKEN }}@github.com/用户名/仓库名
- name: Push DownStream
run: git -C repo.git push --all downstream && git -C repo.git push --tags downstream
- name: Try Unshallow On Failed
if: failure()
run: |
git -C repo.git fetch --unshallow origin || exit 1
git -C repo.git gc
git -C repo.git count-objects -vH
git -C repo.git push --all downstream && git -C repo.git push --tags downstream

Github上也有相关同步仓库的Actions项目,如https://github.com/repo-sync/github-synchttps://github.com/wei/git-sync等。

自动同步仓库Release

secrets.GITHUB_TOKEN可不用填写,保持默认。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
name: release
on:
schedule:
- cron: "35 14 * * *"
push:
branches:
- master
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout out project files
uses: actions/checkout@v2
with:
fetch-depth: 1

- name: Check and release
run: |
CORE_TAG_URL="https://api.github.com/repos/用户名/仓库名/releases/latest"
CORE_LATEST_VER=`curl -H "Accept: application/vnd.github.v3+json" -H "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" -s ${CORE_TAG_URL} --connect-timeout 5 | grep 'tag_name' | cut -d\" -f4`
if [[ ${CORE_LATEST_VER} != v* ]]; then
CORE_LATEST_VER=v${CORE_LATEST_VER}
fi
DIST_TAGS_URL="https://api.github.com/repos/${{ github.repository }}/tags"
DIST_TAG_FOUND=`curl -H "Accept: application/vnd.github.v3+json" -H "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" -s ${DIST_TAGS_URL} --connect-timeout 5 | grep "\"name\"\: \"${CORE_LATEST_VER}\""` || true
if [ -z ${DIST_TAG_FOUND} ]; then
rm -rf *
for file in $(curl -H "Accept: application/vnd.github.v3+json" -H "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" -sSL $CORE_TAG_URL | grep 'browser_download_url' | cut -d\" -f4); do
wget $file
done
git add .
git config user.name "用户名"
git config user.email "邮箱"
git commit -m "Version ${CORE_LATEST_VER}"
git tag -a "${CORE_LATEST_VER}" -m "Version ${CORE_LATEST_VER}"
git remote add release "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}"
git push -u --follow-tags release master
fi

参考

文章作者: Kylen Chan
文章链接: https://booku.ltd/posts/github-actions/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Kylen's Blog

评论