Github Actions 备忘清单

本备忘单总结了 Github Actions 常用的配置说明,以供快速参考。

入门

介绍

GitHub Actions 的仓库中自动化、自定义和执行软件开发工作流程,有四个基本的概念,如下:

:- :-
workflow (工作流程) 持续集成一次运行的过程,就是一个 workflow
job (任务) 一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务
step (步骤) 每个 job 由多个 step 构成,一步步完成
action (动作) 每个 step 可以依次执行一个或多个命令(action)

  • 采用 YAML 格式定义配置文件
  • 存放在代码仓库的 .github/workflows 目录中
  • 后缀名统一为 .yml,比如 ci.yml
  • 一个库可以有多个 workflow 文件
  • 根据配置事件自动运行配置文件

配置文件

```yaml {3,5,10} name: GitHub Actions Demo on: push: branches:

  1. - main

任务

jobs: build: runs-on: ubuntu-latest

  1. # 步骤 根据步骤执行任务
  2. steps:
  3. - uses: actions/checkout@v3
  4. - uses: actions/setup-node@v3
  5. with:
  6. node-version: 16
  7. - run: npm install
  8. - run: npm run build
  1. 存放到 `.github/workflows` 目录中,命名为 `ci.yml`,当 `push` 代码到仓库 `main` 分支中,该配置自动运行配置。
  2. ### 指定触发
  3. <!--rehype:wrap-class=row-span-2-->
  4. `push` 事件触发 `workflow`
  5. ```yaml
  6. on: push

push 事件或 pull_request 事件都可以触发 workflow

  1. on: [push, pull_request]

只有在 main 分支 push 事件触发 workflow

```yaml {2} on: push: branches:

  1. - main
  1. `push` 事件触发 `workflow``docs` 目录下的更改 `push` 事件不触发 `workflow`
  2. ```yaml {2,4}
  3. on:
  4. push:
  5. paths-ignore:
  6. - 'docs/**'

push 事件触发 workflow,包括 sub-project 目录或其子目录中的文件触发 workflow,除非该文件在 sub-project/docs 目录中,不触发 workflow

  1. on:
  2. push:
  3. paths:
  4. - 'sub-project/**'
  5. - '!sub-project/docs/**'

版本发布为 published 时运行工作流程。

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

多项任务

  1. jobs:
  2. my_first_job: # 第一个任务
  3. name: My first job
  4. my_second_job: # 第二个任务
  5. name: My second job

通过 jobs (jobs.<job_id>.name)字段,配置一项或多项需要执行的任务

多项任务依赖关系

通过 needs (jobs.<job_id>.needs)字段,指定当前任务的依赖关系

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

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

多项任务传递参数

```yml {2,5,9,11,15} jobs: job1: runs-on: ubuntu-latest

  1. # 将步骤输出映射到作业输出
  2. outputs:
  3. output1: ${{ steps.step1.outputs.test }}
  4. output2: ${{ steps.step2.outputs.test }}
  5. steps:
  6. - id: step1
  7. run: echo "::set-output name=test::hello"
  8. - id: step2
  9. run: echo "::set-output name=test::world"

job2: runs-on: ubuntu-latest needs: job1 steps:

  1. - run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}
  1. ### 指定每项任务的虚拟机环境
  2. ```yml
  3. runs-on: ubuntu-latest

指定运行所需要的虚拟机环境,⚠️ 它是必填字段

```yml {3} jobs: build: # 任务名称 runs-on: ubuntu-latest # 虚拟机环境配置

  1. ---
  2. - `Windows Server 2022` _(windows-latest)_ _(windows-2022)_
  3. - `Ubuntu 20.04` _(ubuntu-latest)_ _(ubuntu-20.04)_
  4. - `macOS Monterey 12` _(macos-12)_
  5. - `macOS Big Sur 11` _(macos-latest)_,_(macos-11)_
  6. <!--rehype:className=style-arrow-->
  7. 另见: [选择 GitHub 托管的运行器](https://docs.github.com/cn/actions/using-workflows/workflow-syntax-for-github-actions#选择-github-托管的运行器)
  8. ### 指定每项任务的步骤
  9. 每个步骤都可以指定以下三个字段
  10. ```shell
  11. jobs.<job_id>.steps.name # 步骤名称
  12. # 该步骤运行的命令或者 action
  13. jobs.<job_id>.steps.run
  14. # 该步骤所需的环境变量
  15. jobs.<job_id>.steps.env

steps 字段指定每个 Job 的运行步骤,可以包含一个或多个步骤(steps)

```yml {4} jobs: build: runs-on: ubuntu-latest steps:

  1. - uses: actions/checkout@v3
  2. - uses: actions/setup-node@v3
  3. with:
  4. node-version: 16
  5. - run: npm install
  6. - run: npm run build
  1. ### 环境变量
  2. ```shell
  3. jobs.<job_id>.environment

使用单一环境名称的示例

  1. environment: staging_environment

使用环境名称和 URL 的示例

  1. environment:
  2. name: production_environment
  3. url: https://github.com

自定义环境变量

GitHub 会保留 GITHUB_ 环境变量前缀供 GitHub 内部使用。设置有 GITHUB_ 前缀的环境变量或密码将导致错误。

  1. - name: 测试 nodejs 获取环境变量
  2. env:
  3. API_TOKEN: ${{ secrets.API_TOKEN }}

https://github.com/<用户名>/<项目名称>/settings/secrets 中添加 secrets API_TOKEN,在工作流中设置环境变量 API_TOKEN

表达式

if 条件下使用表达式时,可以省略表达式语法 (${{ }}),因为 GitHub 会自动将 if 条件作为表达式求值

```yml {3} steps:

  • uses: actions/hello-world-action@v1.1 if: github.repository == ‘uiw/uiw-repo’

    if: ${{ }}

    ```

设置环境变量的示例

  1. env:
  2. MY_ENV_VAR: ${{ <expression> }}

操作符

  • ( ) (逻辑分组)
  • [ ] (指数)
  • . (属性取消引用)
  • ! (不是)
  • < (少于)
  • <= (小于或等于)
  • > (比…更棒)
  • >= (大于或等于)
  • == (平等的)
  • != (不相等)
  • && (和)
  • || (或者)

Github 上下文

属性名称 类型 描述
github (object) 工作流程中任何作业或步骤期间可用的顶层上下文。
github.event (object) 完整事件 web 挂钩有效负载。 更多信息请参阅“触发工作流程的事件”。
github.event_path (string) 运行器上完整事件 web 挂钩有效负载的路径。
github.workflow (string) 工作流程的名称。 如果工作流程文件未指定 name,此属性的值将是仓库中工作流程文件的完整路径。
github.job (string) 当前作业的 job_id。
github.run_id (string) 仓库中每个运行的唯一编号。 如果您重新执行工作流程运行,此编号不变。
github.run_number (string) 仓库中特定工作流程每个运行的唯一编号。 此编号从 1(对应于工作流程的第一个运行)开始,然后随着每个新的运行而递增。 如果您重新执行工作流程运行,此编号不变。
github.actor (string) 发起工作流程运行的用户的登录名。
github.repository (string) 所有者和仓库名称。 例如 Codertocat/Hello-World。
github.repository_owner (string) 仓库所有者的名称。 例如 Codertocat。
github.event_name (string) 触发工作流程运行的事件的名称。
github.sha (string) 触发工作流程的提交 SHA。
github.ref (string) 触发工作流程的分支或标记参考。
github.head_ref (string) 工作流程运行中拉取请求的 head_ref 或来源分支。 此属性仅在触发工作流程运行的事件为 pull_request 时才可用。
github.base_ref (string) 工作流程运行中拉取请求的 base_ref 或目标分支。 此属性仅在触发工作流程运行的事件为 pull_request 时才可用。
github.token (string) 代表仓库上安装的 GitHub 应用程序进行身份验证的令牌。 这在功能上等同于 GITHUB_TOKEN 密码。 更多信息请参阅“使用 GITHUB_TOKEN 验证身份”。
github.workspace (string) 使用 checkout 操作时步骤的默认工作目录和仓库的默认位置。
github.action (string) 正在运行的操作的名称。 在当前步骤运行脚本时,GitHub 删除特殊字符或使用名称 run。 如果在同一作业中多次使用相同的操作,则名称将包括带有序列号的后缀。 例如,运行的第一个脚本名称为 run1,则第二个脚本将命名为 run2。 同样,actions/checkout 第二次调用时将变成 actionscheckout2。

Github 上下文是访问有关工作流运行、运行器环境、作业和步骤的信息的一种方式

默认环境变量

环境变量 描述
CI 始终设置为 true
HOME 用于存储用户数据的 GitHub 主目录路径。 例如 /github/home
GITHUB_WORKFLOW 工作流程的名称。
GITHUB_RUN_ID 仓库中每个运行的唯一编号。 如果您重新执行工作流程运行,此编号不变。
GITHUB_RUN_NUMBER 仓库中特定工作流程每个运行的唯一编号。 此编号从 1(对应于工作流程的第一个运行)开始,然后随着每个新的运行而递增。 如果您重新执行工作流程运行,此编号不变。
GITHUB_ACTION 操作唯一的标识符 (id)。
GITHUB_ACTIONS 当 GitHub 操作 运行工作流程时,始终设置为 true。 您可以使用此变量来区分测试是在本地运行还是通过 GitHub 操作 运行。
GITHUB_ACTION_PATH GitHub 操作所在的路径
GITHUB_ACTOR 发起工作流程的个人或应用程序的名称。 例如 octocat
GITHUB_API_URL 返回 API URL。例如:https://api.github.com
GITHUB_REPOSITORY 所有者和仓库名称。 例如 octocat/Hello-World
GITHUB_EVENT_NAME 触发工作流程的 web 挂钩事件的名称
GITHUB_EVENT_PATH 具有完整 web 挂钩事件有效负载的文件路径。 例如 /github/workflow/event.json
GITHUB_WORKSPACE GitHub 工作空间目录路径。 如果您的工作流程使用 actions/checkout 操作,工作空间目录将包含存储仓库副本的子目录。 如果不使用 actions/checkout 操作,该目录将为空。 例如 /home /runner/work/my-repo-name/my-repo-name
GITHUB_SHA 触发工作流程的提交 SHA。 例如 ffac537e6cbbf9
GITHUB_REF 触发工作流程的分支或标记参考。 例如 refs/heads/feature-branch-1。 如果分支或标记都不适用于事件类型,则变量不会存在
GITHUB_HEAD_REF 仅为复刻的仓库设置。头部仓库的分支
GITHUB_BASE_REF 仅为复刻的仓库设置。基础仓库的分支

另见: 默认环境变量

直接常量

作为表达式的一部分,可以使用 boolean, null, numberstring数据类型

  1. env:
  2. myNull: ${{ null }}
  3. myBoolean: ${{ false }}
  4. myIntegerNumber: ${{ 711 }}
  5. myFloatNumber: ${{ -9.2 }}
  6. myHexNumber: ${{ 0xff }}
  7. myExponentialNumber: ${{ -2.99e-2 }}
  8. myString: Mona the Octocat
  9. myStringInBraces: ${{ 'It''s source!' }}

函数 contains

使用字符串的示例

  1. contains('Hello world', 'llo') // 返回 true

使用对象过滤器的示例返回 true

  1. contains(github.event.issue.labels.*.name, 'bug')

另见: 函数 contains

函数 startsWith

  1. startsWith('Hello world', 'He') // 返回 true

另见: 函数 startsWith,此函数不区分大小写

函数 format

  1. format('{{Hello {0} {1} {2}!}}', 'Mona', 'the', 'Octocat')
  2. // 返回 '{Hello Mona the Octocat!}'.

另见: 函数 format

函数 join

  1. join(github.event.issue.labels.*.name, ', ')
  2. // 也许返回 'bug, help wanted'.

另见: 函数 join

函数 toJSON

  1. toJSON(job)
  2. // 也许返回 { "status": "Success" }.

另见: 函数 toJSON

函数

:- :-
fromJSON 返回 JSON 对象或 JSON 数据类型的值 #
hashFiles 返回与路径模式匹配的文件集的单个哈希 #
success 当前面的步骤都没失败或被取消时返回 true #
always 使步骤始终执行,返回 true 即使取消也是如此 #
cancelled 如果工作流被取消,则返回 true #
failure 当作业的任何先前步骤失败时返回 true #

函数 success()

  1. steps:
  2. ...
  3. - name: The job has succeeded
  4. if: ${{ success() }}

函数 failure()

  1. steps:
  2. ...
  3. - name: The job has failed
  4. if: ${{ failure() }}

常用实例

获取版本信息

  1. - name: Test
  2. run: |
  3. # Strip git ref prefix from version
  4. echo "${{ github.ref }}"
  5. # VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
  6. # # Strip "v" prefix from tag name
  7. # [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
  8. echo "$VERSION"

提交到 gh-pages 分支

  1. - name: Deploy
  2. uses: peaceiris/actions-gh-pages@v3
  3. with:
  4. github_token: ${{secrets.GITHUB_TOKEN}}
  5. publish_dir: ./build

修改 package.json

  1. - name: Modify Version
  2. shell: bash
  3. run: |
  4. node -e 'var pkg = require("./package.json"); pkg.version= (new Date().getFullYear().toString().substr(2)) + "." + (new Date().getMonth() + 1) + "." + (new Date().getDate()); require("fs").writeFileSync("./package.json", JSON.stringify(pkg, null, 2))'

使用 github-action-package 修改 name 字段

  1. - name: package.json info
  2. uses: jaywcjlove/github-action-package@main
  3. with:
  4. rename: '@wcj/github-package-test'

克隆带有 Submodule 的仓库

  1. - name: Checkout
  2. uses: actions/checkout@v3
  3. with:
  4. path: main
  5. submodules: true

submodulestrue 检出子模块或 recursive 递归检出子模块

  1. - name: Clone sub repository
  2. shell: bash
  3. run: |
  4. auth_header="$(git config --local --get http.https://github.com/.extraheader)"
  5. # git submodule sync --recursive
  6. # git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --remote --force --recursive --checkout ant.design

步骤依赖作业

使用 jobs.<job_id>.needs 识别在此作业运行之前必须成功完成的任何作业。它可以是一个字符串,也可以是字符串数组。 如果某个作业失败,则所有需要它的作业都会被跳过,除非这些作业使用让该作业继续的条件表达式。

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

在此示例中,job1 必须在 job2 开始之前成功完成,而 job3 要等待 job1job2 完成。此示例中的作业按顺序运行:

  1. job1
  2. job2
  3. job3

配置如下

  1. jobs:
  2. job1:
  3. job2:
  4. needs: job1
  5. job3:
  6. if: ${{ always() }}
  7. needs: [job1, job2]

在此示例中,job3 使用 always() 条件表达式,因此它始终在 job1job2 完成后运行,不管它们是否成功。

同步 Gitee

  1. - name: Sync to Gitee
  2. run: |
  3. mirror() {
  4. git clone "https://github.com/$1/$2"
  5. cd "$2"
  6. git remote add gitee "https://jaywcjlove:${{ secrets.GITEE_TOKEN }}@gitee.com/uiw/$2"
  7. git remote set-head origin -d
  8. git push gitee --prune +refs/remotes/origin/*:refs/heads/* +refs/tags/*:refs/tags/*
  9. cd ..
  10. }
  11. mirror uiwjs uiw

提交 NPM 包

  1. - run: npm publish --access public
  2. env:
  3. NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

获取 NPM_TOKEN,可以通过 npm 账号创建 token

  1. npm token list [--json|--parseable] # 查看
  2. npm token create [--read-only] [--cidr=1.1.1.1/24,2.2.2.2/16] # 创建
  3. npm token revoke <id|token> # 撤销

可以使用 JS-DevTools/npm-publish 提交

  1. - name: 📦 @province-city-china/data
  2. uses: JS-DevTools/npm-publish@v1
  3. with:
  4. token: ${{ secrets.NPM_TOKEN }}
  5. package: packages/data/package.json

它有个好处,检测 package.json 中版本号是否发生变更,来决定是否提交版本,不会引发流程错误。

步骤作业文件共享

Artifacts 是 GitHub Actions 为您提供持久文件并在运行完成后使用它们或在作业(文档)之间共享的一种方式。

要创建工件并使用它,您将需要不同的操作:上传和下载。 要上传文件或目录,您只需像这样使用它:

  1. steps:
  2. - uses: actions/checkout@v2
  3. - run: mkdir -p path/to/artifact
  4. - run: echo hello > path/to/artifact/a.txt
  5. - uses: actions/upload-artifact@v2
  6. with:
  7. name: my-artifact
  8. path: path/to/artifact/a.txt

然后下载 artifact 以使用它:

  1. steps:
  2. - uses: actions/checkout@v2
  3. - uses: actions/download-artifact@v2
  4. with:
  5. name: my-artifact

Node.js

  1. - name: Setup Node
  2. uses: actions/setup-node@v2
  3. with:
  4. node-version: 14

使用矩阵策略 在 nodejs 不同版本中运行

  1. strategy:
  2. matrix:
  3. node-version: [10.x, 12.x, 14.x]
  4. steps:
  5. - uses: actions/checkout@v2
  6. - name: 使用 Node ${{ matrix.node-version }}
  7. uses: actions/setup-node@v1
  8. with:
  9. node-version: ${{ matrix.node-version }}
  10. - run: npm ci
  11. - run: npm run build --if-present
  12. - run: npm test

提交 docker 镜像

  1. # https://www.basefactor.com/github-actions-docker
  2. - name: Docker login
  3. run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
  4. - name: Build ant.design image
  5. run: |
  6. cd ./ant\.design
  7. docker build -t ant.design .
  8. - name: Tags & Push docs
  9. run: |
  10. # Strip git ref prefix from version
  11. VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
  12. # Strip "v" prefix from tag name
  13. [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
  14. docker tag ant.design ${{ secrets.DOCKER_USER }}/ant.design:$VERSION
  15. docker tag ant.design ${{ secrets.DOCKER_USER }}/ant.design:latest
  16. docker push ${{ secrets.DOCKER_USER }}/ant.design:$VERSION
  17. docker push ${{ secrets.DOCKER_USER }}/ant.design:latest

创建一个 tag

  1. - name: Create Tag
  2. id: create_tag
  3. uses: jaywcjlove/create-tag-action@main
  4. with:
  5. package-path: ./package.json

根据 package-path 指定的 package.json 检测 version 是否发生变化来创建 tag

生成 git 提交日志

  1. - name: Generate Changelog
  2. id: changelog
  3. uses: jaywcjlove/changelog-generator@main
  4. with:
  5. filter-author: (小弟调调™)
  6. - name: Get the changelog
  7. run: echo "${{ steps.changelog.outputs.changelog }}"

提交到 GitHub docker 镜像仓库

  1. - name: '登录到 GitHub 注册表'
  2. run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
  3. - name: '编译 docker image'
  4. run: docker build -t ghcr.io/jaywcjlove/reference:latest .
  5. - name: '推送到 GitHub 注册表中'
  6. run: docker push ghcr.io/jaywcjlove/reference:latest
  7. - name: '标记 docker 镜像并发布到 GitHub 注册表'
  8. if: steps.create_tag.outputs.successful
  9. run: |
  10. echo "version: v${{ steps.changelog.outputs.version }}"
  11. docker tag ghcr.io/jaywcjlove/reference:latest ghcr.io/jaywcjlove/reference:${{steps.changelog.outputs.version}}
  12. docker push ghcr.io/jaywcjlove/reference:${{steps.changelog.outputs.version}}

提交 commit 到 master 分支

  1. - name: 生成一个文件,并将它提交到 master 分支
  2. run: |
  3. # Strip git ref prefix from version
  4. VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
  5. COMMIT=released-${VERSION}
  6. # Strip "v" prefix from tag name
  7. [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
  8. echo "输出版本号:$VERSION"
  9. # 将版本输出到当前 VERSION 文件中
  10. echo "$VERSION" > VERSION
  11. echo "1. 输出Commit:$commit"
  12. echo "2. Released $VERSION"
  13. git fetch
  14. git config --local user.email "action@github.com"
  15. git config --local user.name "GitHub Action"
  16. git add .
  17. git commit -am $COMMIT
  18. git branch -av
  19. git pull origin master
  20. - name: 将上面的提交 push master 分支
  21. uses: ad-m/github-push-action@master
  22. with:
  23. github_token: ${{ secrets.GITHUB_TOKEN }}

作业之间共享数据

创建一个文件,然后将其作为构件上传

```yml {11} jobs: example-job: name: Save output steps:

  1. - shell: bash
  2. run: |
  3. expr 1 + 1 > output.log
  4. - name: Upload output file
  5. uses: actions/upload-artifact@v3
  6. with:
  7. name: output-log-file
  8. path: output.log
  1. 可以下载名为 `output-log-file` 的工件
  2. ```yml {7}
  3. jobs:
  4. example-job:
  5. steps:
  6. - name: Download a single artifact
  7. uses: actions/download-artifact@v3
  8. with:
  9. name: output-log-file

指定运行命令的工作目录

```yml {3}

  • name: Clean temp directory run: rm -rf * working-directory: ./temp ```

使用 working-directory 关键字,您可以指定运行命令的工作目录(./temp)

defaults.run

```yml {4,5,7} jobs: job1: runs-on: ubuntu-latest defaults: run: shell: bash working-directory: scripts

  1. 作业中的所有 `run` 步骤提供默认的 `shell` `working-directory`
  2. ### jobs.<job_id>.steps[*].shell
  3. 使用 `bash` 运行脚本
  4. ```yml {4}
  5. steps:
  6. - name: Display the path
  7. run: echo $PATH
  8. shell: bash

运行 python 脚本

```yml {6} steps:

  • name: Display the path run: | import os print(os.environ[‘PATH’]) shell: python ```

您可以使用 shell 关键字覆盖运行器操作系统中的默认 shell 设置

一些 actions 推荐

:- :-
create-tag-action 根据 package.json 创建 Tag / Release
changelog-generator 生成 changelog 日志
github-action-modify-file-content 修改仓库文件内容
github-action-contributors 生成贡献(contributors.svg)图片
generated-badges 生成徽章(Badges)图片
coverage-badges-cli 生成覆盖率徽章(Badges)图片
action-ejs 基于 ejs 生成 HTML
github-action-package 修改 JSON 文件内容
markdown-to-html-cli Markdown 转换成 HTML
ncipollo/release-action 创建 Release
peaceiris/actions-gh-pages 将文件或文件夹内容提交到 gh-pages 分支

另见