只能使用 GitHub 操作在特定的分支上运行作业

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

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

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

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

我如何才能做到这一点? 是否可能在一个特定的分支上运行 工作

103135 次浏览

在最近的更新中,您现在可以将 if条件句放在 job

我测试了这个工作流程,它在每次推送时运行作业 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

虽然你不能有条件在 工作水平在这一刻,你可以有条件在 台阶水平-见 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添加到给定作业的每个步骤中。


我希望这只是一个临时的解决方案/变通方案,在测试版结束之前会添加工作条件。

下面是我为应该只在特定分支上运行的步骤所做的工作。

- name: Publish Image
# Develop branch only
if: github.ref == 'refs/heads/develop'
run: |
... publish commands ...

大多数答案为 单分支提供了解决方案。为了限制作业在 任何特定的分支集上运行,您可以使用带有多个分离(||)操作符的 if条件操作; 但是这样做太冗长,而且不尊重 干燥原理

使用 强 > 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: …

下面这些对我的工作有帮助:

公关目标分支机构如属下列情况之一:
if: contains(github.base_ref, 'staging')
|| contains(github.base_ref, 'production')
当 pull 请求的源分支是下面的分支之一时:
if: contains(github.head_ref, 'feature')
|| contains(github.head_ref, 'release')

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 工作流生成构建构件, 您可以创建一个新的工作流,该工作流使用工作流 _ 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

对于步骤或作业,您还可以使用 github.ref_name,它是触发工作流运行的分支或标记名称。

name: my workflow
on: push
jobs:
if: github.ref_name == 'main'
test:
runs-on: ubuntu-latest
steps:
- name: Execute tests
run: exit 0

有关 github 上下文的更多信息,请检查 给你

您需要将这两个脚本添加到工作流中

//main.yml
name: main
on:
push:
branches:
- main




//size.yml
name: size
on:
pull_request:
branches:
- main
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 条件是这样包装的 if: $\{\{ github.ref == 'refs/heads/main' }}

已经有一些很好的答案了,这里有一个在条件句中指定多个分支的方法:

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

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

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

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

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

  1. 从存储库设置,创建一个 production环境
  2. Deployment Branches下拉列表中选择 Selected Branches,并在模式中添加 main
  3. 在生产环境秘密中添加 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

环境信息表明秘密的来源。如果当前的分支名称与 Selected Branches中提供的模式不匹配,那么作业将立即失败并出现错误。因为我们有一个条件只能在 main上运行这个任务,所以通常这不会困扰我们,因为这个任务无论如何都会在其他分支上被跳过。但是,如果有人错误地或出于恶意地修改了 yml 文件,并在推动分支之前删除了该条件,那么他们将得到一个错误。所以,我们的系统仍然是安全的,至少在这里的威胁。

希望这对任何想知道的人都有帮助。

二零二二年

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

name: Distribute to Firebase


on:
push:
branches: [ main ]
jobs:
...