概要
GitHub上の特定のmilestoneにひもづくPRとissueのタイトル、URL、作成日時をスプレットシートにシュッと貼りたいときに便利なクエリです。
結論
$ gh api graphql -F owner='toshi0607' -F name='jctl' -F number=2 -F first=10 -f query='
query($name: String!, $owner: String!, $number: Int!, $first: Int) {
repository(owner: $owner, name: $name) {
milestone(number: $number) {
issues(first: $first) {
nodes {
title
url
createdAt
}
}
pullRequests(first: $first) {
nodes {
title
url
createdAt
}
}
}
}
}
'| jq -r '.data.repository.milestone | .issues.nodes[], .pullRequests.nodes[] | [.url, .title, .createdAt] | @tsv'
https://github.com/toshi0607/jctl/issues/5 lint 2019-10-02T07:44:16Z
https://github.com/toshi0607/jctl/issues/6 unit test 2019-10-02T07:44:25Z
https://github.com/toshi0607/jctl/issues/7 CMD option 2019-10-02T07:44:51Z
https://github.com/toshi0607/jctl/pull/9 add readme 2019-10-04T02:01:35Z
https://github.com/toshi0607/jctl/pull/10 add sample .envrc 2019-10-04T15:35:29Z
https://github.com/toshi0607/jctl/pull/11 add test case 2019-10-06T14:39:32Z
https://github.com/toshi0607/jctl/pull/12 use os.UserHomeDir 2019-10-11T14:31:11Z
https://github.com/toshi0607/jctl/pull/13 set TTL 2019-10-11T15:12:06Z
GitHub CLI
GitHubにクエリするにあたりGitHub CLIを利用しました。2020年6月12日にリリースされたv0.10.0では、サブコマンドでGitHubのGraphQL APIとREST APIが叩けるようになったようです。
こんな構文です。
$ gh api graphql -F owner=':owner' -F name=':repo' -f query='
query($name: String!, $owner: String!) {
repository(owner: $owner, name: $name) {
releases(last: 3) {
nodes { tagName }
}
}
}
'
macOSの場合はHomebrew
でつぎのように気軽にインストールできます。
$ brew install github/gh/gh
# version出すときにリリースタグのURL出すのいいかも
$ gh --version
gh version 0.11.1 (2020-07-28)
https://github.com/cli/cli/releases/tag/v0.11.1
他のOSの場合はこの辺りを参照してインストールし、触ってみてください。
Repositoryの取得
このRepositoryを例に、結論のクエリを組み立てていきます。
実際のGraphQLのクエリは、オブジェクト毎にページが用意されています。引数、取得できるフィールド、関連づけて取得できるデータ(Connections)、関連して取得できるデータの引数が確認できます。
Repositoryのページはこれです。
特定のRepository自体の情報はつぎのように取得できます。引数にはownerフィールドとnameフィールドを指定しています。
$ gh api graphql -F owner='toshi0607' -F name='jctl' -f query='
query($name: String!, $owner: String!) {
repository(owner: $owner, name: $name) {
milestone(number: 2) {
url
createdAt
}
}
}
'
{
"data": {
"repository": {
"milestone": {
"url": "https://github.com/toshi0607/jctl/milestone/2",
"createdAt": "2020-08-19T12:21:27Z"
}
}
}
}
Milestoneの取得
Repositoryを起点に取得できるデータは、collaborators、forks、issues、pullRequests、milestonesなどです。今回取得したいのはmilestonesです。
関連情報を取得するときは、repositoryを取得するときに指定したような記法でrepositoryの一フィールドに指定します。
引数にはmilestoneのnumberフィールドを指定しています。実物はこのmilestoneです。
$ gh api graphql -F owner='toshi0607' -F name='jctl' -F number=2 -f query='
query($name: String!, $owner: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
milestone(number: $number) {
title
url
createdAt
}
}
}
'
{
"data": {
"repository": {
"milestone": {
"title": "test2",
"url": "https://github.com/toshi0607/jctl/milestone/2",
"createdAt": "2020-08-19T12:21:27Z"
}
}
}
}
Milestoneのページはこれです。
milestoneにひもづくデータの取得
milestoneにひもづくissueを取得してみましょう。先ほどと同様に、入れ子方式でissueを指定します。
ただし、今度はissueを複数取得するつもりなのでissues
を指定します。引数はissue自体のフィールドではなく、関連するissueをフィルタリングするもの(orderBy、statesなど)のひとつであるfirstを指定しています。このようにして取得できるissueの集まりは、issueオブジェクトではなくIssueConnectionです。issueオブジェクトはnodesの中に入っています。
$ gh api graphql -F owner='toshi0607' -F name='jctl' -F number=2 -F first=10 -f query='
query($name: String!, $owner: String!, $number: Int!, $first: Int) {
repository(owner: $owner, name: $name) {
milestone(number: $number) {
issues(first: $first) {
nodes {
title
url
createdAt
}
}
}
}
}
'
{
"data": {
"repository": {
"milestone": {
"issues": {
"nodes": [
{
"title": "lint",
"url": "https://github.com/toshi0607/jctl/issues/5",
"createdAt": "2019-10-02T07:44:16Z"
},
{
"title": "unit test",
"url": "https://github.com/toshi0607/jctl/issues/6",
"createdAt": "2019-10-02T07:44:25Z"
},
{
"title": "CMD option",
"url": "https://github.com/toshi0607/jctl/issues/7",
"createdAt": "2019-10-02T07:44:51Z"
}
]
}
}
}
}
}
PRも同じように取得できます。
$ gh api graphql -F owner='toshi0607' -F name='jctl' -F number=2 -F first=10 -f query='
query($name: String!, $owner: String!, $number: Int!, $first: Int) {
repository(owner: $owner, name: $name) {
milestone(number: $number) {
issues(first: $first) {
nodes {
title
url
createdAt
}
}
pullRequests(first: $first) {
nodes {
title
url
createdAt
}
}
}
}
}
'
{
"data": {
"repository": {
"milestone": {
"issues": {
"nodes": [
{
"title": "lint",
"url": "https://github.com/toshi0607/jctl/issues/5",
"createdAt": "2019-10-02T07:44:16Z"
},
{
"title": "unit test",
"url": "https://github.com/toshi0607/jctl/issues/6",
"createdAt": "2019-10-02T07:44:25Z"
},
{
"title": "CMD option",
"url": "https://github.com/toshi0607/jctl/issues/7",
"createdAt": "2019-10-02T07:44:51Z"
}
]
},
"pullRequests": {
"nodes": [
{
"title": "add readme",
"url": "https://github.com/toshi0607/jctl/pull/9",
"createdAt": "2019-10-04T02:01:35Z"
},
{
"title": "add sample .envrc",
"url": "https://github.com/toshi0607/jctl/pull/10",
"createdAt": "2019-10-04T15:35:29Z"
},
{
"title": "add test case",
"url": "https://github.com/toshi0607/jctl/pull/11",
"createdAt": "2019-10-06T14:39:32Z"
},
{
"title": "use os.UserHomeDir",
"url": "https://github.com/toshi0607/jctl/pull/12",
"createdAt": "2019-10-11T14:31:11Z"
},
{
"title": "set TTL",
"url": "https://github.com/toshi0607/jctl/pull/13",
"createdAt": "2019-10-11T15:12:06Z"
}
]
}
}
}
}
}
タブ区切りに変換する
タブ区切りにしておくと、スプレッドシートに貼りやすいです。graphqlから帰ってきたJSONをjqで加工します。
$ gh api graphql -F owner='toshi0607' -F name='jctl' -F number=2 -F first=10 -f query='
query($name: String!, $owner: String!, $number: Int!, $first: Int) {
repository(owner: $owner, name: $name) {
milestone(number: $number) {
issues(first: $first) {
nodes {
title
url
createdAt
}
}
pullRequests(first: $first) {
nodes {
title
url
createdAt
}
}
}
}
}
'| jq -r '.data.repository.milestone | .issues.nodes[], .pullRequests.nodes[] | [.url, .title, .createdAt] | @tsv'
https://github.com/toshi0607/jctl/issues/5 lint 2019-10-02T07:44:16Z
https://github.com/toshi0607/jctl/issues/6 unit test 2019-10-02T07:44:25Z
https://github.com/toshi0607/jctl/issues/7 CMD option 2019-10-02T07:44:51Z
https://github.com/toshi0607/jctl/pull/9 add readme 2019-10-04T02:01:35Z
https://github.com/toshi0607/jctl/pull/10 add sample .envrc 2019-10-04T15:35:29Z
https://github.com/toshi0607/jctl/pull/11 add test case 2019-10-06T14:39:32Z
https://github.com/toshi0607/jctl/pull/12 use os.UserHomeDir 2019-10-11T14:31:11Z
https://github.com/toshi0607/jctl/pull/13 set TTL 2019-10-11T15:12:06Z
スプレッドシートの1Aに貼り付けるとこんな感じです。
「特定のRepositoryのMilestoneにひもづくPRやissueを取得してスプレッドシートに貼りやすいように加工する」というユースケース自体は頻繁にないかもしれません。それでも、GitHub CLIでgraphqlを簡単に扱え、いろいろな使い道がありそうだったので具体的な例として残してみることにしました。
別の方法
GitHub CLIにはissueサブコマンドとprサブコマンドもあります。
prのlistコマンドではデフォルトでopenなPRが取得できます。Milestoneベースでフィルタリングする方法はなさそうでした。
$ gh pr list --help
List and filter pull requests in this repository
USAGE
gh pr list [flags]
FLAGS
-a, --assignee string Filter by assignee
-B, --base string Filter by base branch
-l, --label strings Filter by labels
-L, --limit int Maximum number of items to fetch (default 30)
-s, --state string Filter by state: {open|closed|merged|all} (default "open")
-w, --web Open the browser to list the pull request(s)
INHERITED FLAGS
--help Show help for command
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO format
EXAMPLES
$ gh pr list --limit 999
$ gh pr list --state closed
$ gh pr list --label "priority 1" --label "bug"
$ gh pr list --web
LEARN MORE
Use "gh <command> <subcommand> --help" for more information about a command.
Read the manual at https://cli.github.com/manual
$ gh pr list --state closed -R toshi0607/jctl
Showing 8 of 8 pull requests in toshi0607/jctl that match your search
# 13 set TTL feature/set-ttl
# 12 use os.UserHomeDir feature/use-UserHomeDir
# 11 add test case feature/add-test-case
# 10 add sample .envrc feature/add-sample.envrc
# 9 add readme feature/add-readme
# 3 fix CI feature/fix-CI
# 2 add logs feature/add-logs
# 1 add gha test feature/add-gha-test
issueのlistコマンドでは、milestone名でフィルタリングできそうです。
$ gh issue list --help
List and filter issues in this repository
USAGE
gh issue list [flags]
FLAGS
-a, --assignee string Filter by assignee
-A, --author string Filter by author
-l, --label strings Filter by labels
-L, --limit int Maximum number of issues to fetch (default 30)
--mention string Filter by mention
-m, --milestone name Filter by milestone name
-s, --state string Filter by state: {open|closed|all} (default "open")
-w, --web Open the browser to list the issue(s)
INHERITED FLAGS
--help Show help for command
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO format
EXAMPLES
$ gh issue list -l "help wanted"
$ gh issue list -A monalisa
$ gh issue list --web
LEARN MORE
Use "gh <command> <subcommand> --help" for more information about a command.
Read the manual at https://cli.github.com/manual
ただし、表示される時間は最新更新時間(今回はmilestoneを紐付け他時間)で、milestoneのフィルタリングはよくわかりませんでした。
$ gh issue list -R toshi0607/jctl
Showing 3 of 3 issues in toshi0607/jctl
# 7 CMD option about 1 hour ago
# 6 unit test about 1 hour ago
# 5 lint about 1 hour ago
$ gh issue list -R toshi0607/jctl -m test2
No issues match your search in toshi0607/jctl
$ gh issue list -R toshi0607/jctl --milestone test2
No issues match your search in toshi0607/jctl
それを差し置いても、他にも便利な使い方ができそうです。
$ gh issue
Work with GitHub issues
USAGE
gh issue <command> [flags]
CORE COMMANDS
close: Close issue
create: Create a new issue
list: List and filter issues in this repository
reopen: Reopen issue
status: Show status of relevant issues
view: View an issue
FLAGS
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO format
INHERITED FLAGS
--help Show help for command
ARGUMENTS
An issue can be supplied as argument in any of the following formats:
- by number, e.g. "123"; or
- by URL, e.g. "https://github.com/OWNER/REPO/issues/123".
EXAMPLES
$ gh issue list
$ gh issue create --label bug
$ gh issue view --web
LEARN MORE
Use "gh <command> <subcommand> --help" for more information about a command.
Read the manual at https://cli.github.com/manual
$ gh pr
Work with GitHub pull requests
USAGE
gh pr <command> [flags]
CORE COMMANDS
checkout: Check out a pull request in Git
close: Close a pull request
create: Create a pull request
diff: View a pull request's changes.
list: List and filter pull requests in this repository
merge: Merge a pull request
ready: Mark a pull request as ready for review
reopen: Reopen a pull request
review: Add a review to a pull request
status: Show status of relevant pull requests
view: View a pull request
FLAGS
-R, --repo OWNER/REPO Select another repository using the OWNER/REPO format
INHERITED FLAGS
--help Show help for command
ARGUMENTS
A pull request can be supplied as argument in any of the following formats:
- by number, e.g. "123";
- by URL, e.g. "https://github.com/OWNER/REPO/pull/123"; or
- by the name of its head branch, e.g. "patch-1" or "OWNER:patch-1".
EXAMPLES
$ gh pr checkout 353
$ gh pr create --fill
$ gh pr view --web
LEARN MORE
Use "gh <command> <subcommand> --help" for more information about a command.
Read the manual at https://cli.github.com/manual