测试 GitHub 工作流,一些比较特殊的玩儿法。
GitHub actions 有四个基本的概念,如下:
- workflow (工作流程):持续集成一次运行的过程,就是一个 workflow。
- job (任务):一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务。
- step(步骤):每个 job 由多个 step 构成,一步步完成。
- action (动作):每个 step 可以依次执行一个或多个命令(action)。
GitHub Actions 采用 YAML
格式的配置文件叫做 workflow 文件,存放在代码仓库的 .github/workflows
目录。文件名可以任意取,但是后缀名统一为 .yml
,比如 ci.yml
。一个库可以有多个 workflow
文件。GitHub 只要发现 .github/workflows
目录里面有 .yml
文件,就会根据配置事件自动运行该文件。
name: GitHub Actions Demo
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- run: npm install
- run: npm run build
on
字段指定触发 workflow
的条件,通常是某些事件。
# push 事件触发 workflow
on: push
# push 事件或 pull_request 事件都可以触发 workflow
on: [push, pull_request]
# 只有在 main 分支 push 事件触发 workflow
on:
push:
branches:
- main
# push 事件触发 workflow,但是 docs 目录下的更改 push 事件不触发 workflow
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
(jobs.<job_id>.name
)字段,配置一项或多项需要执行的任务。
jobs:
my_first_job:
name: My first job
my_second_job:
name: My second job
通过 needs
(jobs.<job_id>.needs
)字段,指定当前任务的依赖关系。
jobs:
job1:
job2:
needs: job1
job3:
needs: [job1, job2]
上面配置中,job1
必须先于 job2
完成,而 job3
等待 job1
和 job2
的完成才能运行。因此,这个 workflow 的运行顺序依次为:job1
、job2
、job3
。
jobs:
job1:
runs-on: ubuntu-latest
# Map a step output to a job output
outputs:
output1: ${{ steps.step1.outputs.test }}
output2: ${{ steps.step2.outputs.test }}
steps:
- id: step1
run: echo "::set-output name=test::hello"
- id: step2
run: echo "::set-output name=test::world"
job2:
runs-on: ubuntu-latest
needs: job1
steps:
- run: echo ${{needs.job1.outputs.output1}} ${{needs.job1.outputs.output2}}
runs-on
字段指定运行所需要的虚拟机环境。
runs-on: ubuntu-18.04
jobs:
build:
runs-on: ubuntu-18.04
虚拟环境 | YAML 工作流程标签 | 注: |
---|---|---|
Windows Server 2022 | windows-latest 或 windows-2022 |
windows-latest 标签目前使用的是 Windows Server 2022 运行器镜像 |
Windows Server 2019 | windows-2019 |
|
Ubuntu 22.04 | ubuntu-22.04 |
Ubuntu 22.04 目前处于公开测试阶段。 |
Ubuntu 20.04 | ubuntu-latest 或 ubuntu-20.04 |
|
Ubuntu 18.04 | ubuntu-18.04 |
|
macOS Monterey 12 | macos-12 |
macOS 12 目前处于公开测试阶段。 |
macOS Big Sur 11 | macos-latest 或 macos-11 |
macos-latest 标签当前使用 macOS 11 运行器镜像。 |
macOS Catalina 10.15 | macos-10.15 |
steps
字段指定每个 Job 的运行步骤,可以包含一个或多个步骤。每个步骤都可以指定以下三个字段。
jobs.<job_id>.steps.name:步骤名称。
jobs.<job_id>.steps.run:该步骤运行的命令或者 action。
jobs.<job_id>.steps.env:该步骤所需的环境变量。
jobs:
build:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: 'https://registry.npmjs.org'
- run: npm install
- run: npm run build
# ci.yml
name: Node.js CI
on: push
jobs:
test:
# Containers must run in Linux based operating systems
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
trigger_tests:
needs: test
runs-on: ubuntu-latest
steps:
- name: Trigger tests
uses: actions/github-script@v6
with:
script: |
const res = await github.rest.repos.createDispatchEvent({
owner: 'jaywcjlove',
repo: 'typenexus',
event_type: 'run-deploy'
});
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
上面 ci.yml
工作流执行完成之后,触发 main.yml
,注意上面的 run-deploy
取名保持一致
# main.yml
name: deploy
on:
repository_dispatch:
types: [run-deploy]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Test
run: |
# Strip git ref prefix from version
echo "${{ 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"
name: CI
on:
push:
tags:
- v*
jobs:
create-docker-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
# 向 EVN 写入 CURRENT_VERSION 环境变量赋值版本号
- run: |
echo "CURRENT_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
# 可以获取到 CURRENT_VERSION 的值
- run: echo "${{env.CURRENT_VERSION}}"
jobs:
build:
if: "!contains(github.event.head_commit.message, 'skip ci')"
- run: echo "previous_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo '')" >> $GITHUB_ENV
- name: Generate changelog
id: changelog
uses: jaywcjlove/changelog-generator@main
if: env.previous_tag
- name: Modify Version
shell: bash
run: |
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))'
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
- name: Checkout
uses: actions/checkout@v3
with:
path: main
submodules: true
submodules
:true
检出子模块或 recursive
递归检出子模块。
- name: Clone sub repository
shell: bash
run: |
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: job1
job3:
needs: [job1, job2]
在此示例中,job1
必须在 job2
开始之前成功完成,而 job3
要等待 job1
和 job2
完成。
此示例中的作业按顺序运行:
❶ job1
❷ job2
❸ job3
jobs:
job1:
job2:
needs: job1
job3:
if: ${{ always() }}
needs: [job1, job2]
在此示例中,job3
使用 always()
条件表达式,因此它始终在 job1
和 job2
完成后运行,不管它们是否成功。
Artifacts 是 GitHub Actions 为您提供持久文件并在运行完成后使用它们或在作业(文档)之间共享的一种方式。
要创建工件并使用它,您将需要不同的操作:上传和下载。 要上传文件或目录,您只需像这样使用它:
steps:
- uses: actions/checkout@v2
- run: mkdir -p path/to/artifact
- run: echo hello > path/to/artifact/world.txt
- uses: actions/upload-artifact@v2
with:
name: my-artifact
path: path/to/artifact/world.txt
然后下载 artifact
以使用它:
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
name: my-artifact
- run: npm publish --access public
env:
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> # 撤销
# https://www.basefactor.com/github-actions-docker
- name: Docker login
run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
- name: Build ant.design image
run: |
cd ./ant\.design
docker build -t ant.design .
- name: Tags & Push docs
run: |
# Strip git ref prefix from version
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//')
docker tag ant.design ${{ secrets.DOCKER_USER }}/ant.design:$VERSION
docker tag ant.design ${{ secrets.DOCKER_USER }}/ant.design:latest
docker push ${{ secrets.DOCKER_USER }}/ant.design:$VERSION
docker push ${{ secrets.DOCKER_USER }}/ant.design:latest
- name: 生成一个文件,并将它提交到 master 分支
run: |
# Strip git ref prefix from version
VERSION=$(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" > VERSION
echo "1. 输出Commit:$commit"
echo "2. Released $VERSION"
git fetch
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add .
git commit -am $COMMIT
git branch -av
git pull origin master
- name: 将上面的提交 push 到 master 分支
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: 18
jobs:
test:
# Containers must run in Linux based operating systems
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
- name: Sync to Gitee
run: |
mirror() {
git clone "https://github.com/$1/$2"
cd "$2"
git remote add gitee "https://jaywcjlove:${{ secrets.GITEE_TOKEN }}@gitee.com/uiw/$2.git"
git remote set-head origin -d
git push gitee --prune +refs/remotes/origin/*:refs/heads/* +refs/tags/*:refs/tags/*
cd ..
}
mirror uiwjs uiw
强烈建议操作使用环境变量访问文件系统,而非使用硬编码的文件路径。 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_ACTOR | 发起工作流程的个人或应用程序的名称。 例如 octocat。 |
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 |
GITHUB_SHA | 触发工作流程的提交 SHA。 例如 ffac537e6cbbf934b08745a378932722df287a53。 |
GITHUB_REF | 触发工作流程的分支或标记参考。 例如 refs/heads/feature-branch-1。 如果分支或标记都不适用于事件类型,则变量不会存在。 |
GITHUB_HEAD_REF | 仅为复刻的仓库设置。 头部仓库的分支。 |
GITHUB_BASE_REF | 仅为复刻的仓库设置。 基础仓库的分支。 |
注:
GitHub
会保留GITHUB_
环境变量前缀供GitHub
内部使用。 设置有GITHUB_
前缀的环境变量或密码将导致错误。
在 https://github.com/<用户名>/<项目名称>/settings/secrets
中添加 secrets
NODE_API_TOKEN
,在工作流中设置环境变量 NODE_API_TOKEN
- name: 测试 nodejs 获取环境变量
env:
NODE_API_TOKEN: ${{ secrets.NODE_API_TOKEN }}
run: npm run env
属性名称 | 类型 | 描述 |
---|---|---|
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。 |
As always, thanks to our amazing contributors!
Made with action-contributors.
Licensed under the MIT License.