GitHub Actions Workflow 详细指南
摘要
本文面向第一次接触 GitHub Actions 的开发者,从基本概念、YAML 语法和变量表达式开始,逐步介绍 CI、测试矩阵、缓存、构建产物、发布、OIDC、安全和排错。
文档中的示例需要放在仓库的
.github/workflows/目录中,例如.github/workflows/ci.yml。
GitHub Actions 会执行代码和第三方 Action,复制示例前应根据项目实际情况调整权限、Node.js 版本和命令。
一、GitHub Actions 是什么
GitHub Actions 是 GitHub 内置的自动化平台。代码推送、Pull Request、标签、Release、Issue、定时任务或人工点击按钮,都可以触发自动任务。
常见用途:
-
每次提交后运行类型检查、格式检查和单元测试。
-
在 Linux、Windows、macOS 或不同 Node.js 版本上测试。
-
构建前端、后端、桌面应用或 Docker 镜像。
-
将测试报告、安装包等保存为 Artifact。
-
发布 npm 包、GitHub Release、Docker 镜像。
-
部署到云服务器、Kubernetes、静态网站或 GitHub Pages。
-
自动添加标签、回复 Issue、检查依赖和执行安全扫描。
基本执行过程:
1 | GitHub 事件 |
工作流文件本身属于仓库代码,应像源代码一样接受评审。
二、最小可运行示例
创建 .github/workflows/hello.yml:
1 | name: Hello |
含义:
-
name: Hello:Actions 页面显示的工作流名称。 -
on.push:任意分支收到 push 时触发。 -
jobs:定义工作流中的任务。 -
say-hello:Job 的内部 ID,可以自定义。 -
runs-on:Job 在 GitHub 托管的 Ubuntu Runner 中运行。 -
steps:Job 内按顺序执行的步骤。 -
run:在 Runner 的 Shell 中执行命令。
推送该文件后,可以在仓库的 Actions 页面查看运行记录和日志。
三、Workflow、Job、Step、Action 和 Runner
3.1 Workflow
Workflow 是一个 YAML 文件,描述什么时候运行以及运行什么。文件只能位于:
1 | .github/workflows/*.yml |
子目录中的 YAML 不会被当作 Workflow:
1 | .github/workflows/release/npm.yml # 不会作为工作流加载 |
3.2 Job
Job 是一组在同一 Runner 中执行的步骤。同一个 Job 的 Step:
-
共享工作目录。
-
共享该 Job 中创建的文件。
-
默认按声明顺序执行。
-
任一步失败后,后续普通步骤默认跳过。
不同 Job:
-
默认并行执行。
-
通常运行在不同的全新 Runner 中。
-
不会自动共享文件或环境变量。
-
需要通过
needs设置顺序,通过 Artifact 共享文件。
3.3 Step
Step 是 Job 中的单个操作,有两种主要形式:
1 | # 执行 Shell 命令 |
一个 Step 不能同时使用 run 和 uses。
3.4 Action
Action 是可复用的自动化组件。例如:
-
actions/checkout:检出仓库代码。 -
actions/setup-node:安装并配置 Node.js。 -
actions/cache:缓存依赖或构建数据。 -
actions/upload-artifact:上传构建产物。
引用格式:
1 | uses: owner/repository@ref |
其中 ref 可以是标签、分支或完整 commit SHA:
1 | uses: actions/checkout@v6 |
安全性最高的是固定到完整 commit SHA。标签更易读、更易升级,但标签指向理论上可以改变。
3.5 Runner
Runner 是执行 Job 的机器。GitHub 托管 Runner 常用标签:
1 | runs-on: ubuntu-latest |
也可以使用自托管 Runner:
1 | runs-on: [self-hosted, linux, x64] |
注意:
-
GitHub 托管 Runner 通常是一次性的虚拟环境。
-
不要假设上一次 Workflow 创建的文件还存在。
-
ubuntu-latest会随 GitHub 更新,不代表永久固定的 Ubuntu 版本。 -
对环境高度敏感时可以使用明确的 Runner 标签或容器。
四、Workflow 顶层语法
一个较完整的结构如下:
1 | name: CI |
4.1 name
Actions 页面中的工作流名称:
1 | name: Continuous Integration |
省略时,GitHub 通常显示文件路径。
4.2 run-name
单次运行记录的动态名称:
1 | run-name: Deploy ${{ inputs.environment }} by @${{ github.actor }} |
4.3 env
定义整个 Workflow 可用的环境变量:
1 | env: |
4.4 defaults
为所有 run Step 设置默认 Shell 或工作目录:
1 | defaults: |
defaults.run 中不能使用 Context 或表达式。
五、触发事件 on
5.1 任意 push
1 | on: |
简写:
1 | on: push |
多个简单事件:
1 | on: [push, pull_request] |
5.2 限定分支
1 | on: |
只忽略某些分支:
1 | on: |
同一个事件中不能同时使用 branches 和 branches-ignore。需要混合规则时,在 branches 中使用 !:
1 | on: |
负模式顺序有意义:后面的匹配可以改变前面的结果。
5.3 标签触发
1 | on: |
匹配示例:
1 | v1.0.0 匹配 |
更严格的模式:
1 | tags: |
GitHub 的过滤模式是 glob,不是完整正则表达式;复杂版本校验仍应在 Step 中执行。
5.4 路径过滤
只在源码改变时运行:
1 | on: |
忽略纯文档修改:
1 | on: |
同时配置分支和路径时,两者必须都匹配:
1 | on: |
注意:如果分支保护规则把某个 Workflow 设为必需检查,路径过滤导致它完全不运行时,该检查可能一直显示 Pending。此时可以让 Workflow 总是触发,再在 Job 中通过 if 决定是否执行。
5.5 Pull Request
1 | on: |
常见 types:
-
opened:PR 新建。 -
synchronize:PR 分支出现新提交。 -
reopened:重新打开。 -
closed:关闭或合并。 -
ready_for_review:Draft 转为可评审。
仅在 PR 被合并后执行:
1 | on: |
pull_request_target 与 pull_request 不同。它在目标仓库默认分支的安全上下文中运行,可能拥有 Secret 和写权限。不要在 pull_request_target 中检出并执行不受信任的 PR 代码。
5.6 Release
1 | on: |
适合在 GitHub Release 发布后上传资源或同步到其他平台。
5.7 多事件不同配置
只要其中一个事件触发就会运行:
1 | on: |
六、权限 permissions 与 GITHUB_TOKEN
每次 Workflow 运行时,GitHub 自动创建短期 GITHUB_TOKEN。它只对当前仓库和本次运行有效,任务结束后失效。
6.1 最小只读权限
1 | permissions: |
检出代码通常只需要 contents: read。
6.2 禁用全部默认权限
1 | permissions: {} |
随后在具体 Job 中按需授权:
1 | jobs: |
6.3 常用权限
1 | permissions: |
以上是权限名称展示,不代表一个普通 Job 应同时拥有全部权限。实际工作流应只声明当前 Job 必需的最少几项。
只要显式设置了某些权限,未列出的权限通常会变成 none。
6.4 使用 Token
1 | - name: Create release |
即使没有显式把 Token 传给第三方 Action,Action 仍可能通过 github.token 获取它,因此最小权限非常重要。
七、并发控制 concurrency
并发组用于避免同一类任务同时运行。
1 | concurrency: |
变量含义:
-
github.workflow:Workflow 的name,例如CI。 -
github.ref:完整 Git 引用,例如refs/heads/main、refs/pull/123/merge或refs/tags/v3.0.12。 -
github.ref_name:简短名称,例如main或v3.0.12。
main 分支示例:
1 | ci-CI-refs/heads/main |
同一个 PR 连续推送多次时:
1 | cancel-in-progress: true |
旧 CI 会被取消,只保留最新提交的 CI,节约时间。
发布任务一般不应中途取消:
1 | concurrency: |
否则可能出现“npm 已发布,但 GitHub Release 尚未创建”这种不完整状态。
按部署环境分组:
1 | concurrency: |
注意:
-
同一并发组最多有一个 Running 和一个 Pending 运行。
-
并发组名称不区分大小写。
-
GitHub 不保证同组 Pending 任务的执行顺序。
八、Job 语法
8.1 Job ID 与显示名称
1 | jobs: |
-
unit-test是内部 ID,用于needs.unit-test。 -
name是 Actions 页面显示名称。
Job ID 建议只使用字母、数字、- 和 _。
8.2 选择 Runner
1 | jobs: |
8.3 超时
1 | jobs: |
应为可能卡住的网络、测试和部署 Job 设置合理超时。
8.4 Job 级环境变量和权限
1 | jobs: |
8.5 Job 默认 Shell 和目录
1 | jobs: |
九、Step 语法
9.1 执行单行和多行命令
1 | - name: Single command |
9.2 指定 Shell
1 | - run: echo "bash" |
不同 Runner 的默认 Shell 不完全相同。跨平台 Workflow 最好显式指定。
9.3 指定工作目录
1 | - name: Test frontend |
9.4 调用 Action 并传参
1 | - name: Setup Node.js |
with 支持哪些参数由该 Action 的 action.yml 定义,应查阅对应仓库文档。
9.5 Step ID 和输出
1 | - name: Read version |
id 是表达式引用名,不是显示名称。
9.6 超时和允许失败
1 | - name: Optional audit |
continue-on-error 应谨慎使用,否则真正的问题可能被隐藏。
十、变量、Context 和表达式
表达式写在:
1 | ${{ ... }} |
10.1 常用 Context
github
当前仓库、事件和运行信息:
1 | - run: | |
常见值:
1 | github.repository = hanqunfeng/claude-trace |
env
读取 YAML 中定义的环境变量:
1 | env: |
Shell 内也可使用:
1 | - run: echo "$APP_NAME" |
vars
读取仓库、组织或 Environment 配置变量:
1 | - run: echo "Region=${{ vars.DEPLOY_REGION }}" |
vars 不是 Secret,会显示在日志和界面中。
secrets
读取加密 Secret:
1 | - run: ./deploy.sh |
runner
Runner 信息:
1 | - run: | |
job
1 | - if: always() |
steps
1 | - id: tests |
-
outcome:应用continue-on-error之前的原始结果。 -
conclusion:应用之后的最终结果。
needs
1 | - run: echo "${{ needs.build.outputs.artifact-name }}" |
matrix
1 | - run: echo "Node.js ${{ matrix.node }}" |
inputs
手动触发或复用 Workflow 的输入:
1 | - run: echo "Environment=${{ inputs.environment }}" |
10.2 运算符
1 | if: github.ref == 'refs/heads/main' |
在 YAML 中以 ! 开头容易被当成 YAML Tag,最好保留 ${{ }}:
1 | if: ${{ !cancelled() }} |
10.3 常用函数
1 | if: startsWith(github.ref, 'refs/tags/v') |
JSON 转换:
1 | env: |
调试 Context:
1 | - name: Dump GitHub context |
不要随意输出完整 secrets、Token 或包含敏感请求信息的 Context。
十一、环境变量、配置变量和 Secret
11.1 作用域优先级
环境变量可定义在 Workflow、Job 或 Step:
1 | env: |
越具体的作用域优先级越高。
11.2 跨 Step 设置环境变量
1 | - name: Set variable |
写入 $GITHUB_ENV 后只对后续 Step 生效,当前 Step 中不会自动出现新值。
11.3 添加 PATH
1 | - run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" |
11.4 Secret
在仓库的 Settings → Secrets and variables → Actions 中配置:
1 | env: |
注意:
-
Secret 不应直接写入仓库。
-
GitHub 会尝试遮蔽日志中的 Secret 原值,但不要依赖遮蔽来弥补主动输出。
-
来自 Fork 的
pull_request默认无法读取普通 Secret。 -
Dependabot 触发的工作流也受到 Secret 和 Token 权限限制。
-
Secret 不能可靠地直接用于
if,可以先映射到 Job 环境变量。
示例:
1 | jobs: |
十二、条件执行 if
12.1 分支和标签条件
1 | if: github.ref == 'refs/heads/main' |
1 | if: startsWith(github.ref, 'refs/tags/v') |
12.2 事件条件
1 | if: github.event_name == 'workflow_dispatch' |
12.3 Job 成功、失败或取消
默认相当于 success():
1 | - run: echo "Only on success" |
失败时上传日志:
1 | - name: Upload failure logs |
无论前面结果如何都执行清理:
1 | - name: Cleanup |
更适合多数清理和汇总任务的写法:
1 | if: ${{ !cancelled() }} |
always() 在任务被取消时仍可能执行,某些网络操作会拖延取消过程。
12.4 Draft PR 跳过测试
1 | jobs: |
十三、Job 依赖和输出
13.1 needs
Job 默认并行。使用 needs 设置依赖:
1 | jobs: |
依赖多个 Job:
1 | deploy: |
13.2 Step 输出传给 Job
1 | jobs: |
输出适合少量文本。文件应通过 Artifact 传递。
13.3 多行输出
1 | - id: notes |
如果内容可能包含 EOF,应使用随机且不会出现在内容中的分隔符。
十四、Matrix 测试矩阵
14.1 Node.js 多版本
1 | jobs: |
该配置创建 3 个并行 Job。
14.2 多操作系统和多版本
1 | strategy: |
一共创建 3 × 2 = 6 个 Job。
14.3 排除组合
1 | strategy: |
14.4 添加特殊组合
1 | strategy: |
14.5 失败策略
1 | strategy: |
-
fail-fast: true:一个普通矩阵 Job 失败后,取消其他进行中的矩阵 Job。 -
fail-fast: false:让所有组合都运行完,便于看到完整兼容性结果。 -
max-parallel:限制同时运行数量。
实验版本允许失败:
1 | continue-on-error: ${{ matrix.experimental }} |
十五、缓存 Cache
缓存用于复用依赖下载数据,提高后续 Workflow 速度。缓存不是构建产物,也不能保证永久存在。
15.1 setup-node 自动缓存 npm
1 | - uses: actions/setup-node@v6 |
setup-node 缓存 npm 的全局下载缓存,不直接缓存 node_modules。npm ci 仍会根据 lockfile 创建干净依赖树。
Monorepo 多个 lockfile:
1 | cache-dependency-path: | |
15.2 actions/cache
1 | - name: Cache build data |
15.3 缓存键
好的 Key 通常包含:
-
操作系统。
-
运行时版本。
-
lockfile 哈希。
-
必要时加入配置版本。
1 | key: npm-${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} |
15.4 缓存安全
-
不要缓存 Secret、Token、
.npmrc认证文件。 -
Fork PR 可能读取基础分支创建的缓存。
-
不可信代码可能尝试缓存投毒。
-
发布任务优先考虑禁用缓存,以降低供应链风险。
-
Cache 命中不代表可以跳过
npm ci或完整性检查。
十六、构建产物 Artifact
Artifact 用于保存或跨 Job 传递文件,例如:
-
编译结果。
-
测试报告。
-
覆盖率报告。
-
安装包。
-
失败日志。
16.1 上传
1 | - name: Upload dist |
16.2 下载
1 | jobs: |
16.3 Cache 与 Artifact 的区别
-
Cache:优化速度,可被后续运行复用,可能被清理,不适合发布交付。
-
Artifact:保存本次运行结果,可下载或供后续 Job 使用,有明确保留期限。
十七、容器和服务数据库
17.1 Job 运行在容器中
1 | jobs: |
17.2 PostgreSQL 服务
1 | jobs: |
17.3 Redis 服务
1 | services: |
服务容器主要用于 Linux Runner。真实项目应固定合适的镜像版本,避免 latest 引入意外变化。
十八、手动、定时和外部触发
18.1 手动触发 workflow_dispatch
1 | on: |
使用输入:
1 | - run: | |
常用输入类型:
-
string -
boolean -
choice -
number -
environment
命令行触发:
1 | gh workflow run deploy.yml \ |
18.2 定时任务
1 | on: |
表示每周一 UTC 02:00。Cron 字段:
1 | ┌──────── 分钟 0-59 |
注意:
-
GitHub Actions Cron 使用 UTC。
-
最短间隔通常为 5 分钟。
-
高峰期可能延迟,不适合秒级准时任务。
-
Scheduled Workflow 使用默认分支上的 Workflow 文件。
多个时间表可以读取触发它的表达式:
1 | on: |
18.3 外部触发 repository_dispatch
1 | on: |
调用 API:
1 | gh api repos/OWNER/REPO/dispatches \ |
读取数据:
1 | - run: echo "${{ github.event.client_payload.version }}" |
18.4 一个 Workflow 完成后触发
1 | on: |
workflow_run 可能拥有比原 Workflow 更高的权限。不要让低权限、不可信 Workflow 通过 Artifact、Cache 或输出向高权限 Workflow 注入可执行内容。
十九、复用 Workflow 和 Composite Action
19.1 可复用 Workflow
被调用文件 .github/workflows/reusable-test.yml:
1 | name: Reusable test |
调用:
1 | jobs: |
跨仓库调用:
1 | jobs: |
调用可复用 Workflow 的 uses 位于 Job 级别,不放在 steps 中。
19.2 可复用 Workflow 输出
1 | on: |
调用方:
1 | jobs: |
19.3 Composite Action
适合复用一组 Step。创建 .github/actions/setup-project/action.yml:
1 | name: Setup project |
调用本地 Composite Action 前必须先检出仓库:
1 | steps: |
选择建议:
-
复用整个 Job 或标准发布流程:Reusable Workflow。
-
在多个 Job 中复用若干 Step:Composite Action。
-
只复用一行命令:Shell/npm script 通常更简单。
二十、Environment、部署审批和 OIDC
20.1 Environment
仓库可配置 staging、production 等 Environment:
1 | jobs: |
Environment 可配置:
-
审批人。
-
等待时间。
-
允许部署的分支或标签。
-
Environment 专属 Secret 和变量。
生产部署示例:
1 | on: |
20.2 OIDC 是什么
传统发布需要把长期 Token 保存为 Secret。OIDC 的流程是:
1 | Workflow |
优势:
-
不保存长期发布凭证。
-
凭证只在本次 Job 中短期有效。
-
平台可以限制仓库、Workflow、分支和 Environment。
-
降低 Token 泄漏及轮换成本。
20.3 OIDC 基础权限
1 | permissions: |
id-token: write 只允许请求 OIDC Token,并不会自动赋予修改仓库或云资源的权限。
20.4 npm Trusted Publishing
1 | name: Publish |
还必须在 npmjs.com 包设置中配置 Trusted Publisher,确保以下信息一致:
-
GitHub owner / organization。
-
Repository。
-
Workflow 文件名。
-
可选的 Environment。
-
Allowed action 是
npm publish。
npm Trusted Publishing 当前要求 Node.js >= 22.14.0、npm >= 11.5.1,并使用受支持的云托管 Runner。本项目的 Node.js 24 满足要求,工作流还会显式检查 npm 最低版本。OIDC 发布会自动生成 provenance。
20.5 GitHub Release 权限
如果发布后还要创建 GitHub Release:
1 | permissions: |
可以拆成两个 Job,让 npm 发布 Job 不拥有仓库写权限:
1 | jobs: |
二十一、安全最佳实践
21.1 最小权限
1 | permissions: |
只在需要的 Job 中增加 write。
21.2 固定第三方 Action
最严格方式:
1 | uses: third-party/action@完整40位commitSHA # v2.3.1 |
GitHub 官方也建议固定 Action 到完整 SHA。Dependabot 可帮助更新 Action 版本。
.github/dependabot.yml 示例:
1 | version: 2 |
21.3 不要把不可信输入直接拼入 Shell
危险:
1 | - run: echo "${{ github.event.pull_request.title }}" |
攻击者可能构造包含 Shell 语法的 PR 标题。
更安全:
1 | - env: |
表达式由 GitHub 在脚本执行前替换;通过环境变量传递可以避免内容被解释成脚本源码。
21.4 谨慎使用 pull_request_target
可以安全用于:
-
添加标签。
-
评论 PR。
-
检查 PR 元数据。
不要:
-
检出 Fork PR 的 HEAD 后运行其脚本。
-
安装 Fork 修改过的依赖。
-
把高权限 Token 交给不可信代码。
21.5 不记录 Secret
避免:
1 | - run: env |
21.6 审查依赖安装脚本
npm ci 可能执行依赖的生命周期脚本。发布任务应:
-
使用提交到仓库的 lockfile。
-
审查 lockfile 变化。
-
使用 Dependabot/Renovate。
-
根据 npm 版本采用脚本 allowlist 等安全机制。
-
避免发布阶段动态安装未固定的
latest工具。
21.7 限制超时和并发
1 | timeout-minutes: 20 |
既避免无限等待,也减少异常任务消耗。
21.8 Environment 审批
生产部署使用受保护 Environment,并要求人工审批。即使 Workflow 被错误触发,也不会立即部署。
21.9 Fork、Artifact 和 Cache
来自不可信代码的 Artifact 或 Cache 也可能包含恶意内容。高权限 Workflow 不应下载并执行低权限 Workflow 产生的任意二进制或脚本。
二十二、调试与排错
22.1 查看日志
在 GitHub 仓库 Actions 页面中:
-
选择 Workflow。
-
选择某次运行。
-
选择 Job。
-
展开失败 Step。
使用 GitHub CLI:
1 | gh run list |
22.2 重新运行
1 | gh run rerun RUN_ID |
重新运行时:
-
github.run_id不变。 -
github.run_attempt增加。 -
使用原运行对应的 commit。
22.3 输出调试信息
1 | - name: Debug |
创建 Repository Secret:
1 | ACTIONS_STEP_DEBUG=true |
可启用更详细的 Step 调试日志。需要时临时开启,排查后删除。
22.4 Job Summary
1 | - name: Write summary |
Summary 会显示在运行概览页面,比在长日志中查找结果更方便。
22.5 本地检查 YAML
基础语法检查:
1 | ruby -e 'require "yaml"; YAML.load_file(".github/workflows/ci.yml", aliases: true)' |
更推荐安装 actionlint:
1 | brew install actionlint |
普通 YAML 解析器只能检查 YAML 是否有效,无法完整理解 GitHub Actions 的 Context、Action 参数和事件语义。
22.6 为什么 Workflow 没有触发
检查:
-
文件是否位于
.github/workflows/。 -
Workflow 是否已存在于默认分支。
-
分支、标签和路径过滤是否匹配。
-
YAML 是否有效。
-
仓库是否禁用了 Actions。
-
Fork Workflow 是否等待维护者批准。
-
commit message 是否使用了跳过 CI 的标记。
-
定时 Workflow 是否因仓库长期无活动而被禁用。
22.7 为什么 Secret 是空的
常见原因:
-
Secret 名称拼写错误。
-
Fork PR 不提供 Secret。
-
Dependabot 运行受到限制。
-
使用的是 Environment Secret,但 Job 没有声明对应
environment。 -
Secret 只配置在组织中,但仓库未被授权使用。
22.8 为什么后续 Job 找不到文件
每个 Job 通常使用不同 Runner。使用 Artifact:
1 | # Job A |
22.9 为什么环境变量在下一步不存在
普通 Shell export 只影响当前 Step:
1 | - run: export VERSION=1.0.0 |
应写入:
1 | - run: echo "VERSION=1.0.0" >> "$GITHUB_ENV" |
二十三、常用完整模板
23.1 Node.js CI
1 | name: CI |
23.2 多平台测试
1 | name: Cross-platform CI |
23.3 构建并保存 Artifact
1 | name: Build |
23.4 手动部署
1 | name: Deploy |
23.5 Docker 发布到 GHCR
1 | name: Publish image |
实际使用时把占位符替换为官方发布页对应版本的完整 SHA。
23.6 PR 失败时上传日志
1 | name: Test with diagnostics |
二十四、常见问题
Q1:name、Job ID、Step name 有什么区别?
1 | name: CI # Workflow 名称 |
Q2:为什么 run 之前通常要 checkout?
Runner 默认没有仓库文件。actions/checkout 把对应 commit 检出到 $GITHUB_WORKSPACE。
Q3:不同 Step 是否共享文件?
同一 Job 中共享。不同 Job 通常不共享,需要 Artifact。
Q4:不同 Step 是否共享 export 的环境变量?
不共享。写入 $GITHUB_ENV 才能传给后续 Step。
Q5:${{ }} 和 $VAR 有什么区别?
-
${{ }}:由 GitHub Actions 在 Step 运行前求值。 -
$VAR:由 Linux/macOS Shell 在运行时读取。 -
PowerShell 通常使用
$env:VAR。
Q6:为什么连续 push 后旧 CI 被取消?
Workflow 设置了相同 concurrency.group 和 cancel-in-progress: true。
Q7:为什么发布 Workflow 不取消旧任务?
发布包含不可逆的外部操作。中途取消可能导致 npm、GitHub Release 状态不一致。
Q8:为什么 Job 默认并行?
没有 needs 依赖的 Job 彼此独立。使用:
1 | job-b: |
即可改成串行依赖。
Q9:Action 的 @v6 是 npm 版本吗?
不是。它是 Action 仓库的 Git 标签。actions/setup-node@v6 表示 setup-node Action v6,node-version: "24" 才是 Node.js 版本。
Q10:Workflow 可以修改仓库吗?
可以,但必须给 GITHUB_TOKEN 对应写权限,例如 contents: write。分支保护规则仍可能限制直接 push。
Q11:为什么 Fork PR 读取不到 Secret?
这是安全设计,防止外部贡献者修改 Workflow 后输出或上传 Secret。
Q12:npm ci 和 npm install 在 CI 中如何选择?
有 lockfile 时优先 npm ci:
-
按 lockfile 严格安装。
-
不修改 lockfile。
-
依赖不一致时直接失败。
-
更适合可重复构建。
Q13:可以在本地完整模拟 GitHub Actions 吗?
可以使用第三方工具做部分模拟,但 Runner 镜像、权限、OIDC、Secret、GitHub 事件和托管服务无法保证完全一致。最终仍应以 GitHub Actions 实际运行结果为准。
Q14:修改 Workflow 后如何安全验证?
-
运行 YAML/actionlint 检查。
-
先在功能分支通过
pull_request验证低权限 CI。 -
为部署流程增加
workflow_dispatch的 dry-run 输入。 -
使用 staging Environment。
-
对发布流程严格校验标签和版本。
-
不要用真实版本反复测试不可撤销的 npm publish。
二十五、官方参考资料
GitHub Actions 和各个 Action 会持续更新。编写新 Workflow 或升级主要版本时,应重新查看官方文档及对应 Action 的 Release Notes。