如何基于路径过滤限制GitHub Actions中由其他工作流触发的工作流执行
问题解答
首先得明确:你直接在workflow2的on字段里同时写paths和workflow_run是不行的,因为GitHub Actions中on下的多个事件是逻辑或的关系——这会导致workflow2在两种场景下都会触发:要么有提交修改了folder1(不管workflow1有没有运行),要么workflow1运行完成(不管提交有没有碰folder1),完全不符合你要的「workflow1完成且提交涉及folder1才触发」的需求。
下面给两种可行的实现方式,推荐第一种:
方案一:在workflow1中做路径判断,有条件触发workflow2
这种方式是从源头控制——只有当提交确实修改了folder1时,workflow1才主动调用workflow2,是最高效的方式。
修改workflow1的配置:
需要先检查提交的路径变化,再通过GitHub API触发workflow2:
name: workflow1 on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 2 # 必须拉取上一次提交,才能对比路径变化 # 检查提交是否修改了folder1目录 - name: Detect folder1 changes id: check_folder1 run: | # 对比当前提交和上一次提交的文件变化 if git diff --name-only HEAD~1 HEAD | grep -q "^folder1/"; then echo "changed=true" >> $GITHUB_OUTPUT else echo "changed=false" >> $GITHUB_OUTPUT fi # 只有当folder1有修改时,触发workflow2 - name: Trigger workflow2 (if needed) if: steps.check_folder1.outputs.changed == 'true' uses: actions/github-script@v7 with: script: | await github.rest.actions.createWorkflowDispatch({ owner: context.repo.owner, repo: context.repo.repo, workflow_id: 'workflow2.yml', # 注意这里是workflow2的文件名 ref: context.ref # 使用当前触发workflow1的分支/tag })
修改workflow2的配置:
把触发方式改成workflow_dispatch(允许被其他工作流主动调用):
name: workflow2 on: workflow_dispatch: # 由workflow1条件触发 jobs: build: # 注意你原来的配置这里漏了job名称,必须补上 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # 你的后续步骤...
方案二:在workflow2中触发后检查路径,不符合则终止
这种方式是workflow2会被workflow_run触发,但在执行步骤前先检查原提交的路径变化,如果没碰folder1就直接终止运行。缺点是会占用少量资源,且GitHub的Actions列表里会有触发记录,但好处是不需要修改workflow1。
修改后的workflow2配置:
name: workflow2 on: workflow_run: workflows: ["workflow1"] types: - completed jobs: build: runs-on: ubuntu-latest steps: # 通过GitHub API获取触发workflow1的原提交,并检查路径变化 - name: Check if original commit touched folder1 uses: actions/github-script@v7 id: path_check with: script: | # 获取workflow1的运行详情,拿到触发它的提交SHA const workflowRun = await github.rest.actions.getWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.payload.workflow_run.id }); const commitSha = workflowRun.data.head_sha; # 对比当前提交和上一次提交的文件变化 const commitCompare = await github.rest.repos.compareCommits({ owner: context.repo.owner, repo: context.repo.repo, base: `${commitSha}~1`, head: commitSha }); # 判断是否有folder1的文件修改 const hasFolder1Change = commitCompare.data.files?.some(file => file.filename.startsWith('folder1/') ) || false; return hasFolder1Change; # 如果没有修改folder1,直接终止job - name: Exit if no folder1 changes if: steps.path_check.outputs.result != 'true' run: | echo "No changes in folder1, exiting workflow2" exit 0 # 用exit 0标记为成功终止,也可以用exit 1标记失败,根据需求选 # 后续正常步骤 - uses: actions/checkout@v4 # 你的其他步骤...
注意事项
- 确保使用的Actions版本是最新的(比如
actions/checkout@v4、actions/github-script@v7),避免旧版本的兼容性问题。 - 方案一中,触发workflow2需要对应的权限:如果是GitHub托管的仓库,默认的
GITHUB_TOKEN已经有actions:write权限,可以直接使用;如果是自托管 runner,需要确认权限配置。
内容的提问来源于stack exchange,提问作者Michael W.
相关产品推荐
相关产品推荐

