跳至主要内容

重复使用工作流

了解如何通过重复使用现有工作流来避免在创建工作流时出现重复。

概览

您可以使工作流可重复使用,而不是从一个工作流复制并粘贴到另一个工作流。然后,您和任何有权访问可重复使用工作流的人都可以从另一个工作流调用可重复使用的工作流。

重复使用工作流可避免重复。这使工作流更容易维护,并且允许您通过在其他人的工作基础上构建来更快速地创建新工作流,就像您对操作所做的那样。工作流重复使用还通过帮助您使用设计精良、已经过测试并被证明有效的那些工作流来促进最佳实践。您的组织可以建立一个可重复使用工作流库,该库可以集中维护。

下图显示了使用可重复使用工作流的正在进行中的工作流运行。

  • 在图表左侧的三个构建作业成功完成后,将运行一个名为“部署”的依赖作业。
  • “部署”作业调用一个可重复使用的工作流,该工作流包含三个作业:“暂存”、“审查”和“生产”。
  • 只有在“暂存”作业成功完成后,“生产”部署作业才会运行。
  • 当作业针对某个环境时,工作流运行会显示一个进度条,该进度条显示作业中的步骤数。在下图中,“生产”作业包含 8 个步骤,目前正在处理步骤 6。
  • 使用可重复使用的工作流来运行部署作业允许您为每个构建运行那些作业,而无需在工作流中复制代码。

Diagram of a workflow calling a reusable workflow.

使用另一个工作流的工作流称为“调用方”工作流。可重复使用的工作流是“被调用”工作流。一个调用方工作流可以使用多个被调用工作流。每个被调用工作流都在一行中引用。结果是,调用方工作流文件可能只包含几行 YAML,但在运行时可能会执行大量任务。当您重复使用工作流时,将使用整个被调用工作流,就像它是调用方工作流的一部分一样。

如果您从不同的存储库重复使用工作流,则被调用工作流中的任何操作都会像它们是调用方工作流的一部分一样运行。例如,如果被调用工作流使用 actions/checkout,则该操作将签出托管调用方工作流的存储库的内容,而不是被调用工作流的内容。

当可重复使用的工作流被调用方工作流触发时,github 上下文始终与调用方工作流关联。被调用工作流会自动获得对 github.tokensecrets.GITHUB_TOKEN 的访问权限。有关 github 上下文的更多信息,请参阅“上下文”。

您可以在包含工作流的存储库的依赖项图中,查看在您的 GitHub Actions 工作流中引用的重复使用的工作流,这些工作流作为依赖项。有关更多信息,请参阅“关于依赖项图”。

可重复使用的工作流和复合操作

可重复使用的工作流和复合操作都有助于您避免重复。可重复使用的工作流允许您重复使用整个工作流,其中包含多个作业和步骤,而复合操作则组合多个步骤,然后您可以在作业步骤中运行这些步骤,就像任何其他操作一样。有关更多信息,请参阅“避免重复”。

可重复使用的工作流和入门工作流

入门工作流允许组织中具有创建工作流权限的每个人更快速、更轻松地创建工作流。当人们创建新工作流时,他们可以选择入门工作流,并且编写工作流的部分或全部工作将由他们完成。在入门工作流中,您还可以引用可重复使用的工作流,以便人们可以轻松地从重复使用集中管理的工作流代码中受益。如果您在引用可重复使用的工作流时使用提交 SHA,则可以确保重复使用该工作流的每个人始终使用相同的 YAML 代码。但是,如果您通过标签或分支引用可重复使用的工作流,请确保您可以信任该版本的工作流。有关更多信息,请参阅“GitHub Actions 的安全强化”。

有关更多信息,请参阅“为您的组织创建入门工作流”。

访问可重复使用的工作流

如果满足以下任一条件,另一个工作流可以使用可重复使用的工作流

下表显示了可重复使用的工作流对调用者工作流的可访问性,具体取决于主机存储库的可见性。

调用者存储库可访问的工作流存储库
私有私有公共
公共公共

调用者存储库的 Actions 设置页面上的Actions 权限必须配置为允许使用操作和可重用工作流 - 请参阅“管理存储库的 GitHub Actions 设置”。

对于私有存储库,被调用工作流存储库的 Actions 设置页面上的访问策略必须明确配置为允许从包含调用者工作流的存储库进行访问 - 请参阅“管理存储库的 GitHub Actions 设置”。

注意:为了增强安全性,GitHub Actions 不支持对操作或可重用工作流进行重定向。这意味着当操作存储库的所有者、名称或操作名称发生更改时,使用该操作并带有前一个名称的任何工作流都将失败。

使用运行程序

使用 GitHub 托管的运行程序

GitHub 托管的运行程序的分配始终仅使用调用者的上下文进行评估。GitHub 托管的运行程序的计费始终与调用者相关联。调用者工作流无法使用来自被调用存储库的 GitHub 托管的运行程序。有关更多信息,请参阅“使用 GitHub 托管的运行程序”。

使用自托管运行程序

与调用者工作流属于同一位用户或组织拥有的被调用工作流可以从调用者的上下文中访问自托管运行程序。这意味着被调用工作流可以访问

  • 调用者存储库中的自托管运行程序
  • 调用者存储库的组织中的自托管运行程序,前提是该运行程序已向调用者存储库开放

限制

  • 你可以连接最多四级工作流。有关更多信息,请参阅“嵌套可重用工作流”。

  • 你可以从单个工作流文件中调用最多 20 个唯一可重用工作流。此限制包括从顶级调用者工作流文件开始可能被调用的任何嵌套可重用工作流树。

    例如,top-level-caller-workflow.ymlcalled-workflow-1.ymlcalled-workflow-2.yml 算作 2 个可重用工作流。

  • 在调用者工作流中工作流级别定义的 env 上下文中设置的任何环境变量不会传播到被调用工作流。有关更多信息,请参阅“变量”和“上下文”。

  • 类似地,在被调用工作流中定义的 env 上下文中设置的环境变量在调用者工作流的 env 上下文中不可访问。相反,你必须使用可重用工作流的输出。有关更多信息,请参阅“使用可重用工作流的输出”。

  • 要在多个工作流中重用变量,请在组织、存储库或环境级别设置它们,并使用 vars 上下文引用它们。有关更多信息,请参阅“变量”和“上下文”。

  • 可重用工作流直接在作业中调用,而不是在作业步骤中调用。因此,你不能使用 GITHUB_ENV 向调用工作流中的作业步骤传递值。

创建可重用工作流

可重用工作流是 YAML 格式的文件,与任何其他工作流文件非常相似。与其他工作流文件一样,可重用工作流位于存储库的 .github/workflows 目录中。不支持 workflows 目录的子目录。

对于可重用的工作流,on 的值必须包括 workflow_call

on:
  workflow_call:

在可重用工作流中使用输入和机密

你可以定义输入和机密,这些输入和机密可以从调用工作流传递,然后在被调用工作流中使用。在可重用工作流中使用输入或机密有三个阶段。

  1. 在可重用工作流中,使用 inputssecrets 关键字定义将从调用工作流传递的输入或机密。

    on:
      workflow_call:
        inputs:
          config-path:
            required: true
            type: string
        secrets:
          envPAT:
            required: true
    

    有关定义输入和机密的语法详细信息,请参阅 on.workflow_call.inputson.workflow_call.secrets

  2. 在可重用工作流中,引用你在前一步骤的 on 键中定义的输入或机密。

    注意:如果在调用工作流中使用 secrets: inherit 继承机密,则即使它们未在 on 键中明确定义,你也可以引用它们。有关更多信息,请参阅“GitHub Actions 的工作流语法”。

    jobs:
      reusable_workflow_job:
        runs-on: ubuntu-latest
        environment: production
        steps:
        - uses: actions/labeler@v4
          with:
            repo-token: ${{ secrets.envPAT }}
            configuration-path: ${{ inputs.config-path }}
    

    在上面的示例中,envPAT 是已添加到 production 环境的环境机密。因此,在作业中引用此环境。

    注意:环境机密是加密字符串,存储在你为存储库定义的环境中。环境机密仅对引用适当环境的工作流作业可用。有关更多信息,请参阅“使用环境进行部署”。

  3. 从调用工作流传递输入或机密。

    要将命名输入传递给被调用的工作流,请在作业中使用 with 关键字。使用 secrets 关键字来传递命名机密。对于输入,输入值的数据类型必须与被调用的工作流中指定的数据类型匹配(布尔值、数字或字符串)。

    jobs:
      call-workflow-passing-data:
        uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
        with:
          config-path: .github/labeler.yml
        secrets:
          envPAT: ${{ secrets.envPAT }}
    

    在同一组织或企业中调用可重用工作流的工作流可以使用 inherit 关键字来隐式传递机密。

    jobs:
      call-workflow-passing-data:
        uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
        with:
          config-path: .github/labeler.yml
        secrets: inherit
    

可重用工作流示例

此名为 workflow-B.yml 的可重用工作流文件(我们将在 示例调用方工作流 中稍后引用它)从调用方工作流中获取一个输入字符串和一个机密,并在操作中使用它们。

YAML
name: Reusable workflow example

on:
  workflow_call:
    inputs:
      config-path:
        required: true
        type: string
    secrets:
      token:
        required: true

jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/labeler@v4
      with:
        repo-token: ${{ secrets.token }}
        configuration-path: ${{ inputs.config-path }}

调用可重用工作流

通过使用 uses 关键字来调用可重用工作流。与在工作流中使用操作不同,您直接在作业中调用可重用工作流,而不是在作业步骤中调用。

jobs.<job_id>.uses

使用以下语法之一来引用可重用工作流文件

  • {owner}/{repo}/.github/workflows/{filename}@{ref} 适用于公共和私有存储库中的可重用工作流。
  • ./.github/workflows/{filename} 适用于同一存储库中的可重用工作流。

在第一个选项中,{ref} 可以是 SHA、发行版本标签或分支名称。如果发行版本标签和分支具有相同的名称,则发行版本标签优先于分支名称。使用提交 SHA 是稳定性和安全性方面的最安全选项。有关更多信息,请参阅“GitHub 操作的安全强化”。

如果您使用第二个语法选项(不带 {owner}/{repo}@{ref}),则被调用的工作流与调用方工作流来自同一提交。不允许使用前缀引用(例如 refs/headsrefs/tags)。

您可以调用多个工作流,在单独的作业中引用每个工作流。

jobs:
  call-workflow-1-in-local-repo:
    uses: octo-org/this-repo/.github/workflows/workflow-1.yml@172239021f7ba04fe7327647b213799853a9eb89
  call-workflow-2-in-local-repo:
    uses: ./.github/workflows/workflow-2.yml
  call-workflow-in-another-repo:
    uses: octo-org/another-repo/.github/workflows/workflow.yml@v1

将输入和机密传递给可重用工作流

要将命名输入传递给被调用的工作流,请在作业中使用 with 关键字。使用 secrets 关键字来传递命名机密。对于输入,输入值的数据类型必须与被调用的工作流中指定的数据类型匹配(布尔值、数字或字符串)。

jobs:
  call-workflow-passing-data:
    uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
    with:
      config-path: .github/labeler.yml
    secrets:
      envPAT: ${{ secrets.envPAT }}

在同一组织或企业中调用可重用工作流的工作流可以使用 inherit 关键字来隐式传递机密。

jobs:
  call-workflow-passing-data:
    uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main
    with:
      config-path: .github/labeler.yml
    secrets: inherit

将矩阵策略与可重用工作流结合使用

使用矩阵策略的作业可以调用可重用工作流。

矩阵策略允许您在单个作业定义中使用变量,以根据变量的组合自动创建多个基于作业运行。例如,您可以使用矩阵策略将不同的输入传递给可重用工作流。有关矩阵的更多信息,请参阅“为作业使用矩阵”。

下面的示例作业调用一个可重用工作流,并通过使用变量 target 定义值 [dev, stage, prod] 来引用矩阵上下文。它将运行三个作业,每个值一个作业。

YAML
jobs:
  ReuseableMatrixJobForDeployment:
    strategy:
      matrix:
        target: [dev, stage, prod]
    uses: octocat/octo-repo/.github/workflows/deployment.yml@main
    with:
      target: ${{ matrix.target }}

调用可重用工作流的作业支持的关键字

当你调用一个可重用工作流时,你只能在包含调用的作业中使用以下关键字

示例调用工作流

此工作流文件调用两个工作流文件。第二个文件 workflow-B.yml(在示例可重用工作流中显示)被传递一个输入(config-path)和一个密钥(token)。

YAML
name: Call a reusable workflow

on:
  pull_request:
    branches:
      - main

jobs:
  call-workflow:
    uses: octo-org/example-repo/.github/workflows/workflow-A.yml@v1

  call-workflow-passing-data:
    permissions:
      contents: read
      pull-requests: write
    uses: octo-org/example-repo/.github/workflows/workflow-B.yml@main
    with:
      config-path: .github/labeler.yml
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}

嵌套可重用工作流

最多可以连接四级工作流,即顶级调用方工作流和最多三级可重用工作流。例如:caller-workflow.ymlcalled-workflow-1.ymlcalled-workflow-2.ymlcalled-workflow-3.yml。工作流树中不允许出现循环。

在可重用工作流中,可以调用另一个可重用工作流。

YAML
name: Reusable workflow

on:
  workflow_call:

jobs:
  call-another-reusable:
    uses: octo-org/example-repo/.github/workflows/another-reusable.yml@v1

将密钥传递给嵌套工作流

可以在调用工作流中使用 jobs.<job_id>.secrets 将命名密钥传递给直接调用的工作流。或者,可以使用 jobs.<job_id>.secrets.inherit 将所有调用工作流的密钥传递给直接调用的工作流。有关更多信息,请参阅上面的“重用工作流”部分,以及参考文章“适用于 GitHub Actions 的工作流语法”。密钥仅传递给直接调用的工作流,因此在工作流链 A > B > C 中,工作流 C 仅在密钥从 A 传递到 B,然后从 B 传递到 C 的情况下才会从 A 接收密钥。

在以下示例中,工作流 A 使用 inherit 关键字将所有密钥传递给工作流 B,但工作流 B 仅将一个密钥传递给工作流 C。传递给工作流 B 的任何其他密钥对工作流 C 不可见。

jobs:
  workflowA-calls-workflowB:
    uses: octo-org/example-repo/.github/workflows/B.yml@main
    secrets: inherit # pass all secrets
jobs:
  workflowB-calls-workflowC:
    uses: different-org/example-repo/.github/workflows/C.yml@main
    secrets:
      envPAT: ${{ secrets.envPAT }} # pass just this secret

访问和权限

如果任何嵌套工作流对初始调用方工作流不可访问,则包含嵌套可重用工作流的工作流将失败。有关更多信息,请参阅“重用工作流”。

GITHUB_TOKEN 权限在嵌套工作流中只能相同或更严格。例如,在工作流链 A > B > C 中,如果工作流 A 具有 package: read 令牌权限,则 B 和 C 不能具有 package: write 权限。有关更多信息,请参阅“自动令牌验证”。

有关如何使用 API 确定特定工作流运行中涉及哪些工作流文件的信息,请参阅“监控正在使用的工作流”。

使用可重用工作流的输出

可重用工作流可能会生成您希望在调用方工作流中使用的数据。要使用这些输出,您必须将它们指定为可重用工作流的输出。

如果使用矩阵策略执行设置输出的可重用工作流,则输出将是实际上设置值的矩阵的最后一个成功完成的可重用工作流设置的输出。这意味着,如果最后一个成功完成的可重用工作流为其输出设置一个空字符串,而倒数第二个成功完成的可重用工作流为其输出设置一个实际值,则输出将包含倒数第二个完成的可重用工作流的值。

以下可重用工作流有一个包含两个步骤的单一作业。在这些步骤中的每一个步骤中,我们设置一个单词作为输出:“hello”和“world”。在作业的outputs部分,我们将这些步骤输出映射到称为output1output2的作业输出。然后,我们在on.workflow_call.outputs部分为工作流本身定义两个输出,一个称为firstword,我们将其映射到output1,另一个称为secondword,我们将其映射到output2

value必须设置为被调用工作流中作业级别输出的值。步骤级别输出必须首先映射到作业级别输出,如下所示。

有关更多信息,请参阅“为作业定义输出”和“GitHub Actions 的工作流语法”。

YAML
name: Reusable workflow

on:
  workflow_call:
    # Map the workflow outputs to job outputs
    outputs:
      firstword:
        description: "The first output string"
        value: ${{ jobs.example_job.outputs.output1 }}
      secondword:
        description: "The second output string"
        value: ${{ jobs.example_job.outputs.output2 }}

jobs:
  example_job:
    name: Generate output
    runs-on: ubuntu-latest
    # Map the job outputs to step outputs
    outputs:
      output1: ${{ steps.step1.outputs.firstword }}
      output2: ${{ steps.step2.outputs.secondword }}
    steps:
      - id: step1
        run: echo "firstword=hello" >> $GITHUB_OUTPUT
      - id: step2
        run: echo "secondword=world" >> $GITHUB_OUTPUT

我们现在可以在调用方工作流中使用输出,就像在同一工作流中使用作业的输出一样。我们使用可重用工作流中工作流级别定义的名称引用输出:firstwordsecondword。在此工作流中,job1调用可重用工作流,job2将可重用工作流的输出(“hello world”)打印到工作流日志中的标准输出。

YAML
name: Call a reusable workflow and use its outputs

on:
  workflow_dispatch:

jobs:
  job1:
    uses: octo-org/example-repo/.github/workflows/called-workflow.yml@v1

  job2:
    runs-on: ubuntu-latest
    needs: job1
    steps:
      - run: echo ${{ needs.job1.outputs.firstword }} ${{ needs.job1.outputs.secondword }}

有关使用作业输出的更多信息,请参阅“GitHub Actions 的工作流语法”。如果您希望在工作流之间共享变量以外的内容(例如构建工件),请参阅“将工作流数据存储为工件”。

监控正在使用的哪些工作流

你可以使用 GitHub REST API 监控可重复使用的工作流的使用情况。当工作流作业启动时,将触发 prepared_workflow_job 审计日志操作。记录的数据包括

  • repo - 工作流作业所在的组织/存储库。对于调用其他工作流的作业,这是调用工作流的组织/存储库。

  • @timestamp - 作业启动的日期和时间,采用 Unix 纪元格式。

  • job_name - 运行的作业的名称。

  • calling_workflow_refs - 参与此工作流作业的所有调用工作流的文件路径数组。数组中的项按调用顺序的逆序排列。例如,在工作流 A > B > C 的链中,当查看工作流 C 中作业的日志时,数组将为 ["octo-org/octo-repo/.github/workflows/B.yml", "octo-org/octo-repo/.github/workflows/A.yml"]

  • calling_workflow_shas - 参与此工作流作业的所有调用工作流的 SHA 数组。该数组包含与 calling_workflow_refs 数组相同数量的项,顺序也相同。

  • job_workflow_ref - 使用的工作流文件,格式为 {owner}/{repo}/{path}/{filename}@{ref}。对于调用其他工作流的作业,这标识了被调用的工作流。

有关使用 REST API 查询组织审计日志的信息,请参阅“组织的 REST API 端点”。

注意:只能使用 REST API 查看 prepared_workflow_job 的审计数据。在 GitHub Web 界面中不可见,也不包含在导出的 JSON/CSV 审计数据中。

使用可重复使用的工作流重新运行工作流和作业

可以使用 SHA、版本标签或分支名称引用来自公共存储库的可重复使用的工作流。有关更多信息,请参阅“重复使用工作流”。

当你重新运行使用可重复工作流的工作流并且引用不是 SHA 时,需要注意一些行为

  • 重新运行工作流中的所有作业将使用指定引用中的可重复工作流。有关重新运行工作流中的所有作业的更多信息,请参阅“重新运行工作流和作业”。
  • 重新运行工作流中失败的作业或特定作业将使用第一次尝试的相同提交 SHA 中的可重复使用的工作流。有关重新运行工作流中失败的作业的更多信息,请参阅“重新运行工作流和作业”。有关重新运行工作流中特定作业的更多信息,请参阅“重新运行工作流和作业”。

后续步骤

若要继续了解 GitHub Actions,请参阅“触发工作流的事件”。