GitHub Actions 工作流配置详解
详解 GitHub Actions 工作流 YAML 语法,覆盖 on 触发器与事件、jobs/steps、actions、表达式与上下文、内置环境变量、secrets 与输入,配合 act 本地实测回显说明如何编写与调试 workflow 文件
GitHub Actions 工作流配置详解
目标:系统讲解 GitHub Actions 工作流(workflow)文件(
.github/workflows/*.yml)的 YAML 语法,覆盖on触发器、jobs/steps、复用actions、表达式与上下文、内置环境变量、secrets/inputs,并用 act 本地实测回显演示一个可运行示例。本文已在 Ubuntu 22.04 真实环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS
- 工作流存放目录:
.github/workflows/ - 示例仓库:
/opt/data/github-actions/myapp(git 远程指向quzuo-ops/demo-app) - 本地运行工具:act 0.2.89(本地运行 GitHub Actions 工作流的 CLI)
- 示例工作流文件:
.github/workflows/ci.yml - Runner 版本:2.338.0(自托管 Runner,见《Ubuntu 22.04 安装 GitHub Actions Runner 指南》)
二、前置条件
- 代码仓库含
.github/workflows/目录,目录内每个.yml/.yaml即一个工作流 - 已安装 GitHub Actions Runner 或可联网访问 GitHub 托管 Runner
- 本地调试可选装 act(详见《GitHub Actions 常用 CLI 命令详解》)
- 编辑与校验:可用
act -n(dry-run)在本地校验工作流语法正确性
三、工作流文件总览(示例 ci.yml)
一段被实际运行(见"八、实测")的最小示例,完整展示语法骨架:
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout 代码
uses: actions/checkout@v4
- name: 打印工作区
run: |
echo "仓库名: ${{ github.repository }}"
echo "分支: ${{ github.ref_name }}"
echo "工作目录文件列表:"
ls -la
- name: 输出信息
run: echo "Hello GitHub Actions from act"
工作流由四层结构组成:
name:工作流名称,显示在 Actions 页;on:触发条件(事件/调度);jobs:一个或多个 job(任务),可并行、可依赖;- 每个 job 内的
runs-on(运行环境)与steps(步骤列表,每步用uses复用 action 或用run执行 shell 命令)。
四、on 触发器(事件)
on 决定工作流何时触发,可写单个事件、数组,或带过滤条件的地图形式。
4.1 单个事件 / 事件数组
on: push # 任意 push 触发
on: [push, pull_request] # push 或 PR 触发
4.2 带过滤的 push / pull_request
on:
push:
branches: [main, "release/*"] # 仅这些分支的 push
paths:
- "src/**" # 仅这些路径变更时触发
pull_request:
types: [opened, synchronize] # 仅响应 PR 的这两种状态
4.3 定时与手动触发
on:
schedule:
- cron: "0 2 * * *" # 每天 02:00 UTC 触发
workflow_dispatch: # 手动触发,可带输入
inputs:
environment:
description: 部署环境
required: true
default: staging
version:
description: 版本号
4.4 复用其它工作流(workflow_call / workflow_run)
on:
workflow_call: # 供其它工作流调用,可声明 inputs/secrets
inputs:
tag:
type: string
required: true
workflow_run:
workflows: ["CI"] # 上游 CI 工作流完成后触发
branches: [main]
types: [completed]
💡 说明:
workflow_dispatch触发的 job 才能用 act 在本地以手动事件模拟;schedule的 cron 语法与 Linux 一致(5 段),但时区固定为 UTC。
五、jobs 与 runs-on
5.1 多 job 与依赖关系
jobs:
build:
runs-on: ubuntu-latest
steps: []
test:
runs-on: ubuntu-latest
needs: build # 依赖 build 成功后执行
steps: []
release:
runs-on: [self-hosted, Linux, X64] # 指定自托管 Runner(通过 label)
needs: [build, test] # 依赖多个 job
steps: []
5.2 矩阵(matrix)策略与并发控制
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node: [16, 18, 20]
os: [ubuntu-latest] # 维度自由组合
fail-fast: false
concurrency:
group: build-{{ github.ref }}
cancel-in-progress: true
steps:
- run: node --version # 同一套步骤会在各组合上各跑一次
💡 说明:
needs建立 DAG 依赖,未声明依赖的 job 并行执行;strategy.matrix将同一 job 打散为多组合并行,fail-fast=false时某组合失败不终止其它组合。
5.3 运行环境(runs-on 取值)
| runs-on 取值 | 说明 |
|---|---|
ubuntu-latest / ubuntu-22.04 | GitHub 托管 Ubuntu(由 GitHub 配额运行) |
windows-latest、macos-latest | GitHub 托管 Windows/macOS |
[self-hosted, Linux, X64] | 自托管 Runner,按 label 匹配 |
[self-hosted, linux, arm64] | 自托管 ARM64 Runner |
六、steps 与 actions(uses/run)
一个 step 只能有一个主要关键字:uses(复用 action)或 run(执行命令)。可给 step 起 name 便于日志定位。
6.1 run 步骤(执行 shell 命令)
steps:
- name: 安装依赖
run: npm ci
- name: 多行命令
run: |
set -euxo pipefail
echo "step 1"
echo "step 2"
- name: 指定 shell
shell: bash
run: echo "使用 bash"
6.2 uses 步骤(复用 action)
uses: owner/repo@ref 三要素:仓库名 + 标签/分支/SHA。常用官方 action:
steps:
- uses: actions/checkout@v4 # 检出代码到工作区
with:
submodules: true
- uses: actions/setup-node@v4 # 安装 Node.js
with:
node-version: '20'
cache: 'npm'
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- uses: actions/cache@v4 # 缓存依赖
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
💡 说明:
with传 action 的输入参数;宁可固定到 SHA(@<40位sha>)保证安全可复现,也可固定到 tag(@v4)便于升级。
6.3 条件执行与输出
steps:
- name: 仅 main 分支执行
if: github.ref == 'refs/heads/main'
run: echo "在主分支"
- name: 输出传给下一步
id: ver
run: echo "value=v1.0.0" >> "$GITHUB_OUTPUT"
- name: 读取上一步输出
run: echo "版本是 ${{ steps.ver.outputs.value }}"
七、表达式、上下文、环境变量与 secrets
7.1 表达式与上下文(contexts)
${{ 表达式 }} 内是表达式,可引用上下文对象。常用上下文:
| 上下文 | 用途 | 示例值(实测 act 下) |
|---|---|---|
github | 事件与仓库信息 | github.repository → quzuo-ops/demo-app |
github.ref_name | 分支/Tag 名 | master |
steps.<id>.outputs.<k> | 上一步输出 | 见 6.3 |
matrix.<k> | 矩阵当前组合 | matrix.node |
env | 工作流/Job/Step 环境变量 | env.MY_VAR |
secrets | 加密机密 | secrets.API_TOKEN |
inputs | workflow_dispatch 输入 | inputs.version |
runner | runner 信息 | runner.os、runner.arch |
7.2 内置环境变量
系统内置一批默认环境变量,可直接以 $GITHUB_* 形式引用:
| 变量 | 说明 |
|---|---|
$GITHUB_WORKSPACE | 默认工作区目录 |
$GITHUB_SHA | 当前提交 SHA |
$GITHUB_REPOSITORY | owner/repo |
$GITHUB_REF | 触发引用的 ref |
$GITHUB_RUN_NUMBER | 运行序号 |
$GITHUB_ACTOR | 触发用户 |
$GITHUB_OUTPUT | 写 step 输出的文件路径 |
$GITHUB_ENV | 写环境变量的文件路径 |
$GITHUB_PATH | 追加 PATH 的文件路径 |
steps:
- name: 写环境变量
run: echo "MY_VAR=hello" >> "$GITHUB_ENV"
- name: 读环境变量
run: echo "$MY_VAR"
7.3 secrets(机密)与 inputs(输入)
name: Deploy
on:
workflow_dispatch:
inputs:
target: { type: choice, options: [staging, prod], default: staging }
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: echo "目标环境 ${{ inputs.target }}"
- run: |
# secrets 全量传入环境变量(名称均为大写)
echo "${{ secrets.API_TOKEN }}" > /dev/null
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
⚠️ 安全提示:不要在
run里用echo ${{ secrets.X }}直接打印,避免机密进入日志;应通过env传入再使用。secrets取自仓库或组织 Settings,且不可在if:条件中直接比较(存在泄漏风险)。
八、act 本地实测(真实回显)
8.1 编写示例工作流
mkdir -p /opt/data/github-actions/myapp/.github/workflows
cd /opt/data/github-actions/myapp
cat > .github/workflows/ci.yml <<'EOF'
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout 代码
uses: actions/checkout@v4
- name: 打印工作区
run: |
echo "仓库名: ${{ github.repository }}"
echo "分支: ${{ github.ref_name }}"
echo "工作目录文件列表:"
ls -la
- name: 输出信息
run: echo "Hello GitHub Actions from act"
EOF
git init && git add -A && git commit -qm init
8.2 用 act 校验与列出 job
act list -W .github/workflows
实测回显:
Stage Job ID Job name Workflow name Workflow file Events
0 build build CI ci.yml push
8.3 用 act 本地运行 push 事件
act push -j build -W .github/workflows
实测回显:
[CI/build] ⭐ Run Set up job
[CI/build] 🚀 Start image=node:20-bookworm-slim
[CI/build] 🐳 docker pull image=node:20-bookworm-slim platform= username= forcePull=true
[CI/build] 🐳 docker run image=node:20-bookworm-slim platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[CI/build] ✅ Success - Set up job
[CI/build] ⭐ Run Main Checkout 代码
[CI/build] 🐳 docker cp src=/opt/data/github-actions/myapp/. dst=/opt/data/github-actions/myapp
[CI/build] ✅ Success - Main Checkout 代码 [25.273241ms]
[CI/build] ⭐ Run Main 打印工作区
[CI/build] 🐳 docker exec cmd=[bash -e /var/run/act/workflow/1] user= workdir=
[CI/build] | 仓库名: quzuo-ops/demo-app
[CI/build] | 分支: master
[CI/build] | 工作目录文件列表:
[CI/build] | total 20
[CI/build] | drwxr-xr-x 4 root root 4096 Oct 10 00:30 .
[CI/build] | drwxr-xr-x 3 root root 4096 Oct 10 00:30 ..
[CI/build] | drwxr-xr-x 7 root root 4096 Oct 10 00:30 .git
[CI/build] | drwxr-xr-x 3 root root 4096 Oct 10 00:30 .github
[CI/build] | -rw-r--r-- 1 root root 8 Oct 10 00:24 README.md
[CI/build] ✅ Success - Main 打印工作区 [101.480655ms]
[CI/build] ⭐ Run Main 输出信息
[CI/build] 🐳 docker exec cmd=[bash -e /var/run/act/workflow/2] user= workdir=
[CI/build] | Hello GitHub Actions from act
[CI/build] ✅ Success - Complete job
[CI/build] 🏁 Job succeeded
💡 说明:上面「仓库名: quzuo-ops/demo-app」来自
github.repository上下文,act 依据仓库的 git 远程地址推导;//workflow/1表明这是工作流的第 1 个run步骤的桶文件,逐行按步骤回放。实际在真实 GitHub 推送后由托管 Runner 执行,输出格式一致但以真实 history 为准。
8.4 dry-run 校验语法(仅预检,不实际执行)
act -n -j build -W .github/workflows
实测回显(节选):
*DRYRUN* [CI/build] ⭐ Run Set up job
*DRYRUN* [CI/build] 🚀 Start image=node:20-bookworm-slim
*DRYRUN* [CI/build] ✅ Success - Set up job
*DRYRUN* [CI/build] ⭐ Run Main Checkout 代码
*DRYRUN* [CI/build] ✅ Success - Main Checkout 代码
*DRYRUN* [CI/build] ⭐ Run Main 打印工作区
*DRYRUN* [CI/build] ✅ Success - Main 打印工作区 [46.867046ms]
*DRYRUN* [CI/build] ⭐ Run Main 输出信息
*DRYRUN* [CI/build] ✅ Success - Main 输出信息 [39.015654ms]
*DRYRUN* [CI/build] 🏁 Job succeeded
九、常见问题
Q1:本地 act 运行报 Could not find any stages to run?
-W 传的路径未含工作流的『目录』(应传 .github/workflows 目录而非单个文件路径写法不当),或用 -W .github/workflows 指定目录、-j <job> 指定 job 即可。
Q2:${{ github.ref_name }} 与 ${{ github.ref }} 有何区别?
github.ref 是完整 ref(如 refs/heads/main);github.ref_name 是去掉前缀的名字(如 main)。比较分支常 github.ref == 'refs/heads/main',打印用 ref_name。
Q3:workflow_dispatch 输入在 act 里如何提供?
act 用 --input key=value 提供(见《常用 CLI 命令详解》),例如 act workflow_dispatch -j deploy --input target=prod。
Q4:secrets 在 env: 里没生效?
在真实 Runner 上 secrets 需在仓库 /Settings → Secrets and variables → Actions 预先定义;名称引用时用 secrets.名称,且放在 env: 下传进程(命名大写仅为约定,不强制)。
十、参考链接
- 工作流语法官方文档:https://docs.github.com/zh/actions/writing-workflows/workflow-syntax-for-github-actions
- 触发器官方文档:https://docs.github.com/zh/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
- 表达式与上下文:https://docs.github.com/zh/actions/learn-github-actions/contexts
- act 本地运行:https://nektosact.com/