如何配置GitHub Actions仅在main分支推送时执行Build和Deploy作业
我有一个包含测试、构建和部署流程的GitHub Actions工作流,这是较为常见的配置。我希望test作业能在main分支以及针对main分支的拉取请求(PR)中运行,但build和deploy作业仅在推送到main分支时执行,该如何安全配置?我的简化版
.github/workflows/ci.yml配置如下:
name: CI on: push: branches: ["main"] pull_request: branches: ["main"] jobs: test: runs-on: ubuntu-latest steps: - name: "Lint, Test and Report" run: echo "running linter, then tests then report on this" build: needs: test runs-on: ubuntu-latest steps: - name: "Build" run: echo "Building the artifacts" deploy: needs: - test - build runs-on: ubuntu-latest steps: - name: "Deploy to Production" run: echo "Drumroll...."
我未找到能标识当前为PR的环境变量或github.x属性,是否可以通过匹配分支名称,比如使用
if: startsWith(github.ref, 'refs/heads/main')来确保仅在main分支时运行?
解决方案
要实现这个需求,通过作业级别的if条件判断就能精准控制各作业的运行时机,比单纯匹配分支名称更可靠:
1. 保留Test作业的现有触发逻辑
你当前的触发规则已经能让test作业在main分支推送、以及针对main的PR中自动运行,这部分无需修改。
2. 给Build和Deploy作业添加运行条件
直接在build和deploy作业中添加if条件,限定它们只在推送到main分支的场景下执行:
- 用
github.event_name == 'push'确保是推送事件,而非PR事件 - 配合
github.ref == 'refs/heads/main'确保推送的目标是main分支
修改后的完整配置如下:
name: CI on: push: branches: ["main"] pull_request: branches: ["main"] jobs: test: runs-on: ubuntu-latest steps: - name: "Lint, Test and Report" run: echo "running linter, then tests then report on this" build: needs: test runs-on: ubuntu-latest # 仅在推送到main分支时执行 if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: "Build" run: echo "Building the artifacts" deploy: needs: - test - build runs-on: ubuntu-latest # 仅在推送到main分支时执行 if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: "Deploy to Production" run: echo "Drumroll...."
关于分支匹配方式的说明
你提到的startsWith(github.ref, 'refs/heads/main')确实能匹配main分支,但如果存在main-beta这类前缀相同的分支,会出现误匹配。直接用github.ref == 'refs/heads/main'更精准。另外,结合github.event_name == 'push'可以彻底排除PR场景——因为PR事件的github.event_name是pull_request,此时即使分支名看起来像main,也不会触发build和deploy。
补充:识别PR的官方属性
其实GitHub Actions提供了明确识别PR的属性:
github.event_name == 'pull_request':直接判断当前是PR事件github.event.pull_request.base.ref == 'main':可判断PR的目标分支是main(不过你的触发规则已经限定了PR针对main,所以这个在当前场景下不是必须)
内容的提问来源于stack exchange,提问作者berkes

