Skip to content

Github Actions

触发工作流的事件

环境变量

默认环境变量

在 Workflows 作业中,Github Actions 会注入一些环境变量到执行 Workflows 的运行容器中,有 CIGITHUB_*RUNNER_*CI 一直为 true,GITHUB_* 存储的是有关 github 的环境变量,RUNNER_* 存储的是作业容器环境的系统相关信息。

常见的环境变量有:

  • GITHUB_ACTOR:运行 Workflows 作业的用户或应用程序的名称,通常 Push,Pull Request 等操作触发 Workflows 都是用户名称,在 Workflows 中触发通常是应用程序的名称。
  • `
  • GITHUB_TOKEN: 针对 Workflows 作业临时生成的针对本仓库的访问令牌。

NOTE

每一次 Github Actions 工作流作业开始时,Github 都会创建唯一的 GITHUB_TOKEN 在这个工作流中进行身份验证,这个GITHUB_TOKEN 的生存时间只在这个工作流运行期间,或者最长 24 小时(考虑到即是一些复杂工作流运行时间较长,但也太可能要运行 24 小时)。且 GITHUB_TOKEN 的权限仅限于本仓库,并且可以在 仓库的 Settings > Actions > GeneralWorkflow permissions 中设置为对本仓库的可读或者可读可写权限。

全部环境变量参考 Github Actions 文档 默认环境变量

明文环境变量 除了可以在 Shell 中使用外,还可以通过 env 上下文,在 Workflows 配置文件中使用。

自定义变量

可以像 Dockefile 那样在文件中配置 ENV,将明文数据作为环境变量注入到容器中,在 Workflows 配置文件中明文配置的环境变量有个 3 个作用域,全局,jobs,steps。

yml
name: Greeting on variable day
on: workflow_dispatch
env: # 全局作用域
  DAY_OF_WEEK: Monday
jobs:
  greeting_job:
    runs-on: ubuntu-latest
    env: # jobs 作用域
      Greeting: Hello
    steps:
      - name: "Say Hello Mona it's Monday"
        run: echo "$Greeting $First_Name. Today is $DAY_OF_WEEK!"
        env: # steps 作用域
          First_Name: Mona
      - name: "Say 你好 it's Monday"
        if: ${{ env.DAY_OF_WEEK == 'Monday' }}
        run: echo "$Greeting $First_Name. Today is $DAY_OF_WEEK!"
        env:
          First_Name: Mona

也可以存储到 vars 上下文中,在 Settings > Security > Secrets and Variables > Actions 中添加 Variables,Variables 也是明文存储,可以在流水线中直接输出该环境变量明文内容。

在 Workflows 配置文件中使用 vars 上下文

yml
on:
  workflow_dispatch:
env:
  env_var: ${{ vars.ENV_CONTEXT_VAR }}
jobs:
  display-variables:
    name: ${{ vars.JOB_NAME }}

如果是私密数据,可以在仓库的 Settings > Security > Actions 中添加 Secrets,即是是在流水线中输出该环境变量,也是加密数据。

私密数据存储到密钥后,可以通过 secrets上下文 来使用,更多细节和安全使用方式参考 Github Actions 文档 使用机密

yml
steps:
  - name: Hello world action
    with: # Set the secret as an input
      super_secret: ${{ secrets.SuperSecret }}
    env: # Or as an environment variable
      super_secret: ${{ secrets.SuperSecret }}

提醒

自定义 Secrets 环境变量不能和默认环境变量名称相同,如果名称相同会被忽略。

上下文

上下文是可以在 Workflows 配置文件中作为表达式使用的,类似于模板变量,会将 Workflows 文件进行编译,替换模板变量,根据编译后的 Workflows 配置文件配置容器环境。 而环境变量是进入到容器后,可以通过 Shell 读取的值。

用户可以给予此特性,对 Workflows 配置文件进行逻辑编程,使得流程不仅是纯文本表达,还有一定执行逻辑性,参考 Github Actions 文档 上下文

串行/并行 jobs

jobs 选项是数组,可以配置多个 job,所有 job 默认并行运行,可以配置 job 运行之间的关系,使 job 可以依照依赖关系顺序串行的运行。

yml
jobs:
  setup:
    runs-on: ubuntu-latest
    steps:
      - run: ./setup_server.sh
  build:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - run: ./build_server.sh
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: ./test_server.sh

矩阵 jobs: 多版本测试

当一些公共库需要测试不同版本开发/生产/测试环境下的功能,可以使用矩阵任务,更多详细内容参考 Github Actions 文档 矩阵策略

yml
jobs:
  build:
    runs-on: ubuntu-latest
    # 给 build 任务设置成矩阵jobs,分别在 node.js 14 和 16版本下分别运行此 job
    strategy:
      matrix:
        node: [14, 16]
    # 如果测试版本很多,还可以控制并发数
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

工作流中触发事件

当 Github Actions 工作流内 使用 GITHUB_TOKEN push 推送内容到本仓库中,是不会触发 push 事件,导致工作流循环递归触发的,但是会触发 workflow-dispatchrepostory_dispatch 事件。并且用 GITHUB_TOKEN 的 GitHub Actions 工作流推送的提交不会触发 GitHub Pages 生成。

如何从一个仓库 Github Actions 工作流中 push 产物或者代码到另一个仓库呢?

比如,从一个私有仓库触发 Github Actions 工作流,然后推送到另外一个仓库如 GitHub Pages 仓库中,GITHUB_TOKEN 只有本仓库的权限,也就是只有这个私有仓库的权限,是没有办法 push 到另一个公共仓库的,所以需要创建一个 Github App token,用来将构建产物 commit 提交到公共仓库中。

Workflows 中执行脚本

通过 run 关键字来执行 shell 命令。

yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: npm install -g bats
      - name: 多行脚本
        run: | npm install -g \
          npm run build
      - name: 删除打包文件
        run: rm -rf .dist

或者将 shell 脚本写入到仓库的文件中,但是在 Github Actions 工作流中,如果没有使用 action/checkout@4 来下载仓库文件到工作流的虚拟服务器中是没有办法读取到 shell 文件的,所以需要特意指定目录,这样才能读取到脚本文件

yml
jobs:
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./scripts
    steps:
      - name: 多行脚本
        run: npm install -g && run build
      - name: 上传到服务器
        run: ./upload.sh
      - name: 删除脚本
        run: |
          ./do-something.sh
          ./delete-dist.sh

脚本执行权限问题

如果脚本没有执行权限,可以在本地 git update-index --chmod=+x PATH/TO/YOUR/script.sh,然后 commit 并且提交到仓库,这样脚本才可以在 Github Actions 容器中执行。

Github Actions 运行容器通常是 Linux,也有使用 Mac 的,这两种环境下不需要上述那样麻烦,直接在 Workflows 文件中给 shell 脚本文件添加执行权限。

yml
# ...
steps:
  - name: 多行脚本
    run: npm install -g && run build
  - run: chmod +x ./upload.sh
  - name: 上传到服务器
    run: ./upload.sh
# ...

jobs 之间共享数据

使用 actions/upaload-artifact

将 build Workflows 打包的文件通过 actions/upload-artifact@4 上传保存,使用 actions/download-artifact@4 下载保存的产物文件。

yml
jobs:
  build:
    name: Save output
    runs-on: ubuntu-latest
    steps:
      - shell: bash
        run: |
          expr 1 + 1 > output.log
      - name: Upload output file
        uses: actions/upload-artifact@v4
        with:
          name: output-log-file
          path: output.log
          retention-day: 5 # 自定义保留日期 5 天
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Download a single artifact
        uses: actions/download-artifact@v4
        with:
          name: output-log-file
yml

提示

多文件可以直接上传目录

yml
- name: Upload archive production artifacts
  uses: actions/upload-artifact@v4
  with:
    name: dist-without-markdown
    path: |
      dist
      !dist/**/*.md

更多或详细内容参考 Github Actions 文档 存储项目

使用 fromJSON 共享数据

参考 Github Actions 文档 表达式#fromJSON

yml
name: build
on: push
jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        run: echo "matrix={\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}" >> $GITHUB_OUTPUT
  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{ fromJSON(needs.job1.outputs.matrix) }}
    steps:
      - run: echo "Matrix - Project ${{ matrix.project }}, Config ${{ matrix.config }}"

缓存依赖

使用 actions/cache@v3 缓存一个 .npm 目录。

yml
jobs:
  example-job:
    steps:
      - name: Cache node modules
        uses: actions/cache@v3
        env:
          cache-name: cache-node-modules
        with:
          # 缓存目录
          path: ~/.npm
          # 缓存目录的 key
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          # 恢复key,使用此 key 来恢复缓存的文件
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-

更多详细内容,参考 Github Actions 文档 缓存依赖项