如何使用 GitHub Actions

简介

GitHub Actions 是 GitHub 在 2018 年推出的持续集成服务。它可以自动完成一些开发周期内的任务,如 Push 代码时自动编译,Pull 代码时自动执行测试脚本等等。

我了解 GitHub Actions 的契机是,我在 GitHub 上保存了一些 Markdown 文档,我希望每次更新文档后自动使用 Pandoc 转换成 PDF 文档。接下来我们一起学习如何通过 GitHub Actions 实现这样的需求。

首先我们先直观的了解一下它在 GitHub 的位置,如果打开一个仓库,它有图中绿色对号√,或者红色叉号×,说明这个项目配置了 GitHub Actions,绿色表示自动化的流程运行成功了,红色表示失败了。

我们点开Actions按钮就可以查看具体的任务详情。下面我们先学习如何配置一个简单的 GitHub Actions。

配置 GitHub Actions

GitHub Actions 可以简单理解为一些自动化脚本,工具,目的就是为了减少重复工作,所以这些工具都可以做成普适性的工具。而 GitHub 官方就开放了一个这类工具的市场,我们可以在上面搜索自己想要的工具。因为初学 GitHub Actions 所以也不知道怎么写配置文件,我们可以直接搜索一个并应用它,看看别人是怎么写的。

我们进入一个自己的仓库,点击Actions,搜索框中搜索PDF,在搜索结果中找到Create PDF · Actions这个工具。如果搜索到点击Configure。如果显示未找到,则点击set up a workflow yourself,同样搜索PDF

打开详情页面,拉到底,将Example usage。里的内容复制到编辑框中。点击右上角Start commit将会把我们新建的main.yml提交到仓库中。这就相当于创建了一个生成 PDF 的 GitHub Actions。当然每个 Actions 都有一些使用要求,比如这里还要根据介绍,创建几个文件夹,比如从哪个文件夹获取源文件,生成后的 PDF 又会放到哪个文件夹等。这里就不再介绍,我们先了解如何创建一个 Actions。

Workflow 配置

GitHub Actions 的配置文件叫做 workflow 文件,存放在代码仓库的.github/workflows 目录。

workflow 文件采用 YAML 格式,文件名可以任意取,但是后缀名统一为.yml or .yaml,比如 foo.yml or foo.yaml。一个库可以有多个 workflow 文件。GitHub 只要发现.github/workflows 目录里面有.yml or .yaml 文件,就会自动运行该文件(并行)。

接下来我们逐个参数来解释都有哪些功能。

on

触发 workflow 的 GitHub 事件的名称。比如push代码时触发,其他人fork代码仓时触发等等。

可以只有一个事件触发,

on: push

也可有多个事件触发,使用列表列举,

on: [push, fork]

所有支持的事件列表,请查看官方文档

on.[push|fork].[tags|branches]

注意:从这里开始就会出现一个字段下有子字段,每个点号.分割一个子字段。如push或者fork可以作为on的子字段,tags或者branches可以作为push或者fork的子字段。在yaml文件中,缩进很重要,每个缩进都表示是从属关系,表示是该字段的子字段。千万要注意缩进关系,如果缩进出错,那么将无法解析yaml文件。

指定触发事件时,可以限定分支或标签。

on:
  push:
    branches:
      - master

上面代码指定,只有 master 分支发生 push 事件时,才会触发 workflow。

name

工作流程的名称。GitHub 在仓库的操作页面上显示工作流程的名称。如果省略 name,GitHub 将其设置为相对于仓库根目录的工作流程文件路径。

jobs

workflow 运行包括一项或多项 jobs。jobs 默认是并行运行。要按顺序运行作业,可以使用 [job_id].needs 关键词在其他 job 上定义依赖项。

每个作业在 runs-on 指定的运行器环境中运行。

jobs.[job_id]

jobs 中的每个任务都有一个[job_id] ,且其必须为 jobs 对象中唯一的字符串键值[job_id]必须以字母或_开头,并且只能包含字母数字字符、-_

jobs:
  first_job:  # [job_id],任务 id
    name: My first job
  second_job:
    name: My second job

jobs.[job_id].[runs-on]

runs-on 字段指定运行所需要的虚拟机环境。它是必填字段。目前可用的虚拟机如下。

- ubuntu-latest,ubuntu-18.04或ubuntu-16.04
- windows-latest,windows-2019或windows-2016
- macOS-latest或macOS-10.14

下面代码指定虚拟机环境为 ubuntu-18.04。

runs-on: ubuntu-18.04

jobs.[job_id].name

workflow 文件的主体是 jobs 字段,表示要执行的一项或多项任务。

job_id 里面的 name 字段是任务的说明。它可以在网页端的 UI 上显示。

jobs:
  first_job:  
    name: My first job  # [job_name],任务名称
  second_job:
    name: My second job

jobs.[job_id].needs

needs 字段指定当前任务的依赖关系,即运行顺序。

jobs:
  job1:
  job2:
    needs: job1
  job3:
    needs: [job1, job2]

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

jobs.[job_id].steps

steps 字段指定每个 Job 的运行步骤,可以包含一个或多个步骤。每个步骤都可以指定以下三个字段。

- jobs.[job_id].steps.name:步骤名称。
- jobs.[job_id].steps.run:该步骤运行的命令或者 action。
- jobs.[job_id].steps.env:该步骤所需的环境变量。

下面是一个完整的 workflow 文件的范例。

name: Greeting from Mona
on: push

jobs:
  my-job:
    name: My Job
    runs-on: ubuntu-latest
    steps:
      - name: Print a greeting
        env:
          MY_VAR: Hi there! My name is
          FIRST_NAME: Mona
          MIDDLE_NAME: The
          LAST_NAME: Octocat
        run: |
          echo $MY_VAR $FIRST_NAME $MIDDLE_NAME $LAST_NAME.

上面代码中,steps 字段只包括一个步骤。该步骤先注入四个环境变量,然后执行一条 Bash 命令。

jobs.[job_id].steps[*].uses

选择一个 action,可以理解为若干 steps.run,有利于代码复用。这也是 github action 最主要的功能。

比如最常用的,下载本仓库的代码到工作区,就是使用的一个 action 完成的:

steps:
  - name: Check out Git repository
    uses: actions/checkout@v2

注:@v2 什么意思?
表示 Action 的版本。我们如果不带版本号的话,就是默认使用最新版本。Github 官方强烈要求我们带上版本号。这样子的话,我们就不会出现:写好一个 Workflow,但是由于某个 Action 的作者一更新,我们的 Workflow 就崩了的问题

jobs.[job_id].steps.run

在 shell 中执行的命令:

steps:
    - uses: actions/checkout@v2
    - name: create dir
        id: dir
        run: |
            mkdir output  # create output dir

以上配置是在下载完本仓库的代码后,在仓库根目录新建一个output文件夹。注意run:后的|表示可以多行命令。如果没有|表示只能执行一条命令。

jobs.[job_id].steps.working-directory

用来指定在run命令在哪执行。

- name: Create dir
  run: mkdir output
  working-directory: ./build

jobs.[job_id].steps.shell

用来指定 shell 类型,如 Python,bash,powershell 等。

steps:
  - name: Display the path
    run: echo $PATH
    shell: bash

所有支持的类型请查看官方文档

如何跳过 GitHub Actions

在 commit message 中只要包含了下面几个关键词就会跳过 Github Actions。

[skip ci]
[ci skip]
[no ci]
[skip actions]
[actions skip]

实例:自动使用 Pandoc 将 Markdown 文件转换为 PDF

Dunky-Z/uefi-spec-zh项目中使用的 GitHub Actions 为例,解释如何实现将 Markdown 文件转换为 PDF。

# CI 名为 MPPL
name: MPPL

# 在 Push 代码时触发 CI
on: push

jobs:
  # 任务名称为 convert_via_pandoc
  convert_via_pandoc:
    # 在 ubuntu-latest 系统上运行
    runs-on: ubuntu-latest
    steps:
      # 步骤一:下载最新代码
      - uses: actions/checkout@v2
      # 步骤二:在项目根目录建立 output 文件夹放生成的 PDF 文件
      - name: create file list
        id: files_list
        run: |
          mkdir output  # create output dir
      # 步骤三:更新项目的子模块
      - name: Git Sumbodule Update
        run: |
          git submodule update --init --remote --recursive
      # 步骤四:为运行的系统中安装需要的字体,因为原系统没有需要的中文字体
      # 字体来源为项目目录的MPPL/fonts
      - name: add fonts
        run: |
          sudo apt-get install ttf-mscorefonts-installer
          sudo apt-get install fontconfig
          fc-list :lang=zh
          ls -lh /usr/share/fonts/
          cp -rf ./MPPL/fonts/* /usr/share/fonts/
          mkfontscale
          mkfontdir
          fc-cache
          fc-list
      # 步骤五:安装 pandoc 和 texlive
      - name: install pandoc
        run: |
          sudo apt-get update
          sudo apt-get install texlive-full
          sudo apt-get install pandoc
          sudo apt-get clean
      # 步骤六:使用 pandoc 命令生成 pdf
      - name: build pdf
        run: |
          cd src
          pandoc -f  markdown-auto_identifiers  --listings --pdf-engine=xelatex --template=../MPPL/templates/mppl.tex  --output=../output/UEFI规范-中文.pdf *.md
      # 步骤七:将生成的结果上传到 GitHub
      - uses: actions/upload-artifact@master
        with:
          name: output
          path: output

注意事项

every step must define a uses or run key
every step must define a uses or run key · Issue #2 · einaregilsson/beanstalk-deploy

参考

GH actions: a step cannot have both the uses and run keys · Issue #318 · fhem/mod-Buienradar

every step must define a uses or run key · Issue #2 · einaregilsson/beanstalk-deploy