是否可以在 Github 操作中共享或重用某些作业步骤?

bai*_*idz 0 github-actions

给出以下示例 Github 操作工作流程

name: My workflow

on: pull_request

jobs:
  foo:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.19

      - name: Foo
        run: echo "foo"

  bar:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.19

      - name: Bar
        run: echo "bar"
Run Code Online (Sandbox Code Playgroud)

我希望这些工作FooBar并行运行。但正如您所看到的,它们有一些共同的步骤。

是否可以创建一个运行结帐和设置步骤并提供自身的作业FooBar以便他们只需运行自己的命令?(这会节省一些时间,但我认为这是不可能的,因为这两个作业都在单独的容器中运行)

如果这是不可能的,有没有办法提取“重复”行并将它们移动到我可以在工作中调用的“步骤函数”,这样我就不必一遍又一遍地编写这些步骤?

Fcm*_*am5 6

您可以使用缓存来节省一些时间:https://docs.github.com/en/actions/using-workflows/caching-dependency-to-speed-up-workflows并合并“YAML 文件中的重复行”在每项工作中,您可能都希望有一个复合动作,您基本上可以在其中提取

steps:
  - name: Checkout repository
    uses: actions/checkout@v3
    with:
      fetch-depth: 0

  - name: Setup Go
    uses: actions/setup-go@v3
    with:
      go-version: 1.19
Run Code Online (Sandbox Code Playgroud)

您可以在工作流程文件中使用的新操作如下所示:

name: My workflow

on: pull_request

jobs:
  foo:
    runs-on: ubuntu-latest
    steps:
      - name: My composite action
        uses: path/to/action

      - name: Foo
        run: echo "foo"

  bar:
    runs-on: ubuntu-latest
    steps:
      - name: My composite action
        uses: path/to/action

      - name: Bar
        run: echo "bar"
Run Code Online (Sandbox Code Playgroud)

请注意,如果您想在同一个存储库中创建此复合操作,则必须在actions/checkout@v3使用相对 URL 调用它之前使用。

所以它将是:

name: My workflow

on: pull_request

jobs:
  foo:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: My composite action
        uses: ./.github/actions/my-action.yaml

      - name: Foo
        run: echo "foo"

  bar:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: My composite action
        uses: ./.github/actions/my-action.yaml
    
      - name: Bar
        run: echo "bar"
Run Code Online (Sandbox Code Playgroud)

是的,如果您只有几步,这种方法可能不会给您带来太大价值。因为您可能只在 YAML 文件中保存几行,并且只能缓存您的依赖项安装

而且,这并不意味着您的“共享/复合”操作只会运行一次,Github 将为调用它们的每个作业重新运行每个步骤(foobar您的情况下)。


另一种方法是,整合您在管道中运行的某些步骤,即创建一个将在其中运行您的操作的Docker 映像,此基础 Docker 映像可能具有您所需的设置,例如:GoLang,以及您必要的构建和测试模块安装。

name: My workflow

on: pull_request

jobs:
  foo:
    runs-on: ubuntu-latest
    container: mydocker.image.uri/name:version
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Foo
        run: echo "foo"

  bar:
    runs-on: ubuntu-latest
    container: mydocker.image.uri/name:version
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Bar
        run: echo "bar"
Run Code Online (Sandbox Code Playgroud)

这种方法的好处是,您可以从工作流程文件中删除一些行,并将一些设置步骤提取到基础 Docker 映像中,您将在其中运行操作。

关于缺点,构建一个稳定的基础映像以及运行步骤所需的设置可能有点困难。此外,您还需要维护 CI/CD 管道的另一部分。


另一种解决方案是使用执行矩阵(带有 缓存依赖文件和构建输出),它将为每个矩阵值运行并行作业(它们将根据运行程序的可用性或您的max-parallel值进行并行化)

name: My workflow

on: pull_request
   
jobs:
  foo:
    runs-on: ubuntu-latest
    strategy:
      matrix: 
        greeting: ["hello", "bonjour"]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
      
      - name: Setup Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.19
          cache: true

      - name: Saying ${{ matrix.greeting }}
        run: echo "${{ matrix.greeting }}!"
Run Code Online (Sandbox Code Playgroud)

步骤并行运行

正如您所看到的,所有步骤都会重新运行:

步骤示例

如果您要做的不仅仅是 GoLang 设置,而是执行可能需要花费大量时间的步骤,这可能并不有趣


我想到的最后一个选择是使用依赖作业这可能不适用于此用例。但是,如果您可以重新设计工作流程以生成输出,或者从第一步调用的二进制文件,那么这可能是一个解决方案,baz那么您的工作流程将具有

  foo:
    runs-on: ubuntu-latest
    needs: baz
    steps:
     - name: Something
       run: echo "baz is saying: ${{ needs.baz.outputs.greeting }}"
Run Code Online (Sandbox Code Playgroud)

我希望这对您有所帮助或给您更多关于如何进一步优化此工作流程的想法!