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:
- main
任务
jobs: build: runs-on: ubuntu-latest
# 步骤 根据步骤执行任务steps:- uses: actions/checkout@v3- uses: actions/setup-node@v3with:node-version: 16- run: npm install- run: npm run build
存放到 `.github/workflows` 目录中,命名为 `ci.yml`,当 `push` 代码到仓库 `main` 分支中,该配置自动运行配置。### 指定触发<!--rehype:wrap-class=row-span-2-->`push` 事件触发 `workflow````yamlon: push
push 事件或 pull_request 事件都可以触发 workflow
on: [push, pull_request]
只有在 main 分支 push 事件触发 workflow
```yaml {2} on: push: branches:
- main
`push` 事件触发 `workflow`,`docs` 目录下的更改 `push` 事件不触发 `workflow````yaml {2,4}on:push:paths-ignore:- 'docs/**'
push 事件触发 workflow,包括 sub-project 目录或其子目录中的文件触发 workflow,除非该文件在 sub-project/docs 目录中,不触发 workflow
on:push:paths:- 'sub-project/**'- '!sub-project/docs/**'
版本发布为 published 时运行工作流程。
on:release:types: [published]
多项任务
jobs:my_first_job: # 第一个任务name: My first jobmy_second_job: # 第二个任务name: My second job
通过 jobs (jobs.<job_id>.name)字段,配置一项或多项需要执行的任务
多项任务依赖关系
通过 needs (jobs.<job_id>.needs)字段,指定当前任务的依赖关系
jobs:job1:job2:needs: job1job3:needs: [job1, job2]
上面配置中,job1 必须先于 job2 完成,而 job3 等待 job1 和 job2 的完成才能运行。因此,这个 workflow 的运行顺序依次为:job1、job2、job3
多项任务传递参数
```yml {2,5,9,11,15} jobs: job1: runs-on: ubuntu-latest
# 将步骤输出映射到作业输出outputs:output1: ${{ steps.step1.outputs.test }}output2: ${{ steps.step2.outputs.test }}steps:- id: step1run: echo "::set-output name=test::hello"- id: step2run: echo "::set-output name=test::world"
job2: runs-on: ubuntu-latest needs: job1 steps:
- run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}
### 指定每项任务的虚拟机环境```ymlruns-on: ubuntu-latest
指定运行所需要的虚拟机环境,⚠️ 它是必填字段
```yml {3} jobs: build: # 任务名称 runs-on: ubuntu-latest # 虚拟机环境配置
---- `Windows Server 2022` _(windows-latest)_ 或 _(windows-2022)_- `Ubuntu 20.04` _(ubuntu-latest)_ 或 _(ubuntu-20.04)_- `macOS Monterey 12` _(macos-12)_- `macOS Big Sur 11` _(macos-latest)_,_(macos-11)_<!--rehype:className=style-arrow-->另见: [选择 GitHub 托管的运行器](https://docs.github.com/cn/actions/using-workflows/workflow-syntax-for-github-actions#选择-github-托管的运行器)### 指定每项任务的步骤每个步骤都可以指定以下三个字段```shelljobs.<job_id>.steps.name # 步骤名称# 该步骤运行的命令或者 actionjobs.<job_id>.steps.run# 该步骤所需的环境变量jobs.<job_id>.steps.env
steps 字段指定每个 Job 的运行步骤,可以包含一个或多个步骤(steps)
```yml {4} jobs: build: runs-on: ubuntu-latest steps:
- uses: actions/checkout@v3- uses: actions/setup-node@v3with:node-version: 16- run: npm install- run: npm run build
### 环境变量```shelljobs.<job_id>.environment
使用单一环境名称的示例
environment: staging_environment
使用环境名称和 URL 的示例
environment:name: production_environmenturl: https://github.com
自定义环境变量
GitHub 会保留 GITHUB_ 环境变量前缀供 GitHub 内部使用。设置有 GITHUB_ 前缀的环境变量或密码将导致错误。
- name: 测试 nodejs 获取环境变量env:API_TOKEN: ${{ secrets.API_TOKEN }}
在 https://github.com/<用户名>/<项目名称>/settings/secrets 中添加 secrets API_TOKEN,在工作流中设置环境变量 API_TOKEN
表达式
在 if 条件下使用表达式时,可以省略表达式语法 (${{ }}),因为 GitHub 会自动将 if 条件作为表达式求值
```yml {3} steps:
设置环境变量的示例
env: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, number 或 string数据类型
env:myNull: ${{ null }}myBoolean: ${{ false }}myIntegerNumber: ${{ 711 }}myFloatNumber: ${{ -9.2 }}myHexNumber: ${{ 0xff }}myExponentialNumber: ${{ -2.99e-2 }}myString: Mona the OctocatmyStringInBraces: ${{ 'It''s source!' }}
函数 contains
使用字符串的示例
contains('Hello world', 'llo') // 返回 true
使用对象过滤器的示例返回 true
contains(github.event.issue.labels.*.name, 'bug')
另见: 函数 contains
函数 startsWith
startsWith('Hello world', 'He') // 返回 true
另见: 函数 startsWith,此函数不区分大小写
函数 format
format('{{Hello {0} {1} {2}!}}', 'Mona', 'the', 'Octocat')// 返回 '{Hello Mona the Octocat!}'.
另见: 函数 format
函数 join
join(github.event.issue.labels.*.name, ', ')// 也许返回 'bug, help wanted'.
另见: 函数 join
函数 toJSON
toJSON(job)// 也许返回 { "status": "Success" }.
另见: 函数 toJSON
函数
| :- | :- |
|---|---|
fromJSON |
返回 JSON 对象或 JSON 数据类型的值 # |
hashFiles |
返回与路径模式匹配的文件集的单个哈希 # |
success |
当前面的步骤都没失败或被取消时返回 true # |
always |
使步骤始终执行,返回 true 即使取消也是如此 # |
cancelled |
如果工作流被取消,则返回 true # |
failure |
当作业的任何先前步骤失败时返回 true # |
函数 success()
steps:...- name: The job has succeededif: ${{ success() }}
函数 failure()
steps:...- name: The job has failedif: ${{ failure() }}
常用实例
获取版本信息
- name: Testrun: |# Strip git ref prefix from versionecho "${{ github.ref }}"# VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')# # Strip "v" prefix from tag name# [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')echo "$VERSION"
提交到 gh-pages 分支
- name: Deployuses: peaceiris/actions-gh-pages@v3with:github_token: ${{secrets.GITHUB_TOKEN}}publish_dir: ./build
修改 package.json
- name: Modify Versionshell: bashrun: |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 字段
- name: package.json infouses: jaywcjlove/github-action-package@mainwith:rename: '@wcj/github-package-test'
克隆带有 Submodule 的仓库
- name: Checkoutuses: actions/checkout@v3with:path: mainsubmodules: true
submodules:true 检出子模块或 recursive 递归检出子模块
- name: Clone sub repositoryshell: bashrun: |auth_header="$(git config --local --get http.https://github.com/.extraheader)"# git submodule sync --recursive# git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --remote --force --recursive --checkout ant.design
步骤依赖作业
使用 jobs.<job_id>.needs 识别在此作业运行之前必须成功完成的任何作业。它可以是一个字符串,也可以是字符串数组。 如果某个作业失败,则所有需要它的作业都会被跳过,除非这些作业使用让该作业继续的条件表达式。
jobs:job1:job2:needs: job1job3:needs: [job1, job2]
在此示例中,job1 必须在 job2 开始之前成功完成,而 job3 要等待 job1 和 job2 完成。此示例中的作业按顺序运行:
❶ job1❷ job2❸ job3
配置如下
jobs:job1:job2:needs: job1job3:if: ${{ always() }}needs: [job1, job2]
在此示例中,job3 使用 always() 条件表达式,因此它始终在 job1 和 job2 完成后运行,不管它们是否成功。
同步 Gitee
- name: Sync to Giteerun: |mirror() {git clone "https://github.com/$1/$2"cd "$2"git remote add gitee "https://jaywcjlove:${{ secrets.GITEE_TOKEN }}@gitee.com/uiw/$2"git remote set-head origin -dgit push gitee --prune +refs/remotes/origin/*:refs/heads/* +refs/tags/*:refs/tags/*cd ..}mirror uiwjs uiw
提交 NPM 包
- run: npm publish --access publicenv:NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
获取 NPM_TOKEN,可以通过 npm 账号创建 token
npm token list [--json|--parseable] # 查看npm token create [--read-only] [--cidr=1.1.1.1/24,2.2.2.2/16] # 创建npm token revoke <id|token> # 撤销
可以使用 JS-DevTools/npm-publish 提交
- name: 📦 @province-city-china/datauses: JS-DevTools/npm-publish@v1with:token: ${{ secrets.NPM_TOKEN }}package: packages/data/package.json
它有个好处,检测 package.json 中版本号是否发生变更,来决定是否提交版本,不会引发流程错误。
步骤作业文件共享
Artifacts 是 GitHub Actions 为您提供持久文件并在运行完成后使用它们或在作业(文档)之间共享的一种方式。
要创建工件并使用它,您将需要不同的操作:上传和下载。 要上传文件或目录,您只需像这样使用它:
steps:- uses: actions/checkout@v2- run: mkdir -p path/to/artifact- run: echo hello > path/to/artifact/a.txt- uses: actions/upload-artifact@v2with:name: my-artifactpath: path/to/artifact/a.txt
然后下载 artifact 以使用它:
steps:- uses: actions/checkout@v2- uses: actions/download-artifact@v2with:name: my-artifact
Node.js
- name: Setup Nodeuses: actions/setup-node@v2with:node-version: 14
使用矩阵策略 在 nodejs 不同版本中运行
strategy:matrix:node-version: [10.x, 12.x, 14.x]steps:- uses: actions/checkout@v2- name: 使用 Node ${{ matrix.node-version }}uses: actions/setup-node@v1with:node-version: ${{ matrix.node-version }}- run: npm ci- run: npm run build --if-present- run: npm test
提交 docker 镜像
# https://www.basefactor.com/github-actions-docker- name: Docker loginrun: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}- name: Build ant.design imagerun: |cd ./ant\.designdocker build -t ant.design .- name: Tags & Push docsrun: |# Strip git ref prefix from versionVERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')# Strip "v" prefix from tag name[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')docker tag ant.design ${{ secrets.DOCKER_USER }}/ant.design:$VERSIONdocker tag ant.design ${{ secrets.DOCKER_USER }}/ant.design:latestdocker push ${{ secrets.DOCKER_USER }}/ant.design:$VERSIONdocker push ${{ secrets.DOCKER_USER }}/ant.design:latest
创建一个 tag
- name: Create Tagid: create_taguses: jaywcjlove/create-tag-action@mainwith:package-path: ./package.json
根据 package-path 指定的 package.json 检测 version 是否发生变化来创建 tag
生成 git 提交日志
- name: Generate Changelogid: changeloguses: jaywcjlove/changelog-generator@mainwith:filter-author: (小弟调调™)- name: Get the changelogrun: echo "${{ steps.changelog.outputs.changelog }}"
提交到 GitHub docker 镜像仓库
- name: '登录到 GitHub 注册表'run: echo ${{ github.token }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin- name: '编译 docker image'run: docker build -t ghcr.io/jaywcjlove/reference:latest .- name: '推送到 GitHub 注册表中'run: docker push ghcr.io/jaywcjlove/reference:latest- name: '标记 docker 镜像并发布到 GitHub 注册表'if: steps.create_tag.outputs.successfulrun: |echo "version: v${{ steps.changelog.outputs.version }}"docker tag ghcr.io/jaywcjlove/reference:latest ghcr.io/jaywcjlove/reference:${{steps.changelog.outputs.version}}docker push ghcr.io/jaywcjlove/reference:${{steps.changelog.outputs.version}}
提交 commit 到 master 分支
- name: 生成一个文件,并将它提交到 master 分支run: |# Strip git ref prefix from versionVERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')COMMIT=released-${VERSION}# Strip "v" prefix from tag name[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')echo "输出版本号:$VERSION"# 将版本输出到当前 VERSION 文件中echo "$VERSION" > VERSIONecho "1. 输出Commit:$commit"echo "2. Released $VERSION"git fetchgit config --local user.email "action@github.com"git config --local user.name "GitHub Action"git add .git commit -am $COMMITgit branch -avgit pull origin master- name: 将上面的提交 push 到 master 分支uses: ad-m/github-push-action@masterwith:github_token: ${{ secrets.GITHUB_TOKEN }}
作业之间共享数据
创建一个文件,然后将其作为构件上传
```yml {11} jobs: example-job: name: Save output steps:
- shell: bashrun: |expr 1 + 1 > output.log- name: Upload output fileuses: actions/upload-artifact@v3with:name: output-log-filepath: output.log
可以下载名为 `output-log-file` 的工件```yml {7}jobs:example-job:steps:- name: Download a single artifactuses: actions/download-artifact@v3with: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
作业中的所有 `run` 步骤提供默认的 `shell` 和 `working-directory`### jobs.<job_id>.steps[*].shell使用 `bash` 运行脚本```yml {4}steps:- name: Display the pathrun: echo $PATHshell: 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 分支 |
另见
- Github Actions 学习笔记 (jaywcjlove.github.io)
- 了解 GitHub Actions (docs.github.com)
