我对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条件和多个分离操作符(||);但这太啰嗦了,不尊重DRY原则。
使用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条件放在工作级别。请在这里查看文档。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