我对GitHub Actions相对较新,我有2个工作-一个运行我的测试,一个将我的项目部署到服务器上。

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

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

这听起来像是一个解决方案,但它们是并行的。在理想的情况下,测试将首先运行,并且只有当测试成功时,才会启动部署作业。当使用两个单独的工作流时,情况就不是这样了。

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


当前回答

虽然这个讨论很老了,但最近我遇到了同样的问题,只是稍微增加了一点。If条件检查分支是否主要工作,但如果有人推动他们的分支和更新工作流yml文件删除If条件呢?deploy作业将在其分支未被检查或合并到main中时被触发,这可能会破坏生产环境。这可能是开源项目中的一个问题。

我在任何地方都找不到答案,所以想分享我的发现。我希望这是正确的线程。

为了确保只有在特定分支中才能触发作业,可以使用环境。部署作业很可能有一些api密钥用于连接到目标服务器,这些密钥可能存储在秘密中。我们应该将它们存储在各自的环境中,而不是存储在可以在存储库中全局访问的存储库秘密中。

环境的官方文档包含了详细的解释和示例脚本,但这里分享了一个简单的示例。假设我们希望只在main更新时运行生产部署

从存储库设置中创建一个生产环境 在“部署分支”下拉菜单中选择“选定的分支”,并在模式中添加main 在生产环境机密中添加api密钥

在工作流yml中,我们只需要添加环境信息environment: production,如下所示(使用来自@peterevans的回答的脚本)

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/main'
    environment: production
    steps:
      - name: Deploy app
        run: exit 0

The environment information indicates where the secrets have to be read from. If the current branch name doesn't match the pattern provided in Selected Branches then the job will immediately fail with an error. Since we have a condition to only run this on main, normally that won't bother us because this job will be skipped on other branches anyways. But if someone, mistakenly or with ill intentions, modifies the yml file and removes the condition before pushing their branch, they'll get an error. So, our system remains secure at least from the threat here.

希望这对有同样疑惑的人有所帮助。

其他回答

在最近的更新中,您现在可以将if条件放在工作级别。请在这里查看文档。https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idif

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

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

已经有了一些很好的答案。下面是在条件语句中指定多个分支的方法:

name: my workflow
on: push
jobs:
  deploy:
    if: contains(fromJson('["refs/heads/master", "refs/heads/main"]'), github.ref)
    runs-on: ubuntu-latest
    steps:
      - name: Execute tests
        run: exit 0

2022

下面的工作流程只在主分支的推送中运行:

name: Distribute to Firebase

on:
  push:
    branches: [ main ]
jobs:
...
name: CI
on: push
jobs:
  prod-check:
    if: ${{ github.ref == 'refs/heads/main' }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to production server on branch $GITHUB_REF"

根据文档,if条件是这样包装的 如果:${{github。Ref == 'refs/heads/main'}}

2021年更新

我知道有可能只在特定的工作流上运行整个工作流 分支,然而,这意味着我将有一个“测试”工作流和一个 “部署”的工作流。 这听起来像是一个解决方案,但它们是并行的。在一个 理想的情况是,测试将首先运行,并且只有在他们成功的情况下 deploy作业将启动。当使用两个单独的时候,情况就不是这样了 工作流。

现在,您可以使用事件workflow_run来实现测试首先运行的部分,并且只有当测试成功时,才会启动部署作业(请继续阅读以了解如何执行):

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 /工作流/ tests.yml

name: My tests workflow

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

jobs:
  test:

    # ... your implementation to run your tests

工作流< your_repo > / .github /工作流/ 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