4. 工作流触发器详解
工作流触发器决定了 GitHub Actions 在什么条件下被唤醒。一个工作流可以同时监听多个事件,每个事件又可以叠加分支过滤、路径过滤、活动类型过滤和参数约束。理解触发器的关键,不是记住事件名称,而是建立“事件源 → 过滤条件 → 触发结果”的判断链:谁产生了事件、事件携带了哪些字段、哪些字段会被 on 下的过滤器拦截、最终哪些作业会进入运行队列。
GitHub Actions 的触发器大致分为四类:代码托管事件(push、pull_request、create、release 等)、定时事件(schedule)、手动事件(workflow_dispatch)和外部事件(repository_dispatch、workflow_call)。本节重点讨论最常用的五种:push、pull_request、schedule、workflow_dispatch、repository_dispatch。
push:最基础的代码推送触发
push 在提交被推送到仓库时触发。默认情况下,任何分支的推送都会触发工作流,这通常不是我们想要的。通过 branches 和 branches-ignore 可以限定分支,通过 paths 和 paths-ignore 可以限定文件路径。需要注意:branches 与 branches-ignore 不能同时出现在同一个事件下,paths 与 paths-ignore 同理。
on:
push:
branches:
- main
- 'release/**'
paths:
- 'src/**'
- 'package.json'
- '!src/**/*.md'
tags:
- 'v*'
上面的配置表示:只有推送到 main 或 release/ 开头的分支,且改动涉及 src/ 或 package.json,同时排除 src/ 下的 Markdown 文件时,工作流才会运行;此外,推送 v 开头的标签也会触发。路径过滤使用 glob 语法,! 前缀表示排除,多个模式按顺序匹配,后面的规则可以覆盖前面的规则。
一个常见误区是:paths 过滤基于两次提交之间的差异文件列表。如果一次推送包含多个提交,GitHub 会计算推送前后的差异,而不是逐个提交判断。因此,合并分支时即使只改了一个文件,也可能因为合并带来的差异范围较大而触发工作流。
pull_request:PR 生命周期触发
pull_request 在 PR 被打开、同步、重新打开、标记为可审查等时刻触发。它比 push 多了一个关键概念:活动类型(types)。默认活动类型是 opened、synchronize、reopened,如果显式指定 types,默认值会被覆盖。
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- main
paths:
- 'src/**'
- 'tests/**'
这里 branches 过滤的是 PR 的目标分支,而不是源分支。也就是说,只有目标为 main 的 PR 才会触发。如果希望过滤源分支,需要使用 head 字段(部分场景支持)。pull_request 还有一个重要变体 pull_request_target,它在目标分支的上下文中运行,拥有写权限和 secrets,适合做标签、评论等操作,但绝不能直接检出并执行 PR 中的不可信代码,否则会造成严重的安全风险。
schedule:定时触发
schedule 使用 POSIX cron 语法,时间基准是 UTC。它只会在默认分支上运行,且最短间隔为 5 分钟。GitHub 的定时任务在高峰期可能延迟,因此不适合对时间精度要求极高的场景。
on:
schedule:
- cron: '0 2 * * 1-5' # 工作日 UTC 02:00
- cron: '30 14 * * 0' # 周日 UTC 14:30
上面的配置表示工作日每天 UTC 02:00 以及周日 UTC 14:30 各触发一次。如果团队在北京时间工作,需要把本地时间减去 8 小时换算成 UTC。例如希望北京时间每天 10:00 运行,应写成 0 2 * * *。定时工作流常用于夜间构建、依赖扫描、数据同步等场景。
workflow_dispatch:手动触发与参数
workflow_dispatch 允许在 GitHub 界面或通过 API 手动触发工作流,并支持定义输入参数。参数类型包括 string、boolean、choice 和 environment。
on:
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options: [staging, production]
dry_run:
description: '仅演练不实际部署'
required: false
default: true
type: boolean
version:
description: '版本号'
required: true
type: string
在作业中通过 github.event.inputs.environment 或 inputs.environment 读取参数。布尔类型在 github.event.inputs 中会变成字符串 'true' 或 'false',而在 inputs 上下文中保持布尔值,因此推荐使用 inputs 上下文。手动触发非常适合发布、回滚、数据修复等需要人工确认的操作。
repository_dispatch:外部系统触发
repository_dispatch 允许通过 REST API 从外部系统触发工作流,常用于跨仓库联动、第三方服务回调等。它需要指定一个自定义的 event_type,并可携带 client_payload 作为数据载荷。
on:
repository_dispatch:
types: [build-request, cache-invalidate]
触发方式为向 POST /repos/{owner}/{repo}/dispatches 发送请求,请求体包含 event_type 和可选的 client_payload。工作流中通过 github.event.client_payload 读取载荷。注意:repository_dispatch 只在默认分支上触发,且需要具有 repo 权限的 token。
触发器组合与过滤优先级
当多个事件同时配置时,任意一个事件满足条件都会触发工作流。过滤条件的判断顺序是:先判断事件类型是否匹配,再判断活动类型是否在 types 列表中,然后判断分支/标签是否匹配,最后判断路径是否匹配。只有全部通过,工作流才会进入运行队列。
实践建议与常见排障
配置触发器时,建议遵循“最小触发面”原则:能用路径过滤就不要全仓库触发,能用分支过滤就不要全分支触发。对于 pull_request,如果只需要在 PR 合并前做检查,使用默认活动类型即可;如果需要在 PR 被标记为可审查时才运行,显式添加 ready_for_review。
常见问题包括:工作流没有触发,通常是因为分支名或路径 glob 写错、types 覆盖了默认值、或者事件发生在非默认分支而 schedule 和 repository_dispatch 不支持。排查时可以在仓库的 Actions 页面查看事件日志,确认事件是否被接收、过滤条件是否匹配。另一个高频问题是 paths 过滤在合并提交上表现不符合预期,此时可以改用 paths-ignore 或结合 dorny/paths-filter 等 action 做更精细的判断。
on 配置为 on: [push, pull_request, workflow_dispatch],先确认工作流本身能正常运行,再逐步加上分支、路径和活动类型过滤,避免一次性配置过复杂导致难以定位问题。
pull_request_target 拥有目标分支的 secrets 和写权限,如果直接检出并执行 PR 中的代码,攻击者可以通过修改 PR 内容窃取 secrets。使用该触发器时,应只做标签、评论、状态更新等不执行不可信代码的操作。
掌握这五类触发器后,就可以根据团队的实际交付节奏组合使用:日常开发用 push 和 pull_request 做持续集成,夜间用 schedule 做定时任务,发布用 workflow_dispatch 做人工确认,跨系统协作用 repository_dispatch 做事件驱动。触发器的设计质量,直接决定了 CI/CD 流水线是否既灵敏又可控。