効率化

特定のブランチに入った対応の棚卸し、GitHubAPI使うとイイ感じ!

2024年8月24日

これは何?

こちらはGitHub Advent Calendar 2024 4日目の記事です!

運用保守の中で、プロダクトマネージャー側から

〇〇ブランチに入った対応って、今JIRAに上がってるので全部かな?もし漏れてるのあったらチケットに起こしといて欲しい

という、ちょっとめんどくさい依頼がありました。

その際、以下のことが必要そうでした。

  • 特定のブランチに入ったPull Requestたちを、タイトル/ID/マージ時刻/contributer含めてガバッと一覧化する
  • 一覧化した各PullRequestに対して、少し備忘的にメモを付け加える
  • その上で、スプレッドシート上にのせて保存、共有できる(GitHub分かんない人にも共有したい)

GitHubのWebサイト上でも検索とかソートはできるのですが、それをいちいちブラウザからコピペしてLocalのExcelに書き写して一覧化してメモかいて、ていうのがめんどくせ〜〜となったので、試しにGitHubAPIで一覧化してみました。その時の備忘録です。

作ったもの

import csv
import json
import codecs
import requests

# GitHubのPersonal Access Token
GITHUB_TOKEN = 'hoge' ##自分のやつを入れる

# リポジトリのオーナー名とリポジトリ名
OWNER = "hogeOwner"
REPO = "HogeRepo"

# ベースブランチ名
BASE_BRANCH = 'HogeBranch'

# APIリクエストURL
API_URL = f'https://api.github.com/repos/{OWNER}/{REPO}/pulls?base={BASE_BRANCH}&state=closed&sort=updated&direction=desc'#&since=2024-01-01T00:00:00Z'

# APIリクエスト
headers = {
    'Authorization': f'token {GITHUB_TOKEN}',
    'Accept': 'application/vnd.github+json'
}

params = {
    'base': BASE_BRANCH,
    'state': 'closed',
    'sort': 'updated',
    'direction': 'desc',
    'per_page': 100  # 最大100件まで取得可能
}

# 全てのページのデータを取得
all_pulls = []
page = 1

while True:
    params['page'] = page
    response = requests.get(API_URL, headers=headers, params=params)
    response.raise_for_status()
    pulls = response.json()

    if not pulls:
        break

    all_pulls.extend(pulls)
    page += 1
print(f'{len(all_pulls)}件のデータを取得しました。')

# マージ時刻がNULLでないPRのみを抽出
#️ 検索APIの仕様上、「マージ済み」か「クローズされただけ」かを絞り込みできなかったので、手元で絞り込んだ
filtered_pulls = [pr for pr in all_pulls if pr['merged_at'] is not None]
# マージ時刻でソートする
sorted_pulls = sorted(filtered_pulls, key=lambda pr: pr['merged_at'])

# Excelで見やすいようにshift_jisで出力するけど、文字化けが発生する場合は?hoge?に変換する
codecs.register_error('none', lambda e: ('?hoge?', e.end))

# CSVファイルに書き込む
count = 0
with open('prs_sjis_backend_11.csv', 'w', newline='', encoding='shift_jis', errors='none') as csvfile:
    fieldnames = ['id', 'title', 'user', 'created_at', 'merged_at', 'state', 'html_url']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    for pr in sorted_pulls:
        count += 1
        writer.writerow({
            'id': pr['id'],
            'title': pr['title'],
            'user': pr['user']['login'],
            'created_at': pr['created_at'],
            'merged_at': pr['merged_at'],
            'state': pr['state'],
            'html_url': pr['html_url']
        })
print(f'{count}件のデータをCSV出力しました。')

ポイント

  • 「マージされているかどうか」はgitHubAPIくんは直接教えてくれない。[merged_at]がNULLかどうかで判断するしかない。

備忘

GitHubのアクセス発行のやり方

https://sakublog.tech/tips/github-personal-access-tokens

使ったGitHubAPI ドキュメント

https://docs.github.com/ja/rest/pulls/pulls?apiVersion=2022-11-28#list-pull-requests

使ってみての所感

  • トークン発行したら2秒で動いてくれたので嬉しい。楽。あとはスプシなり何なりに貼り付けるだけでOK。
  • PythonScriptは ChatGPTくんに書かせたので楽だった(サボった)

追記

セマンティックバージョニング + GitHubのAutomatically generated release notes 使えば、似たようなことがタグの差分としてパッと出せることに気づいた。

-効率化