Check! GitHub GraphQL で紐づいた pull requests と一緒に issues を取得するサンプルコード
Prologue
こんにちは、@dz_ こと、岩永かづみです。
GitHub の何らかの情報を取得するときは、REST API でもできますが、GraphQL を使うと必要なフィールドのみを指定して最小限の通信量で取得できるので効率的です。また、GraphQL は最初とっつきにくかったのですが、慣れれば決まったパターンで利用できるので、今では GraphQL を選択するようになりました。
そんな GitHub GraphQL API を使って、関連するプルリクエストと一緒に issues 一覧を取得する方法をご紹介します。
GitHub の GraphQL API の使い方については、こちらの記事がとても分かりやすいのでお勧めです!
公式ドキュメントはこちらをご参照ください。
GitHub GraphQL で issues と関連する pull requests を取得する
ポイントをかいつまんでご紹介します。サンプルコードの全体像は後述をご参考ください。
GraphQL クエリ
まず GraphQL のクエリについて、ページネーションなし/ありで紹介します。
ページネーションなし、個数固定
ページネーションを考慮せず、個数固定で取得する場合はこのようなクエリになります。
query ($repoName:String!, $owner:String!) {
# 指定したリポジトリ
repository(owner: $owner, name: $repoName) {
# リポジトリの issues
issues(first: 10) {
nodes {
number
title
createdAt
closed
closedAt
# issue に関連づいたアイテム(イベント、コメントなど)のうち、
# メンションで関連付けられたアイテム
timelineItems(first: 10, itemTypes:CROSS_REFERENCED_EVENT) {
nodes {
... on CrossReferencedEvent {
source {
# そのうち、プルリクエストであるアイテム
... on PullRequest {
number
title
merged
}
}
}
}
}
}
}
}
}
issue に紐づくアイテムは timelineItems
というフィールドで取得します。さまざまな種類のアイテムが取得されるので、 itemTypes
で絞って取得します。 itemTypes
に CROSS_REFERENCED_EVENT
を指定すると、 CrossReferencedEvent
のアイテムが取得できます。CrossReferencedEvent
の source
に issue か pull request をもつので、 PullRequest
を指定してプルリクエストを取得します。ドキュメントは下記をご参考ください。
ページネーションあり
ページネーションを考慮する場合、2段階に分けないと取得できません。(むしろ、できる方法がもしあったら教えて下さい!)
まず、issues の一覧を取得します。
query (
$repoName: String!,
$owner: String!,
$issueCursor: String,
$issueNumberInPage: Int!,
) {
repository(owner: $owner, name: $repoName) {
issues(first: $issueNumberInPage, after: $issueCursor) {
nodes {
number
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
レスポンスの repository.issues.pageInfo.hasNextPage
には次にページがあるかどうかが返ってくるので、これを条件にループを回します。次のカーソルの位置は、レスポンスの repository.issues.pageInfo.endCursor
で取得できます。
そして、issue の number
ごとに timelineItems
を取得します。ページネーションの仕組みは前述と同様です。
query (
$repoName: String!,
$owner: String!,
$issueNumber: Int!,
$timelineItemsCursor: String,
$timelineItemsNumberInPage: Int!,
){
repository(owner: $owner, name: $repoName) {
issue(number: $issueNumber) {
number
title
createdAt
closed
closedAt
timelineItems(
first: $timelineItemsNumberInPage,
after: $timelineItemsCursor,
itemTypes:CROSS_REFERENCED_EVENT
) {
nodes {
... on CrossReferencedEvent {
source {
... on PullRequest {
number
title
merged
}
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}
}
octokit で認証と GraphQL 実行を手軽に
さて、GitHub の API を利用するときは、Personal Access Token や GitHub App などを用いて認証を行わないとなりません。いろいろと面倒なので、ライブラリ octokit
の利用をお勧めします。
- JavaScript:
octokit/octokit.js
- C#/.NET:
octokit/octokit.net
- Ruby:
octokit/octokit.rb
今回のサンプルコードでは、JavaScript版 octokit
を利用しています。
GraphQL のクエリを実行する場合は、下記のような形で、クエリと変数を渡す形で直感的に利用できます。
const issuesResponse = await octokit.graphql(issuesQuery, {
owner,
repoName,
issueCursor: issuesCursor,
issueNumberInPage: issuesNumberInPage,
})
サンプルコード
サンプルコード全体はこちらに置いておきます。JavaScript でべた書きしています。
Epilogue
このサンプルコードは業務で検証用に書いたものです。クエリを作るときにちょっとてこずったので、自分への備忘もかねて共有です。
GraphQL は何回か書いてるうちに苦手意識がなくなりました。便利なので、ぜひみなさんも触ってみてください💡
Discussion