在 GitHub Actions 工作流中,是否有一种方法可以让多个作业重用相同的设置?

120

我最近为我的项目使用了Github Actions进行持续集成。我创建了两个独立的任务:第一个任务检查拉取请求中的代码是否被我们的linter接受,第二个任务检查代码是否通过测试套件。我喜欢这样设置的好处是,Github网页上的拉取请求会显示出两个单独的复选标记:

enter image description here

我现在遇到的问题是,工作流YAML文件中存在一些重复的代码:前3个步骤安装Lua和Luarocks。这不仅麻烦而且浪费CI时间,因为同样的操作运行了两次。有没有办法避免这种情况?使得设置代码只写在一个地方并且在工作流执行时只运行一次

但我不确定下一步应该怎么做:

  1. 我应该使用具有共享设置代码的自己的Github Action吗?
  2. 我应该创建一个已经预先安装了Lua和Luarocks的Docker镜像吗?
  3. 我应该使用单个任务?如果它们是同一个任务的步骤,那么还能有独立的linter和测试套件复选标记吗?
  4. 其他什么办法?

以下是我当前工作流程的YAML文件:

name: Github Actions CI

on: [ pull_request ]

jobs:
    lint:
        name: Lint
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v2
            - uses: leafo/gh-actions-lua@v8.0.0
            - uses: leafo/gh-actions-luarocks@v4.0.0

            - run: luarocks install luacheck
            - run: ./run-linter.sh

    test:
        name: Test
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v2
            - uses: leafo/gh-actions-lua@v8.0.0
            - uses: leafo/gh-actions-luarocks@v4.0.0

            - run: luarocks install busted
            - run: ./build-project.sh
            - run: ./run-test-suite.sh

我尝试搜索类似的问题,但找不到确切回答我的问题的内容:

  1. 在 GitHub Actions 工作流中缓存 APT 包:我不能使用此解决方案,因为我没有一种精确指定我正在使用的所有依赖项的所有版本以进行缓存的方法。我也不介意分开运行工作流程不被缓存。我更担心的是代码重复。
  2. Github actions 如何在作业之间共享工作区 / 构件?:我不想管理将构件上传到独立服务然后再删除它们的过程。
  3. 如何跨作业重用部分 Github Action 代码:在那个问题中,作业之间唯一的区别是一个变量,所以接受的答案是使用构建矩阵。但我认为构建矩阵在我的情况下不会很好地发挥作用,因为只有安装设置代码是相同的?

3个回答

45

截至2021年8月份,组合操作不再仅限于runGitHub Actions:通过动作组合减少重复

name: "Publish to Docker"
description: "Pushes built artifacts to Docker"

inputs:
  registry_username:
    description: “Username for image registry”
    required: true
  registry_password:
    description: “Password for image registry”
    required: true

runs:
  using: "composite"
  steps:
      - uses: docker/setup-buildx-action@v1

      - uses: docker/login-action@v1
        with:
          username: ${{inputs.registry_username}}
          password: ${{inputs.registry_password}}

      - uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          tags: user/app:latest

旧回答

你所需要的是复合操作(composite action),它可以帮助你重用已定义的一组步骤。

jobs:
    lint:
        name: Lint
        runs-on: ubuntu-latest
        steps:
            - uses: octocat/say-hello@v1

            - run: luarocks install luacheck
            - run: ./run-linter.sh

    test:
        name: Test
        runs-on: ubuntu-latest
        steps:
            - uses: octocat/say-hello@v1

            - run: luarocks install busted
            - run: ./build-project.sh
            - run: ./run-test-suite.sh

octocat/say-hello/action.yml:

octocat/say-hello/action.yml:

runs:
  using: "composite"
  steps: 
    - run: echo "Nice to meet you!"
      shell: pwsh

如需更多细节, 您也可以查看 ADR 这里

为什么不能简单地运行所有作业,因为每个作业可能在不同的机器上运行。

作业是一组在同一 runner 上执行的步骤。默认情况下,具有多个作业的工作流将并行运行这些作业。您还可以配置工作流以按顺序运行作业。例如,一个工作流可以有两个依次运行的作业来构建和测试代码,其中测试作业依赖于构建作业的状态。如果构建作业失败,则不会运行测试作业。


@AJNinja,现在已经支持了! - Krzysztof Madej
你能否在同一代码库中定义这个组合操作并使用它?例如,当一个 Pull Request 在代码库中被打开时,我有 4 个作业需要运行,但它们都需要相同的一系列“设置”步骤。我看到的所有示例都是操作位于单独的代码库中。 - TemporaryFix
1
当然可以在同一仓库中使用复合操作。请看这里:https://github.com/kmadof/github-actions-manual/blob/main/.github/actions/say-hello/action.yml - Krzysztof Madej

17

在GitHub Actions中,有三种主要的代码重用方式:

这篇文章描述了它们各自的优缺点。

对于你的情况,如果重复的步骤在单个工作流程中,你也可以:

  1. 将它们提取到“准备”任务中
  2. 上传构建产物
  3. 将“准备”任务添加到两个任务的“needs”关键字中
  4. 在两个任务中下载构建产物

我尝试使用上传工件路线,但速度极慢。当然,我同时上传了包含“node_modules”的仓库。但是,我认为我不应该为每个需要它的作业运行checkout和“npm i”。这是不必要的重复。 - TemporaryFix
  1. 您可以缓存节点依赖项。
  2. 您可以将重复的步骤提取到组合操作,该操作在同一工作器上运行,在作业的上下文中共享文件系统。
- Cardinal
3
是的,但组合操作只允许您分组常见任务。每个作业仍然需要执行这些常见任务,这是冗余的。应该有一种通过“needs”关键字使所有其他作业依赖的1个作业来完成应该是1次设置工作的方法。 - TemporaryFix

-4
以下代码片段应该可以为您完成工作。您可以使用一个作业并创建多个任务,而不是创建两个作业,一个用于lint,另一个用于测试。
name: Github Actions CI

on: [ pull_request ]

jobs:
    lint:
        name: Lint and Test
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v2
            - uses: leafo/gh-actions-lua@v8.0.0
            - uses: leafo/gh-actions-luarocks@v4.0.0

            - name: Install Luacheck
              run: luarocks install luacheck

            - name: Run Lint Check
            - run: ./run-linter.sh

            - name: Install Busted
              run: luarocks install busted

            - name: Build Project
              run: ./build-project.sh

            - name: Run Test Suite
            - run: ./run-test-suite.sh


1
这样做不允许代码检查工具和单元测试并行运行,也无法在解决代码检查失败之前发现单元测试失败。 - Charles Stover

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接