前言 Github Actions 是 GitHub 推出的持续集成 (Continuous integration,简称 CI) 服务,它提供了配置非常不错的虚拟服务器环境,基于它可以进行构建、测试、打包、部署项目。简单来讲就是将软件开发中的一些流程交给云服务器自动化处理,比方说开发者把代码 push 到 GitHub 后它会自动测试、编译、发布。有了持续集成服务开发者就可以专心于写代码,其它乱七八糟的事情就不用管了,这样可以大大提高开发效率。本篇文章将介绍 GitHub Actions 的基本使用方法。
基本概念
workflow (工作流程):持续集成一次运行的过程。
job (任务):一个 workflow 由一个或多个 job 构成,含义是一次持续集成的运行,可以完成多个任务。
step (步骤):每个 job 由多个 step 构成,一步步完成。
action (动作):每个 step 可以依次执行一个或多个命令(action)
虚拟环境 GitHub Actions 为每个任务 (job) 都提供了一个虚拟机来执行,每台虚拟机都有相同的硬件资源:
2-core CPU
7 GB RAM 内存
14 GB SSD 硬盘空间
使用限制:
每个仓库只能同时支持20个 workflow 并行。
每小时可以调用1000次 GitHub API 。
每个 job 最多可以执行6个小时。
免费版的用户最大支持20个 job 并发执行,macOS 最大只支持5个。
私有仓库每月累计使用时间为2000分钟,超过后$ 0.008/分钟,公共仓库则无限制
操作系统方面可选择 Windows server、Linux、macOS,并预装了大量软件包和工具。
虽然名称叫持续集成,但当所有任务终止和完成时,虚拟环境内的数据会随之清空,并不会持续。即每个新任务都是一个全新的虚拟环境。
workflow文件 GitHub Actions 的配置文件叫做 workflow 文件(官方中文翻译为 “工作流程文件”),存放在代码仓库的.github/workflows
目录中。workflow 文件采用 YAML 格式,文件名可以任意取,但是后缀名统一为.yml
。一个库可以有多个 workflow 文件,GitHub 只要发现.github/workflows
目录里面有.yml
文件,就会按照文件中所指定的触发条件在符合条件时自动运行该文件中的工作流程。在 Actions 页面可以看到很多种语言的 workflow 文件的模版,可以用于简单的构建与测试。
下面是一个简单的 workflow 文件示例:
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
字段是 workflow 的名称。若忽略此字段,则默认会设置为 workflow 文件名。
on
on
字段指定 workflow
的触发条件,通常是某些事件,比如示例中的触发事件是 push
,即在代码 push
到仓库后被触发。on
字段也可以是事件的数组,多种事件触发,比如在 push
或 pull_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 * * *
发布 release 触发
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
等待 job1
和 job2
的完成才能运行。因此,这个 workflow 的运行顺序依次为:job1
、job2
、job3
。
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
字段指定每个任务的运行步骤,可以包含一个或多个步骤。步骤开头使用 -
符号。每个步骤可以指定以下字段:
其中 uses
和 run
是必填字段,每个步骤只能有其一。同样名称也是可以忽略的。
action
action
是 GitHub Actions 中的重要组成部分,这点从名称中就可以看出,actions
是 action
的复数形式。它是已经编写好的步骤脚本,存放在 GitHub 仓库中。
对于初学者来说可以直接引用其它开发者已经写好的 action
,可以在官方 action仓库 或者 GitHub Marketplace 去获取。此外Awesome Actions 这个项目收集了很多非常不错的 action
。
既然 action
是代码仓库,当然就有版本的概念。引用某个具体版本的 action
:
1 2 3 4 steps: - uses: actions/setup-node@74bc508 - uses: actions/setup-node@v1.2 - 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 name: Node.js CI on: [push ]jobs: build: runs-on: ubuntu-latest strategy: matrix: node-version: [8. x , 10. x , 12. x ] steps: - name: Checkout uses: actions/checkout@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 with: ACCESS_TOKEN: ${{ secrets.DEPLOY_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 * * * 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 target_branch: master force: true tags: true
定时自动同步任务,亦可将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 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-sync
、https://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
参考