学习一下Github仓库的工作流语法,希望在Github仓库中自动执行测试。
重点关注两类项目所需要的基本测试工作流,分别是跨平台CMake项目和LaTex项目。
概述 
Github仓库提供工作流来自动化执行应用的部署,测试和发布等流程。工作流的实质是在Github服务器上提供了几个临时的虚拟环境(Docker),让用户在提交或其他Git行为后触发工作流,然后在虚拟机环境中自动执行相关的指令。
例如,可以使用一个工作流来构建和测试拉取请求,使用另一个工作流在每次创建版本时部署应用程序,
还有另一个工作流程在每次有人打开新问题时添加标签。
注意:
Github仓库支持多个工作流,它们可以同时触发或分别触发。 
Github对公开仓库提供的这类服务是无限制的,但是对私有仓库是受限的,每个月提供免费的时间额度和存储额度,超额需要付费。 
如果在仓库中触发的一个工作流运行失败了,Github可能通过邮件通知。 
 
一个典型的工作流(workflow)包含:
触发工作流的一个或多个事件 
一个或多个作业(job),每个作业都将在运行器机器上执行并运行一系列的一个或多个步骤(step),每个步骤都可以运行指定的脚本或操作(action) 
 
触发工作流的事件通常是:
Git仓库中发生的事件,例如推送到默认分支时、创建版本时 
定时触发或手动触发 
其他Github支持的触发行为 
 
工作流的配置文件是yaml格式文件,存储在.github/workflows/文件夹中,语法规则如下
示例如下
learn-github-actions.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 name:  learn-github-actions run-name:  ${{  github.actor  }}  is  learning  GitHub  Actions on:  [push ]jobs:   check-bats-version:      runs-on:  ubuntu-latest      steps:        -  uses:  actions/checkout@v4        -  uses:  actions/setup-node@v4          with:            node-version:  '20'        -  run:  npm  install  -g  bats        -  run:  bats  -v  
这个工作流会在代码推送事件发生时自动触发。它定义了一个名为
"check-bats-version" 的任务,将在最新的 Ubuntu
环境上运行,具体行为依次为:
Checkout:将代码从你的仓库检出到运行环境中。 
Setup Node:指定 Node.js 的版本为20。 
Install Bats:使用 npm 全局安装 Bats,它是一个用于测试 Bash
脚本的测试框架。 
Run Bats:最后执行 bats -v
命令。这个命令用于显示系统中安装的 Bats 版本。 
 
触发工作流 
常见的工作流触发逻辑是推送到main或者release,以及合并请求时触发,例如
1 2 3 4 5 on:   push:      branches:  [ main , release/**  ]   pull_request:      branches:  [ main , release/**  ] 
有时我们只需要在某些路径或文件发生更改时,才触发工作流,例如
1 2 3 4 5 6 on:   push:      branches:        -  'main'      paths:        -  'src/utils/**'  
这里同时使用了 branches 筛选器和 paths
筛选器,只在这两个筛选器都满足条件时触发工作流。
有时我们只需要在推送形如v1.**的标签时,触发工作流,例如
1 2 3 4 on:   push:      tags:        -  v1.**  
有时我们只是进行文档的更新,可以使用下面的格式来避免对应的修改触发测试工作流
1 2 3 4 5 6 on:   push:      paths-ignore:        -  'doc/**'        -  'docs/**'        -  '**.md'  
注意:工作流的触发逻辑是基于推送的,并不会只检查最新的commit,否则一次性推送多个commit就存在绕过代码检查的风险。
Cpp 项目 
CMake跨平台工作流 
下面是Github官方推荐的,针对跨平台CMake项目,在最新系统的三大编译器环境 中进行编译测试的工作流配置
(基于系统默认的编译器版本)
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 name:  CMake  on  multiple  platforms on:   push:      branches:  [ "main"  ]   pull_request:      branches:  [ "main"  ] jobs:   build:      runs-on:  ${{  matrix.os  }}      strategy:        fail-fast:  false        matrix:          os:  [ubuntu-latest , windows-latest ]         build_type:  [Release ]         c_compiler:  [gcc , clang , cl ]         include:            -  os:  windows-latest              c_compiler:  cl              cpp_compiler:  cl            -  os:  ubuntu-latest              c_compiler:  gcc              cpp_compiler:  g++            -  os:  ubuntu-latest              c_compiler:  clang              cpp_compiler:  clang++          exclude:            -  os:  windows-latest              c_compiler:  gcc            -  os:  windows-latest              c_compiler:  clang            -  os:  ubuntu-latest              c_compiler:  cl      steps:      -  uses:  actions/checkout@v3      -  name:  Set  reusable  strings        id:  strings        shell:  bash        run:  |          echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"     -  name:  Configure  CMake        run:  >          cmake -B ${{ steps.strings.outputs.build-output-dir }}         -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}         -DCMAKE_C_COMPILER=${{ matrix.c_compiler }}         -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}         -S ${{ github.workspace }}     -  name:  Build        run:  cmake  --build  ${{  steps.strings.outputs.build-output-dir  }}  --config  ${{  matrix.build_type  }}      -  name:  Test        working-directory:  ${{  steps.strings.outputs.build-output-dir  }}        run:  ctest  --build-config  ${{  matrix.build_type  }}  
上面的就是默认提供的配置文件,其实啥也不用改,只是清理了注释,当然也可以修改一下触发条件。
这个配置模板使用了矩阵,看起来比较高级,但是缺点是并没有指定具体的编译器版本,始终使用的是系统默认版本,这也意味着不能使用C++20的部分特性。
CMake跨平台工作流(最新版) 
下面提供的是基于最新版编译器(VS2022,gcc13和clang18)的测试工作流(已经足够支持C++20的基础使用)
pipeline-ci.yml,依次调用了三个具体的测试工作流 
bvt-msvc14.yml 
bvt-gcc13.yml 
bvt-clang18.yml 
 
配置文件是参考微软的proxy库的,将编译器版本修改为最新版。 这里
pipeline-ci 指持续集成(Continuous
Integration)中的一个流水线(Pipeline),bvt 指基本验证测试(Basic
Verification Test)。
 
配置文件 pipeline-ci.yml 具体如下
pipeline-ci.yml 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 name:  Test-CI on:   push:      branches:  [ "main"  ]     paths:        -  'src/**'        -  'test/**'    pull_request:      branches:  [ "main"  ]     paths:        -  'src/**'        -  'test/**'  env:   BUILD_TYPE:  Release  jobs:   run-bvt-gcc13:      uses:  ./.github/workflows/bvt-gcc13.yml      name:  run  bvt  with  g++  13    run-bvt-clang15:      uses:  ./.github/workflows/bvt-clang18.yml      name:  run  bvt  with  clang  18    run-bvt-msvc14:      uses:  ./.github/workflows/bvt-msvc14.yml      name:  run  bvt  with  msvc14  (vs2022)  
三个工作流是在不同编译器和环境下的基本测试,除了运行环境不同,以及预先下载配置指定的编译器,核心步骤都是一样的:生成,编译,进入构建目录,执行测试。
1 2 3 4 5 6 7 8 9 -  name:  build  with  cmake   run:  |      cmake . -B build     cmake --build ./build -j8 -  name:  run  tests   run:  |      cd ./build     ctest -j8 
需要注意的是对于MSVC,在ctest时需要明确构建类型,添加-C Release选项。
完整的工作流配置文件依次为
bvt-msvc14.yml 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 name:  bvt-msvc14 on:   workflow_call:      inputs:        branch:          type:  string          required:  false  jobs:   bvt-msvc14:      runs-on:  windows-2022      steps:      -  uses:  actions/checkout@v3        with:          ref:  ${{  inputs.branch  }}      -  name:  build  with  cmake        run:  |          cmake . -B build         cmake --build ./build -j8     -  name:  run  tests        run:  |          cd ./build         ctest -j8 -C Release 
bvt-gcc13.yml 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 name:  bvt-gcc13 on:   workflow_call:      inputs:        branch:          type:  string          required:  false  jobs:   bvt-gcc13:      runs-on:  ubuntu-latest      steps:      -  uses:  actions/checkout@v3        with:          ref:  ${{  inputs.branch  }}      -  name:  install  gcc  13        run:  |          sudo apt update         sudo apt install -y gcc-13 g++-13         sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 13         sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 13     -  name:  check  compiler  version        run:  g++  --version      -  name:  build  with  cmake        run:  |          cmake . -B build         cmake --build ./build -j8     -  name:  run  tests        run:  |          cd ./build         ctest -j8 
bvt-clang18.yml 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 name:  bvt-clang18 on:   workflow_call:      inputs:        branch:          type:  string          required:  false  jobs:   bvt-clang18:      runs-on:  ubuntu-22.04      steps:      -  uses:  actions/checkout@v3        with:          ref:  ${{  inputs.branch  }}      -  name:  install  clang  18        run:  |          wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -         sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main" -y         sudo apt update         sudo apt install -y clang-18         sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/clang-18 18         sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/clang++-18 18     -  name:  check  compiler  version        run:  g++  --version      -  name:  build  with  cmake        run:  |          cmake . -B build         cmake --build ./build -j8     -  name:  run  tests        run:  |          cd ./build         ctest -j8 
为了复用工作流,可以将上面的文件全部存放在某一个公开仓库中(fenglielie/cmakezero.git),然后在其它仓库就可以直接调用它,只需要写一个test-ci.yml,例如
test-ci.yml 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 name:  Test-CI on:   push:      branches:        -  'main'      paths:        -  'src/utils/**'        -  'test/utils/**'  env:   BUILD_TYPE:  Release  jobs:   run-bvt-gcc13:      uses:  fenglielie/cmakezero/.github/workflows/bvt-gcc13.yml@main      name:  run  bvt  with  g++  13    run-bvt-clang15:      uses:  fenglielie/cmakezero/.github/workflows/bvt-clang18.yml@main      name:  run  bvt  with  clang  18    run-bvt-msvc14:      uses:  fenglielie/cmakezero/.github/workflows/bvt-msvc14.yml@main      name:  run  bvt  with  msvc14  (vs2022)  
LaTeX 项目 
编译测试 
如果只需要保证LaTex项目可以顺利编译,可以参考下面的配置模板,这里使用XeLaTeX编译main.tex,并且设置工作目录为./latex/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 name:  Build  LaTeX  document on:   push:      branches:  [ main , release/**  ]   pull_request:      branches:  [ main , release/**  ] jobs:   build_release_latex:      runs-on:  ubuntu-latest      steps:        -  uses:  actions/checkout@v3        -  name:  Compile  LaTeX  document          uses:  xu-cheng/latex-action@v2          with:            working_directory:  ./latex            root_file:  main.tex            args:  -pdf  -xelatex  -file-line-error  -halt-on-error  -interaction=nonstopmode  
编译测试与发布 
如果对LaTeX项目有更多的需求:
将编译生成的PDF文件保留在Git仓库的指定分支(gh_actions_builds)中 
将编译生成的PDF文件添加到Release中 
 
配置示例如下
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 63 name:  Build  and  Release  LaTeX  document on:   push:      branches:  [ main  ]     tags:      -  'v*'    pull_request:      branches:  [ main  ]   workflow_dispatch:  jobs:   build_release_latex:      runs-on:  ubuntu-latest      steps:        -  uses:  actions/checkout@v3        -  name:  Compile  LaTeX  document          uses:  xu-cheng/latex-action@v2          with:            root_file:  main.tex            args:  -pdf  -xelatex  -file-line-error  -halt-on-error  -interaction=nonstopmode        -  name:  Stash  PDF          run:  |            mv main.pdf $HOME # cache the file       -  name:  Create  Branch          uses:  peterjgrainger/action-create-branch@v2.0.1          env:            GITHUB_TOKEN:  ${{  secrets.GH_LATEX_TEST_TOKEN  }}          with:            branch:  gh_actions_builds        -  name:  Checkout  gh_actions_builds  Branch          uses:  actions/checkout@v3          with:            ref:  gh_actions_builds        -  name:  Commit  PDF          run:  |            git config --local user.email "fenglielie@gmail.com"           git config --local user.name "fenglielie"           mv $HOME/main.pdf $(pwd) # bring it back           git add -f main.pdf           git commit -m "Updated by GitHub Action Automatically"       -  name:  Push  PDF          uses:  ad-m/github-push-action@master          with:            branch:  gh_actions_builds            force:  false            github_token:  ${{  secrets.GH_LATEX_TEST_TOKEN  }}        -  name:  Release          uses:  softprops/action-gh-release@v1          if:  startsWith(github.ref,  'refs/tags/' )          with:            files:  main.pdf          env:            GITHUB_TOKEN:  ${{  secrets.GH_LATEX_TEST_TOKEN  }}  
注意:由于需要提交,这里需要配置用户名和邮箱,创建和切换分支,并且需要在Github中设置并提供一个GITHUB_TOKEN,否则在虚拟环境中默认是没有权限对仓库进行任何修改操作的。
 
补充 
看到了一个对于非英文的issue自动翻译的workflow ,记录下来,以后可能有用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 name:  'issue-translator' on:   issue_comment:      types:  [created ]   issues:      types:  [opened ] jobs:   build:      runs-on:  ubuntu-latest      steps:        -  uses:  usthe/issues-translate-action@v2.7          with:            IS_MODIFY_TITLE:  false                                  CUSTOM_BOT_NOTE:  Issue  is  not  in  English.  It  has  been  translated  automatically.