⌨️

GitHub Actions で GitHub CLI を使う

2021/06/13に公開

GitHub CLI とは

GitHub の操作を提供する公式 CLI コマンドです。
https://cli.github.com/

hub コマンドもありますが比較は gh vs hub を確認してみてください。

インストール

GitHub ホストランナーにはプリインストールされているので何もせずに使えます。
セルフホストランナーにインストールする場合は Installation を参照してください。

Amazon Linux 2 へインストールする例
sudo yum install -y https://github.com/cli/cli/releases/download/v1.11.0/gh_1.11.0_linux_386.rpm

認証

対話型では gh auth login でログインしますが非対話型では環境変数 GH_TOKEN または GITHUB_TOKEN が使用できます。
ジョブ単位またはステップ単位で指定します。

jobs:
  github:
    runs-on: ubuntu-20.04
    env:
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GitHub Enterprise

GitHub Enterprise の場合は GH_ENTERPRISE_TOKEN または GITHUB_ENTERPRISE_TOKEN です。
ホストの指定は GH_HOST で行います。

    env:
      GH_ENTERPRISE_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      GH_HOST: github.example.com

https://cli.github.com/manual/gh_help_environment

値には secrets.GITHUB_TOKEN を使用します。
Personal Access Token を発行して使用することもできます。

使用例

クローン

シャロークローン
      # uses: actions/checkout@v2 と同等の clone オプション
      - run: gh repo clone $GITHUB_REPOSITORY . -- --depth 1 --branch ${GITHUB_REF#refs/heads/}
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
パーシャルクローン
      - run: gh repo clone $GITHUB_REPOSITORY . -- --no-checkout --filter=tree:0 --branch ${GITHUB_REF#refs/heads/}
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - run: git sparse-checkout init --cone
      - run: git sparse-checkout set $PATTERNS
        env:
          PATTERNS: |
            subdir1
            subdir2
      - run: git switch ${GITHUB_REF#refs/heads/}

補足:デフォルトシェルbash では変数を展開する際に ${変数名#パターン} とすると先頭がパターンにマッチした場合に最短マッチ部分を削除してくれます。

情報の取得

リポジトリの特定が必要な場合は --repo オプションまたは GH_REPO 環境変数を使用します。
リポジトリをチェックアウト済みの場合は省略できます。
以下の例で PR 1〜3 は同じ結果を返します。

全般
      # バージョン、ヘルプ
      - run: gh --version
      - run: gh --help

      # リポジトリ
      - run: gh repo list
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # PR 1
      - run: gh pr list --repo $GITHUB_REPOSITORY
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # PR 2
      - run: gh pr list
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}

      # PR 3
      - uses: actions/checkout@v2
      - run: gh pr list
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GitHub Actions 関連
      # ヘルプ
      - run: gh actions --help
#         env:
#           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # なぜか認証が要る => v1.12.0 で修正されました

      # ワークフロー
      - run: gh workflow list
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}

      # ワークフロー実行ログ
      - run: gh run list --workflow 'GitHub CLI'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}
      - run: gh run list --workflow gh.yml
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}

      # 実行中のワークフロー
      - run: gh run view $(gh run list --workflow gh.yml --limit 1 | cut -f 7)
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_REPO: ${{ github.repository }}

#       # watch は無限ループするので注意(試す場合は要タイムアウト)
#       - run: gh run watch $(gh run list --workflow gh.yml --limit 1 | cut -f 7)
#         env:
#           GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
#           GH_REPO: ${{ github.repository }}
#         timeout-minutes: 1

Draft PR 作成

fix/ ブランチが push されたら PR 作成
name: GitHub CLI

on:
  push:
    branches:
      - fix/**/*

jobs:
  create-pr:
    runs-on: ubuntu-20.04

    steps:
      # リポジトリがないとなぜかエラーになる
      # fatal: not a git repository (or any of the parent directories): .git
      - uses: actions/checkout@v2
      # title は直近のコミットメッセージで body は空
      - run: gh pr create --draft --title "$(git log -1 --oneline --pretty=format:'%s')" --body "" --assignee $AUTHOR
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          AUTHOR: ${{ github.event.pusher.name }}

  create-pr-fill:
    runs-on: ubuntu-20.04

    steps:
      # 履歴だけ取得
      - run: gh repo clone $GITHUB_REPOSITORY . -- --no-checkout --filter=tree:0 --branch ${GITHUB_REF#refs/heads/}
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      # title と body を自動入力
      - run: gh pr create --draft --fill --assignee $AUTHOR
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          AUTHOR: ${{ github.event.pusher.name }}

どちらの場合も同じブランチで2回目の push が発生するとエラーになるので要制御。
↑の YAML はそのまま使うと後から実行されたジョブが失敗します。

API リクエスト

octokit/request-action を使用することが多いと思いますが gh コマンドでも API を叩くことができます。
https://cli.github.com/manual/gh_api

      # [REST API] Issue のタイトルリスト
      - run: gh api repos/${REPOSITORY}/issues --jq '.[].title'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          REPOSITORY: ${{ github.repository }}

      # [GraphQL] リポジトリのリスト
      - run: |
          gh api graphql --paginate -f query='
            query($endCursor: String) {
              viewer {
                repositories(first: 100, after: $endCursor) {
                  nodes { nameWithOwner }
                  pageInfo {
                    hasNextPage
                    endCursor
                  }
                }
              }
            }
          '
        env:
	  # GITHUB_TOKEN だと実行中のリポジトリ情報しか取れないので PAT 発行
          GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}

まとめ

他にも Gist やリリースを扱えたりと様々なコマンドが存在します。
詳しくはドキュメントを読んでみてください。

Discussion