概述
您可以使工作流可重用,而不是将工作流从一个复制粘贴到另一个。然后,您和任何有权访问可重用工作流的人都可以从另一个工作流中调用该可重用工作流。
重用工作流可以避免重复。这使工作流更易于维护,并允许您通过构建他人的工作来更快地创建新的工作流,就像您使用操作一样。工作流重用还通过帮助您使用设计良好、已过测试且已被证明有效的工作流来促进最佳实践。您的组织可以构建一个可重用工作流库,该库可以集中维护。
下图显示了一个正在进行的工作流运行,该运行使用了可重用的工作流。
- 在图左侧的三个构建作业成功完成后,会运行一个名为“部署”的依赖作业。
- “部署”作业调用一个包含三个作业的可重用工作流:“暂存”、“审查”和“生产”。
- 只有在“暂存”作业成功完成后,才会运行“生产”部署作业。
- 当作业针对某个环境时,工作流运行会显示一个进度条,显示作业中的步骤数。在下图中,“生产”作业包含 8 个步骤,当前正在处理第 6 步。
- 使用可重用工作流运行部署作业,可以避免在工作流中重复代码,从而为每个构建运行这些作业。
使用其他工作流的工作流称为“调用方”工作流。可重用工作流是“被调用”工作流。一个调用方工作流可以使用多个被调用工作流。每个被调用工作流都在一行中引用。结果是,调用方工作流文件可能只包含几行 YAML,但在运行时可能会执行大量任务。重用工作流时,会使用整个被调用工作流,就像它是调用方工作流的一部分一样。
如果重用来自不同存储库的工作流,则被调用工作流中的任何操作都将像它们是调用方工作流的一部分一样运行。例如,如果被调用工作流使用actions/checkout
,则该操作会检出托管调用方工作流的存储库的内容,而不是被调用工作流的内容。
当可重用工作流由调用方工作流触发时,github
上下文始终与调用方工作流关联。被调用工作流会自动授予对github.token
和secrets.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.yml → called-workflow-1.yml → called-workflow-2.yml 计为 2 个可重用工作流。
-
在调用方工作流中工作流级别定义的
env
上下文中设置的任何环境变量都不会传播到被调用工作流。有关更多信息,请参阅“在变量中存储信息”和“访问有关工作流运行的上下文信息”。 -
同样,在被调用工作流中定义的
env
上下文中设置的环境变量在调用方工作流的env
上下文中不可访问。相反,您必须使用可重用工作流的输出。有关更多信息,请参阅“使用可重用工作流的输出”。 -
要在多个工作流中重用变量,请在组织、存储库或环境级别设置它们,并使用
vars
上下文引用它们。有关更多信息,请参阅“在变量中存储信息”和“访问有关工作流运行的上下文信息”。 -
可重用工作流直接在作业中调用,而不是从作业步骤中调用。因此,您不能使用
GITHUB_ENV
将值传递给调用方工作流中的作业步骤。
创建可重用工作流
可重用工作流是 YAML 格式的文件,与任何其他工作流文件非常相似。与其他工作流文件一样,您可以在存储库的.github/workflows
目录中找到可重用工作流。不支持workflows
目录的子目录。
要使工作流可重用,on
的值必须包含workflow_call
on:
workflow_call:
在可重用工作流中使用输入和机密
您可以定义输入和机密,这些输入和机密可以从调用方工作流传递,然后在被调用工作流中使用。在可重用工作流中使用输入或机密有三个阶段。
-
在可重用工作流中,使用
inputs
和secrets
关键字定义将从调用方工作流传递的输入或机密。on: workflow_call: inputs: config-path: required: true type: string secrets: personal_access_token: required: true
有关定义输入和机密的语法的详细信息,请参阅
on.workflow_call.inputs
和on.workflow_call.secrets
。 -
在可重用工作流中,引用您在上一步的
on
键中定义的输入或密钥。注意
如果密钥通过在调用工作流中使用
secrets: inherit
继承,即使它们未在on
键中明确定义,您也可以引用它们。有关更多信息,请参阅“GitHub Actions 的工作流语法”。jobs: reusable_workflow_job: runs-on: ubuntu-latest steps: - uses: actions/labeler@v4 with: repo-token: ${{ secrets.personal_access_token }} configuration-path: ${{ inputs.config-path }}
在上面的示例中,
personal_access_token
是在存储库或组织级别定义的密钥。警告
环境密钥无法从调用工作流传递,因为
on.workflow_call
不支持environment
关键字。如果您在作业级别的可重用工作流中包含environment
,则将使用环境密钥,而不是从调用工作流传递的密钥。有关更多信息,请参阅“管理部署环境”和“GitHub Actions 的工作流语法”。 -
从调用工作流传递输入或密钥。
要将命名输入传递到调用的工作流,请在作业中使用
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: personal_access_token: ${{ secrets.token }}
在同一组织或企业中调用可重用工作流的工作流可以使用
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
的可重用工作流文件(我们将在后面的示例调用工作流中引用它)接收来自调用工作流的输入字符串和密钥,并在操作中使用它们。
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 }}
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
关键字调用可重用工作流。与在工作流中使用操作不同,您直接在作业中调用可重用工作流,而不是在作业步骤中调用。
您可以使用以下语法之一引用可重用工作流文件
{owner}/{repo}/.github/workflows/{filename}@{ref}
用于公共和私有存储库中的可重用工作流。./.github/workflows/{filename}
用于同一存储库中的可重用工作流。
在第一个选项中,{ref}
可以是 SHA、发布标签或分支名称。如果发布标签和分支具有相同的名称,则发布标签优先于分支名称。使用提交 SHA 是确保稳定性和安全性的最安全选项。有关更多信息,请参阅“GitHub Actions 的安全加固”。
如果您使用第二个语法选项(不带{owner}/{repo}
和@{ref}
),则被调用的工作流将来自与调用工作流相同的提交。不允许使用refs/heads
和refs/tags
等 Ref 前缀。您不能在此关键字中使用上下文或表达式。
您可以调用多个工作流,并在单独的作业中引用每个工作流。
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:
personal_access_token: ${{ secrets.token }}
在同一组织或企业中调用可重用工作流的工作流可以使用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]
来引用矩阵上下文。它将运行三个作业,每个变量值一个。
jobs: ReuseableMatrixJobForDeployment: strategy: matrix: target: [dev, stage, prod] uses: octocat/octo-repo/.github/workflows/deployment.yml@main with: target: ${{ matrix.target }}
jobs:
ReuseableMatrixJobForDeployment:
strategy:
matrix:
target: [dev, stage, prod]
uses: octocat/octo-repo/.github/workflows/deployment.yml@main
with:
target: ${{ matrix.target }}
调用可重用工作流的作业支持的关键字
调用可重用工作流时,您只能在包含调用的作业中使用以下关键字
-
注意
- 如果在调用作业中未指定
jobs.<job_id>.permissions
,则被调用工作流将具有GITHUB_TOKEN
的默认权限。有关更多信息,请参阅“自动令牌身份验证”。 - 从调用工作流传递的
GITHUB_TOKEN
权限只能被被调用工作流降级(不能提升)。 - 如果您使用
jobs.<job_id>.concurrency.cancel-in-progress: true
,请不要在被调用和调用工作流中为jobs.<job_id>.concurrency.group
使用相同的值,因为这会导致正在运行的工作流被取消。被调用工作流在${{ github.workflow }}中使用其调用工作流的名称,因此在调用和被调用工作流中都使用此上下文作为jobs.<job_id>.concurrency.group
的值会导致调用工作流在被调用工作流运行时被取消。
- 如果在调用作业中未指定
示例调用工作流
此工作流文件调用两个工作流文件。其中第二个文件workflow-B.yml
(在示例可重用工作流中显示)传递了一个输入(config-path
)和一个密钥(token
)。
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 }}
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.yml → called-workflow-1.yml → called-workflow-2.yml → called-workflow-3.yml。工作流树中不允许循环。
您可以在可重用工作流中调用另一个可重用工作流。
name: Reusable workflow on: workflow_call: jobs: call-another-reusable: uses: octo-org/example-repo/.github/workflows/another-reusable.yml@v1
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:
repo-token: ${{ secrets.personal_access_token }} # pass just this secret
访问和权限
如果任何嵌套工作流无法访问初始调用工作流,则包含嵌套可重用工作流的工作流将失败。有关更多信息,请参阅“重用工作流”。
GITHUB_TOKEN
权限在嵌套工作流中只能保持相同或更严格。例如,在工作流链 A > B > C 中,如果工作流 A 具有package: read
令牌权限,则 B 和 C 不能具有package: write
权限。有关更多信息,请参阅“自动令牌身份验证”。
有关如何使用 API 确定哪些工作流文件参与了特定工作流运行的信息,请参阅“监视正在使用的工作流”。
使用可重用工作流的输出
可重用工作流可能会生成您希望在调用工作流中使用的数据。要使用这些输出,您必须将它们指定为可重用工作流的输出。
如果使用矩阵策略执行设置输出的可重用工作流,则输出将是实际设置值的矩阵的最后一个成功完成的可重用工作流设置的输出。这意味着,如果最后一个成功完成的可重用工作流为其输出设置空字符串,而倒数第二个成功完成的可重用工作流为其输出设置了实际值,则输出将包含倒数第二个完成的可重用工作流的值。
以下可重用工作流具有一个包含两个步骤的作业。在每个步骤中,我们都将一个单词设置为输出:“hello”和“world”。在作业的outputs
部分,我们将这些步骤输出映射到名为output1
和output2
的作业输出。然后,在on.workflow_call.outputs
部分,我们为工作流本身定义两个输出,一个名为firstword
,我们将其映射到output1
,另一个名为secondword
,我们将其映射到output2
。
value
必须设置为被调用工作流中作业级输出的值。步骤级输出必须首先映射到作业级输出,如下所示。
有关更多信息,请参阅“在作业之间传递信息”和“GitHub Actions 的工作流语法”。
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
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
现在,我们可以像在同一个工作流中使用作业的输出一样,使用调用者工作流中的输出。我们使用在可重用工作流的工作流级别定义的名称来引用输出:firstword
和 secondword
。在此工作流中,job1
调用可重用工作流,job2
将可重用工作流的输出(“hello world”)打印到工作流日志的标准输出。
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 }}
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 端点”。
注意
prepared_workflow_job
的审计数据只能使用 REST API 查看。它在 GitHub 网页界面中不可见,也不包含在导出的 JSON/CSV 审计数据中。
使用可重用工作流重新运行工作流和作业
来自公共存储库的可重用工作流可以使用 SHA、发布标签或分支名称进行引用。有关更多信息,请参阅“重用工作流”。
当您重新运行使用可重用工作流的工作流并且引用不是 SHA 时,需要注意一些行为
- 重新运行工作流中的所有作业将使用指定引用中的可重用工作流。有关重新运行工作流中所有作业的更多信息,请参阅“重新运行工作流和作业”。
- 重新运行工作流中失败的作业或特定作业将使用第一次尝试的相同提交 SHA 中的可重用工作流。有关重新运行工作流中失败的作业的更多信息,请参阅“重新运行工作流和作业”。有关重新运行工作流中特定作业的更多信息,请参阅“重新运行工作流和作业”。
后续步骤
要继续学习有关 GitHub Actions 的信息,请参阅“触发工作流的事件”。