133

我对 GitHub Actions 比较陌生,我有 2 个工作——一个运行我的测试,另一个将我的项目部署到服务器上。

显然我希望测试在每个分支上运行,但部署应该只在某些东西被推送到 master 时发生。

我正在努力寻找一种在特定分支上运行工作的方法。我知道可以只在特定分支上运行整个工作流程,但这意味着我将拥有一个“测试”工作流程和一个“部署”工作流程。

这听起来像是一个解决方案,但是它们会并行运行。在理想情况下,测试将首先运行,并且只有当它们成功时,才会开始部署作业。使用 2 个单独的工作流程时情况并非如此。

我怎么能做到这一点?是否可以在特定分支上运行作业?

4

6 回答 6

170

在最近的更新中,您现在可以将if条件置于job级别。请参阅此处的文档。https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idif

我测试了这个工作流,它test在每次推送时运行该作业,但只deploy在主分支上运行。

name: my workflow
on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Execute tests
        run: exit 0
  deploy:
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/master'
    steps:
      - name: Deploy app
        run: exit 0

以下是我的原始答案,如果您希望拥有单独的工作流程,还有一个替代解决方案。

第一个工作流针对除master. 在此工作流程中,您仅运行测试。

on:
  push:
    branches:
      - '*'
      - '!master'

master如果测试成功通过,第二个工作流程将运行并运行您的测试和部署。

on:
  push:
    branches:
      - master
于 2019-09-28T00:12:36.020 回答
29

这是我为仅应在特定分支上运行的步骤所做的。

- name: Publish Image
  # Develop branch only
  if: github.ref == 'refs/heads/develop'
  run: |
    ... publish commands ...
于 2019-10-03T22:00:42.437 回答
26

大多数答案都为一个分支提供了解决方案。要限制作业在任何特定的分支集上运行,您可以使用if带有多个析取 ( ||) 运算符的条件来执行此操作;但这太冗长了,不尊重DRY 原则

使用该contains功能可以以更少的重复次数进行归档。

使用contains

contains('
  refs/heads/dev
  refs/heads/staging
  refs/heads/production
', github.ref)

与使用多个相比||

github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/staging' || github.ref == 'refs/heads/production' || …

完整示例:

---
on: push
jobs:
  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Run tests
      run: …

  deployment:
    name: Deployment
    runs-on: ubuntu-latest
    needs: [test]
    if:
      contains('
        refs/heads/dev
        refs/heads/staging
        refs/heads/production
      ', github.ref)
    steps:
    - uses: actions/checkout@v2
    - name: Deploy
      run: …
于 2020-06-17T00:29:12.650 回答
14

2021 年更新

我知道可以只在特定分支上运行整个工作流程,但这意味着我将拥有一个“测试”工作流程和一个“部署”工作流程。

这听起来像是一个解决方案,但是它们会并行运行。在理想情况下,测试将首先运行,并且只有当它们成功时,才会开始部署作业。使用 2 个单独的工作流程时情况并非如此。

您现在可以使用该事件workflow_run来实现该部分the tests would run first, and only if they succeed, then the deploy job would start(继续阅读以了解如何):

文档页面workflow_run

https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#workflow_run

此事件在请求或完成工作流运行时发生,并允许您根据另一个工作流的完成结果执行工作流。无论先前工作流的结果如何,都会触发工作流运行。

例如,如果您的 pull_request 工作流生成构建工件,您可以创建一个使用 workflow_run 来分析结果并向原始拉取请求添加注释的新工作流。

现在,考虑到 OP 的初始问题:

我希望测试在每个分支上运行,但部署应该只在有东西被推送到时才会发生master

现在可以这样解决:

以下设置正在运行,几分钟前我刚刚在我的一个存储库中实现了相同的逻辑

工作流程<your_repo>/.github/workflows/tests.yml

name: My tests workflow

on:
  push:
    branches:
      - master
  pull_request: {}

jobs:
  test:

    # ... your implementation to run your tests

工作流程<your_repo>/.github/workflows/deploy.yml

name: My deploy workflow

on:
  workflow_run:
    workflows: My tests workflow # Reuse the name of your tests workflow
    branches: master
    types: completed

jobs:
  deploy:
    # `if` required because a workflow run is triggered regardless of
    # the result of the previous workflow (see the documentation page)
    if: ${{ github.event.workflow_run.conclusion == 'success' }}

    # ... your implementation to deploy your project
于 2021-10-27T18:36:29.527 回答
2

虽然此时您无法在作业级别设置条件,但您可以在步骤级别设置条件 - 请参阅GitHub Actions 的上下文和表达式语法

要获取分支名称,当前的解决方案是检查GITHUB_REF环境变量 - 有关详细信息,请参阅默认环境变量这个问题

将它们放在一起 - 如果您决定在最后一个链接中接受已接受的答案,您的工作流程可能如下所示:

jobs:

 test:
  runs-on: ubuntu-latest
  steps:
  - name: Run tests
    run: ./my-tests.sh

 deploy:
  runs-on: ubuntu-latest
  needs: test
  steps:
  - name: Extract branch name
    shell: bash
    run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/})"
    id: extract_branch
  - name: Deploy
    run: ./deploy.sh
    if: steps.extract_branch.outputs.branch == 'master'

如果您希望将所有内容保存在工作流文件中而不是单独的脚本中,您可以随时添加if到给定作业的每个步骤中。


我希望这只是一个临时解决方案/解决方法,并且将在 beta 结束之前添加工作条件。

于 2019-09-28T01:10:36.303 回答
1

以下内容在工作中为我工作:

PR 目标分支是以下之一:
if: contains(github.base_ref, 'staging')
  || contains(github.base_ref, 'production')
当拉取请求的源分支是以下之一时:
if: contains(github.head_ref, 'feature')
  || contains(github.head_ref, 'release')
于 2021-08-21T22:52:33.553 回答