[GitHub/YAML]GitHubActionsで作業を自動化しよう[後半]

GitHubActions未分類

どうも。Kenny(https://twitter.com/tsujikenzo)です。GitHubを使いこなすと、生成AIで進化しながら、いつでも過去に戻れるという、ダーウィン(進化論)もびっくりのケニーです。

いよいよ最終回!シリーズ「GitHub Actionsで作業を自動化しよう」の第3回目をお届けします。

前回は、on:run: といったYAMLの各要素を深掘りし、schedule: を使った定期実行まで体験しました。

今回は、わたしの個人的な目標だった「プルリクエスト(PR)の自動作成」に挑戦します。

めんどうな定型作業をGitHubActionsに任せて、私たちはもっと創造的な仕事に集中しましょう!

今日のゴール:

developブランチで新しい変更をpushしたら、mainブランチへのプルリクエストが、設定したテンプレート(タイトル、本文など)通りに自動で作成される。

はじめに

Git/GitHubの肝は、「いつでもどこでも好きな場所に戻れる」だと個人的に思っています。その価値を最大限に高めるのは、「コミットやマージをこまめに行う」でしょう。

生成AIで、ソースコードやテキストを生成するスピードが恐ろしく早くなりました。なので、コミットやマージをこまめに行うことは、生産性が爆上がりだと信じています。

意外と手順の多いプルリク(PR)

しかし、プルリクエストを作成するときは、以下のように手作業が多く発生します。

  • マージ先のブランチを間違えないように選択
  • 分かりやすいタイトルを考える
  • 「概要」「変更点」など、決まったフォーマットで説明を書く
  • レビュー担当者を割り当てる

PR作成のためにスニペットを用意している方もいるかもしれませんが、意外と手間がかかりますよね。

ときには、PRを作るのがめんどうでひたすら更新作業に没頭します。これは、セーブポイントでセーブせずに、ラスボス戦に向かうようなものです。

このPR作成のような定型作業こそ、GitHub Actionsに任せるべきです。

新しい武器: uses と アクション (Actions)

この自動化を実現するために、第2回までは使わなかった新しいキーワード uses: が登場します。

uses: とは?一言でいうと、「自動化の部品(アクション)」を呼び出すためのキーワード です。

アクション (Actions) とは?、GitHub Actionsで使える、便利な「部品(アクション)」です。

世界中の開発者が「こういう自動化、よくやるよね」という処理を、スクリプトにまとめて公開してくれています。

ちなみに、アクションは、GitHubのMarketplaceで公開されています。YMLファイルを作成したときに自動で表示されるアレです。

 

もちろん、Marketplace専用のWEBサイトもあります。

GitHub Marketplace: tools to improve your workflow
Find the tools that help your team build better, together.

つまり、YAMLの中で、uses:というキーワードで呼び出すだけで、アクションを実行できるということです。

アクションは、アクション識別子と呼ばれる、重複のない任意の文字列です。

使い方は、YAMLファイルに、uses:とともに、アクション識別子を記述するだけです。 

公式のアクションactions/github-script

今回は、actions/github-scriptという、GitHub公式が提供しているアクションを使います。

github-script/README.md at main · actions/github-script
Write workflows scripting the GitHub API in JavaScript - actions/github-script

actions/github-script は、ワークフローファイルの中に複数行の本格的なJavaScriptコードを記述し、GitHubのさまざまな機能(リポジトリ情報の取得、プルリクエストの作成、イシューへのコメントなど)を直接操作できるようにしてくれます。

【ハンズオン】自動PR作成ワークフロー

それでは、アクションを使いながら、自動でPRを作成するワークフローを作成してみましょう。

事前準備: developブランチの作成 ※スクリーンショットは割愛します

  1. mainブランチとは別に、開発の中心となるdevelopブランチを作成します。
  2. 新しいワークフローファイル.github/workflows/auto-pr.ymlを作成します。
  3. GitHubActionsが自動でPRを作成するための、権限を与えます。(超重要)

3-1. Settingから、Actionsをクリックし、Generalをクリックします。 

3-2. Workflow permissionsの、「Read and write permissions」を選択し、「Allow GitHub Actions to create and approve pull requests」にもチェックを入れましょう。最後にSaveします。 

事前準備は、ここまでです。

ステップ1:auto-pr.ymlファイルに指示を書く

auto-pr.ymlファイルに、以下の内容を記述して、保存(Commit changes)します。

# ワークフローの名前
name: Auto Create Pull Request

# ワークフローが動き出す「きっかけ」
on:
  push:
    # developブランチへのpushがきっかけ
    branches:
      - 'develop'

# 実行される「作業」
jobs:
  # ジョブの名前
  create-pull-request-job:
    # 作業する仮想環境(ランナー)
    runs-on: ubuntu-latest

    # 具体的な「手順」
    steps:
      - name: Create Pull Request
        # actions/github-scriptのバージョンは@v7(最新)を使用する
        uses: actions/github-script@v7
        with:
          # リポジトリを操作するための許可証 (このまま書けばOK)
          github-token: ${{ secrets.GITHUB_TOKEN }}

          # 実行するスクリプト
          script: |
            // 1. 必要な情報を準備します
            const { repo, owner } = context.repo; // リポジトリ名とオーナー名
            const headBranch = '${{ github.ref_name }}'; // pushされたブランチ名 (develop)
            const baseBranch = 'main';                // マージ先のブランチ
            const prTitle = 'はじめての自動PR作成';   // PRのタイトル

            // 2. GitHub APIを呼び出してプルリクエストを作成します
            await github.rest.pulls.create({
              owner: owner,
              repo: repo,
              head: headBranch,
              base: baseBranch,
              title: prTitle,
              body: `Automated pull request to sync changes from \`${headBranch}\` to \`${baseBranch}\`.`
            });

保存するときに、「Commit directly to the developブランチ」に、チェックが入ってることを確認しましょう。 

ステップ2:ワークフローが正しく作成できたか確認する

前回の記事では省略しましたが、ワークフローが正しく作成できたか、ymlファイルを作成した直後に、Actionsタブで確認できます。 

ワークフローにエラーが発生しているばあいは、赤の×アイコンが表示されます。もちろんこの状態では、正しくワークフローが動きません。 

理由はさまざまです。

  • ワークフローを実行する権限が無い
  • 無料枠を使い切ってしまっている
  • 期限切れのクレジットカードを登録している
  • usesで無効なバージョンを呼び出そうとしている

エラーが発生しているjobを確認すると、エラーを確認できますので、解決できると思います。 

このような状態になれば、ワークフローの準備ができています。 

ステップ3: ワークフローを動かす

では、実際にワークフローを動かしてみます。「きっかけ」は、前回同様にファイルのPUSHです。

まずは、developブランチのREADME.mdファイルに、少し変更を加えます。 

保存(Commit changes)します。 

Actionsタブを確認すると、ワークフローが懸命に働いていることが確認できます。 

Pull requestを確認して、PRが作成されていれば成功です。 

Mergeするなり、レビューするなりしましょう。

応用編

応用編として、「既存のPRがあったら、PRを作成せずに、通常のコミットを更新する」というワークフローにしてみます。

なぜなら、このままのワークフローだと、既存PRがある状態でPUSHしたばあいは、エラーが発生してしまうからです。 

ワークフローに、事前にPRの重複チェックを行う処理を、追加してみましょう。

# ワークフローの名前
name: Auto Create Pull Request

# ワークフローが動き出す「きっかけ」
on:
  push:
    # developブランチへのpushがきっかけ
    branches:
      - 'develop'

# 実行される「作業」
jobs:
  # ジョブの名前
  create-pull-request-job:
    # 作業する場所
    runs-on: ubuntu-latest
    # 必要な権限
    permissions:
      pull-requests: write # PR作成権限
      contents: read     # ブランチ情報などを読む権限

    # 具体的な「手順」
    steps:
      - name: Create Pull Request if not exists
        # actions/github-scriptのバージョンは@v7(最新)を使用する
        uses: actions/github-script@v7
        with:
          # リポジトリを操作するための許可証
          github-token: ${{ secrets.GITHUB_TOKEN }}
          # 実行するスクリプト
          script: |
            // 1. 必要な情報を準備します
            const { repo, owner } = context.repo;
            const headBranch = '${{ github.ref_name }}'; // develop
            const baseBranch = 'main';
            const prTitle = 'はじめての自動PR作成';

            // 2. ★★★ ここからが追加部分 ★★★
            // 既存のオープンなPRがないか、APIに問い合わせてチェックします
            console.log(`既存のオープンなPRがないか、以下のブランチからチェックします ${headBranch} to ${baseBranch}...`);
            const { data: existingPulls } = await github.rest.pulls.list({
              owner,
              repo,
              head: `${owner}:${headBranch}`, // 「どのリポジトリのどのブランチ」かを明確に指定
              base: baseBranch,
              state: 'open' // オープンなPRのみを対象
            });
            
            // 3. もし既存のPRが見つかったら、メッセージを残して終了します
            if (existingPulls.length > 0) {
              console.log(`既存のオープンなPRがあります。: ${existingPulls[0].html_url}`);
              console.log('PR作成をスキップします。');
              return; // return; でスクリプトの実行をここで止めます
            }
            // ★★★ ここまでが追加部分 ★★★

            // 4. 既存のPRがなければ、新しいPRを作成します
            console.log('既存のPRはありませんでした。新規PRを作成します。');
            await github.rest.pulls.create({
              owner,
              repo,
              head: headBranch,
              base: baseBranch,
              title: prTitle,
              body: `自動PRが作成されました。\`${headBranch}\` to \`${baseBranch}\`.`
            });

修正ポイント

  1. github.rest.pulls.list: プルリクエストを作成する前に、GitHubのAPIに対して「develop から main への、まだオープンな状態のプルリクエストの一覧をください」と問い合わせています。
  2. if (existingPulls.length > 0): もし、問い合わせの結果、1つでも既存のプルリクエストが見つかったら (length > 0)、console.log で「もうPRがありますよ」というメッセージを実行ログに残し、return; でそれ以降の処理(PR作成)を行わずに終了します。
  3. await github.rest.pulls.create(…): もし、既存のプルリクエストが見つからなかった場合にのみ、このPR作成の処理が実行されます。

実行してみよう

上記のコードで auto-pr.yml を更新し、develop ブランチにコミット・プッシュします。(この時点ではまだPRは作成されません)

develop から main へのプルリクエストを手動で作成するか、あるいは develop に何か別の変更をプッシュして、ワークフローに最初のPRを自動作成させます。

プルリクエストが1つオープンな状態で、もう一度 develop ブランチの README.md などを編集して、プッシュしてみてください。 

Actionsタブの実行ログを見ると、今度はエラーにならず、ワークフローは成功で終わります。PRにはコミットが追加されます。 

Actionsを確認すると、たしかにログの中には「PR作成をスキップします。」というメッセージが表示されています。 

自動でPR作成ができるようになりましたね。

まとめ

以上で最終回でした。今回作成したワークフローは、ほんの一例です。

actions/github-script を使えば、イシューを自動で作成したり、ラベルを付けたり、コメントを返したりと、アイデア次第であらゆる定型作業を自動化できます。

このシリーズが、あなたの繰り返し手動作業を解決し、より創造的な仕事に時間を使うためのきっかけになれば幸いです。

さあ、あなたの身の回りにある「自動化できそうな作業」を探しに行きましょう!

このシリーズの目次

タイトルとURLをコピーしました