GitHub ActionsとGitHub APIでOrginizationのプライベートメンバーを取得する

概要

本記事はGitHub ActionsとGitHub APIを使って、一般から閲覧できない組織(Organization)のPrivateメンバーを動的に取得します。
認証はGitHub Appsを用いて設定します。
GitHub APIの取得制限を回避するためのループ処理でPythonを使用します。

やりたいこと

GitHub上のユーザーをプログラムで取得して処理を定義したい場合、専用のREST APIが用意されています。
PublicなメンバーであればAPIをそのまま叩くだけで取得できるのですが、Privateなメンバーは認証等を設定する必要があります。
本記事ではOrganizationに所属するユーザーを対象にして、Public+Privateなメンバーを取得する基盤を構築します。

全体像

GitHub REST APIのList organization membersを使用します。

Organizationメンバー - GitHub Enterprise Server 3.2 Docs

単にAPIを叩くだけでは以下のようにプライベート設定のメンバーを取得できません。

今回はGitHub Appsを設定して認証を行わせることで、Publicでないメンバー情報を取得する設定を行います。

手順

GitHub Appsの作成

Organizationのメンバーを取得するために認証が必要になります。
権限を持ったユーザーのPersonal Access tokenか、GitHub Appsが選択肢に入るかと思います。
いずれでも取得は可能ですが今回はOrgsが対象のため、組織共通の認証基盤として使用できるGitHub Appsを用います。

  1. 対象のOrganizationのSettingsを開きます

  2. 左のメニューからDevelopper settings -> GitHub Appsを開きます

  3. New GitHub Appを選択します

  4. 設定画面で次の項目を入力します

    • GitHub App Name
      • GitHubアプリの名称を決定
    • Webhook/Active
      • 不要のためチェックを外す
    • Permissions
      • 以下の3点のみ設定
        • Repository Permissions
          • Metadata
            • Read-Onlyに設定
          • Secrets
            • Read-Onlyに設定
        • Organization Permissions
          • Members
            • Read-Onlyに設定
  5. GitHub Apps設定画面のInstall Appを開いて、表示されているOrganizationにGitHub Appをインストールします(画像はインストール後のもの)

  6. GitHub Apps設定画面のGeneralを開いて、最上段の項目から「App Id」を控えておきます

  7. Private Keyの項目から「Generate a private key」を選択します Private Keyの.pemファイルがローカル環境にダウンロードされるため、中身を確認します

  8. GitHub Actionsのワークフローを実行するリポジトリのSettingsを開きます
    一覧からSecrets-Actionsを選択して、「New repository secret」から以下の2つを作成します

    • APP_ID
      • 手順6で控えたApp Id
    • PRIVATE_KEY
      • 手順7でローカル環境に落としたPrivateKeyの全文

GitHub Actionsの作成

基本のワークフロー

GitHub Actionsを設定するためのリポジトリに、以下のworkflowファイルを作成します。

.github/workflows/main.yaml

name: orgs prvate member list
on:
  workflow_dispatch:

jobs:
  terraform:
    name: test
    runs-on: ubuntu-latest
    defaults:
      run:
        shell: bash
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Generate github token
        id: generate_token
        uses: tibdex/github-app-token@v1
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.PRIVATE_KEY }}
      - name: org member list
        run: |
          gh api /orgs/[対象Organization名]/members?per_page=100
        env:
          GH_TOKEN: ${{ steps.generate_token.outputs.token }}

gh apiコマンドでGitHub REST APIを呼び出します。
?per_page=100とすることで、上限である100人までのメンバーを取得します。これを設定しない場合は30人までしか取得できないため注意してください。

101~200人目のメンバーはpage=2と指定することで取得できます。
この実装にはループ処理が必要であったため、筆者はActions以外にPythonスクリプトを書いて実装しました。

ループ処理の実装(Python)

101人目以降のメンバーを取得するために以下のように処理を定義します。

main.py

import requests
import json

args = sys.argv
GITHUB_TOKEN = args[1]
GITHUB_REPOSITORY = args[2]
ORG_NAME = GITHUB_REPOSITORY.split('/')[0]

# ヘッダー
header_github = {
    'Accept':'application/vnd.github+json',
    'Authorization': 'token '+GITHUB_TOKEN
}

def get_request_url(url,header):
    '''
    GETリクエストを送信してJSONを受け取るメソッド
    '''
    r = requests.get(url, headers=header)
    if r.status_code != 200:
        print('API call failed.', flush=True)
        print(r.text, flush=True)
    data = r.json()
    return data

# github userget
members_req_url = f'https://api.github.com/orgs/{ORG_NAME}/members?per_page=100'
data_users = []
for i in range(1,1000):
    data_users_temp = get_request_url(members_req_url+"&page="+str(i), header_github)
    if len(data_users_temp)==0:
        break
    data_users += data_users_temp
print("data_mamber_users:", len(data_users), flush=True)

data_usersリストに名前が格納されるので、これを使ってその他処理を定義していくことができます。

GitHub ActionsでPythonを実行する際、ログにprint文で記載した内容を表示させることができます。
重い処理をさせた際に実行順序が入れ替わったりすることがあるため、オプションでflush=Trueを挿入することを推奨します。

.github/workflows/main.yml (抜粋)

      - name: Setup Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.8'
          architecture: 'x64'
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Run Python
        run: python main.py ${{ steps.generate_token.outputs.token }} ${{ github.repository }}
      - name: Print End date
        run: |
          echo $(TZ=Asia/Tokyo date '+%Y-%m-%d %H:%M:%S(%z)')

基本ワークフローのorg member list項と上記を置き換えて定義します。
Privateメンバーを取得するためのトークンをGenerate github tokenから取得し、リポジトリ名(Organization名)はデフォルト定義の変数から取得して引数としてPythonに与えます。

requirements.txt

requests==2.24.0

一部pipインストールが必要なパッケージをrequirements.txtで定義して、仮想マシン環境にインストールします。

実行結果(基本のワークフロー)

Workflowの実行は手動で行います。

実行結果

Privateに設定した自身のユーザー情報が取得できました。
Publicなメンバーが在籍している場合についても、認証不要のため同様に取得されます。

その他

外部コラボレーターを取得したい場合は、以下のAPIを叩けば同様に取得できます。

List outside collaborators for an organization

その他Orginizationに関するPrivateな情報を取得するAPIを叩く場合も、同様の方法でリクエストを送ればよいので、色々試してみてください。

おわりに

今回はGitHub Appsを使って認証が必要なPrivateなOrganizationメンバーを取得しました。
同様の方法でトークンを発行してPrivate情報を取得することができるので、応用して色々なAPIを試してみてください。

執筆担当者プロフィール
西野 佑基

西野 佑基(日本ビジネスシステムズ株式会社)

機械学習系ソリューション開発、業務Webアプリ開発、開発環境自動化などを担当。

担当記事一覧