GitHub Actions:结合schedule与pull_request实现PR每日限次触发工作流
实现方案
核心思路
通过两个工作流配合实现需求:
- 一个轻量工作流监听PR推送事件,标记需要处理的PR;
- 另一个工作流每日定时执行,扫描所有待处理的活跃PR,逐个执行高成本任务,完成后清除标记,确保每个PR每日仅运行一次。
具体实现
1. PR推送监听工作流(pr-push-tracker.yml)
这个工作流仅在PR有新推送时触发,负责给PR添加待处理标签,操作成本极低:
name: Track PR Pushes for Daily Run on: pull_request: types: [synchronize] jobs: mark-pending: runs-on: ubuntu-latest steps: - name: Add pending label to PR uses: actions/github-script@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: ['pending-daily-run'] });
2. 每日定时执行工作流(daily-pr-process.yml)
这个工作流每日定时触发,扫描所有带pending-daily-run标签的活跃PR,执行核心任务后移除标签,避免重复运行:
name: Daily PR Processing on: schedule: # 每日UTC 0点运行,可根据时区调整cron表达式 - cron: '0 0 * * *' workflow_dispatch: # 支持手动触发调试 jobs: process-pending-prs: runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - name: Fetch pending PRs id: get-prs uses: actions/github-script@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} result-encoding: json script: | const prs = await github.rest.pulls.list({ owner: context.repo.owner, repo: context.repo.repo, state: 'open', labels: 'pending-daily-run' }); return prs.data.map(pr => ({ number: pr.number, headSha: pr.head.sha, baseSha: pr.base.sha, title: pr.title })); - name: Process each pending PR if: ${{ steps.get-prs.outputs.result != '[]' }} uses: actions/github-script@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const pendingPRs = ${{ steps.get-prs.outputs.result }}; for (const pr of pendingPRs) { console.log(`Processing PR #${pr.number}: ${pr.title}`); // 1. 执行基础提交与最新提交的对比逻辑(替换为你的实际任务) await exec.exec('git clone', ['--depth=1', context.repo.html_url + '.git']); process.chdir(context.repo.repo); const diffResult = await exec.exec('git', ['diff', pr.baseSha, pr.headSha, '--name-only']); const changedFiles = diffResult.stdout.trim().split('\n').join('\n- '); // 2. 在PR线程发布评论 await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, body: `每日自动任务已完成: - 基础提交:\`${pr.baseSha.slice(0,7)}\` - 最新提交:\`${pr.headSha.slice(0,7)}\` - 修改文件: - ${changedFiles || '无文件变更'}` }); // 3. 移除待处理标签,防止重复执行 await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, name: 'pending-daily-run' }); }
关键细节说明
- 权限配置:需确保
GITHUB_TOKEN拥有pull-requests: write权限,可在仓库「Actions → 通用」设置中,将工作流权限设为「读取和写入权限」。 - 重复执行防护:通过
pending-daily-run标签的添加/移除,即使PR多次推送,也只会被标记一次,定时工作流处理后清除标签,确保每日仅运行一次。 - PR信息访问:定时工作流通过GitHub API直接获取PR的基础提交、最新提交等核心数据,完全支持对比、评论等后续操作。
- 灵活性:可修改
cron表达式调整每日运行时间,也可通过workflow_dispatch手动触发调试任务。
内容的提问来源于stack exchange,提问作者Ben H
相关产品推荐
相关产品推荐

