GitHub で PR の CI を任意のタイミングでのみ手動実行させる方法

GitHub で PR の CI を任意のタイミングでのみ手動実行させる方法

GitHub Actions を動かすタイミングは PR が作成されたとき、コードが更新されたときなど細かく指定できます。

このとき、例えばコードを少し更新してコミット&プッシュを繰り返すような開発の進め方をした場合、その都度 CI が走ってしまうと無駄なリソースを消費してしまいます。こういったケースでは、自動で CI を走らせるのではなく、必要なタイミングでのみ手動実行させたいかもしれません。

これは、特定のラベルを PR に付与することで CI をトリガーするという運用をとることで実現可能です。

以下がその仕組みを取り入れた GitHub Actions のワークフロー定義です。

ワークフローは PR に ci ラベルが付与されたときにトリガーされます。linttest ジョブはそのラベルが存在する場合にのみ実行されます。CI が完了した後、remove_label ジョブが実行され、PR から ci ラベルを削除します。

on:
  pull_request:
    types: [labeled]

jobs:
  lint:
    if: contains(github.event.pull_request.labels.*.name, 'ci')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Linter
        # Your linter command here

  test:
    if: contains(github.event.pull_request.labels.*.name, 'ci')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Tests
        # Your test command here

  remove_label:
    needs: [lint, test]
    runs-on: ubuntu-latest
    steps:
      - name: Remove label from PR
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const label = 'ci';
            const workflowRun = context.payload.workflow_run;
            const prs = workflowRun.pull_requests || [];
            if (prs.length === 0) {
              core.info('No pull requests found for this workflow run.');
              return;
            }
            const pr = prs[0];
            core.info(`Removing label '${label}' from PR #${pr.number}.`);
            try {
              await github.issues.removeLabel({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: pr.number,
                name: label,
              });
              core.info(`Label '${label}' removed.`);
            } catch (error) {
              core.error(`Failed to remove label: ${error.message}`);
            }