RでGitHubAPIを利用してリポジトリ情報などを取得する

タイトルのまんまです。いくつかハマるところがあったのと，数日後には忘れてしまうと思ったのでメモすることにしました。

## 経緯と目的

### 経緯
諸事情により自分のプライベートリポジトリ内のissueに挙がっているコメントを一覧にする必要が発生したのだけど，手作業とかしたくなかったので調べてやってみた。

### 目的
1. GitHubAPIをRから利用する
2. 自分のプライベートリポジトリにアクセス
3. 欲しかった情報を取得する

## 手順

### 全体の流れ
1. GitHubの**Personal access token**を取得
2. APIのためのurlを作成
3. 情報取得して内容を確認

### GitHubのPersonal access tokenを取得

GitHub APIにアクセスする際に使います。GitHubのAPIにアクセスしようとする際，プライベートリポジトリでは認証(アクセスできるものかどうか)をクリアしないといけません。BASIC認証などを利用する方法もあるのですが，さくっと使うというのであれば，このPersonal access tokenを利用するほうがいいでしょう[^1]。

[^1]: このトークンを利用すればアクセスに制限がかかる回数がぐっとゆるくなります。またBASIC認証だとフルコントールとなり何でも出来てしまう状態となるのですが，このトークンは発行する際にアクセスできる領域や権限を設定できます。またすぐに破棄することもできるので非常にお手軽です。なお，GitHub用アプリを開発するというような場合は，ちゃんとアプリ登録をしたほうがいいと思います。

このPersonal access tokenの説明についてはすでにWebに多くの解説が公開されていますので省略します。[github api token]で検索すればすぐにたくさんヒットするはずです。

取得したPersonal access tokenは，以下のような感じで`tkn`に格納したとします:

```r 
tkn <- "SHUUMATUNANISHITEMASUKAHIMADESUKASUKUTTE"
```

### APIのためのurlを作成

ここからがメインです。今回サンプルとして`kazutan/private_ripo_test`というプライベートリポジトリを作成してみましたので，これを例として使います。

なお，apiの詳しい仕様については，以下の公式のドキュメントにあたってください:

- https://developer.github.com/v3/

#### 基本的な部分の準備

けっこう長くなりますんで，ここでパラメータを準備しときます。

```r 
# 以降使うパッケージを宣言しとく
library(RCurl)
library(magrittr)
library(jsonlite)

# access token部分の準備
token <- paste("?access_token=", tkn, sep = "")
# apiのアドレス
base_url <- "https://api.github.com"
# scopeをセット
scope <- "repos"
# 組織・ユーザーの指定
orgs <- "kazutan"
# リポジトリ名
repo_name <- "private_ripo_test"
# イシューの番号
issues_no <- "2"
```

scopeというのは，apiで見に行く対象を指定する，みたいなものかと思います。今回はあくまでリポジトリが対象なので`"repo"`を指定しました。もしユーザー情報がメイン対象であれば`"users"`としてください。あとはコメントで付記したとおりです。

#### プライベートリポジトリの情報を取得

APIに投げるurlを整形します:

```r 
get_url_repo  <- paste(base_url, scope, orgs, repo_name, sep = "/") %>% 
  paste(token, sep = "")
```

整形されたurlは以下のような感じになります:

```
> get_url_repo
[1] "https://api.github.com/repos/kazutan/private_ripo_test?access_token=SHUUMATUNANISHITEMASUKAHIMADESUKASUKUTTE"
```

今回はaccess tokenを一番後ろに持ってきて，`?`でつないでいます。urlにこの`?`以降がひっついていれば，このトークンを利用します。ではこれを投げます:

```r 
res_repo <- getURI(url = get_url_repo,
                   httpheader = c('User-Agent'="kazutan",
                                  Accept="application/vnd.github.VERSION.full+json")) %>% 
  fromJSON()
```

`RCurl::rgetURL()`で取得し，それを`jsonlite::fromJSON()`にてリスト型に変換しています。

なお，引数`httpheader`で指定している要素には注意が必要です。まず，**GitHub APIではUser-Ajentの指定が必須**です。詳しくは[公式ドキュメントのここ](https://developer.github.com/v3/#user-agent-required)を確認してほしいのですが，ユーザーアカウント名でもOKです。なので今回は私のGitHubアカウント名を利用しています。**この引数を指定しないと全く相手にされません**ので気をつけてください。

また，引数`Accept`については，[公式ドキュメントのこちら](https://developer.github.com/v3/media/)を参照してください。受け取るメディアタイプ(データ形式など)を指定します。

取得したデータを`listviewer::jsonedit()`で一部表示てみた内容がこちらです:

![get_repo_info.png](https://qiita-image-store.s3.amazonaws.com/0/35118/c82424b9-7596-9f48-7bbd-e96aaee885b7.png)

`private: `にチェックが入っていることから，このリポジトリがプライベートだというのがわかります。また，色々なurlが情報として取得できています。これらのurlに必要な情報をひっつけていけば簡単にアクセスできます(後述)。

#### issues情報(全体)を取得

考え方はリポジトリ情報の時とほぼ同一で，もうひとつ階層を降りるイメージです。まずurlを整形して準備します:

```r 
get_url_repo_issues_all <- paste(base_url, scope, orgs, repo_name, "issues", sep = "/") %>% 
  paste(token, sep = "")
```

上述のリポ情報取得用urlと比較してもらえればすぐわかると思うので省略します。これをAPIに送ります:

```r 
res_repo_issues_all <- getURI(url = get_url_repo_issues_all,
                              httpheader = c('User-Agent'="kazutan",
                                             Accept="application/vnd.github.VERSION.full+json")) %>% 
  fromJSON()
```

取得した情報を`listviewer::jsonedit()`で一部表示してみた内容がこちらです:

![get_repo_issues_all.png](https://qiita-image-store.s3.amazonaws.com/0/35118/22c8a62c-0921-0a69-f44e-9efc66148e77.png)

今回はissuesが2つ存在し，1レコード(行)がissue1件となったdata.frameで取得できました。これでそれぞれのissueについての情報を取得できました。

#### 単一のissue情報を取得

issue番号を指定すれば，単一の情報を取得できます:

```r 
# イシュー#2の情報をゲットするためのurlを作成
get_url_repo_issues <- paste(base_url, scope, orgs, repo_name, "issues", issues_no, sep = "/") %>% 
  paste(token, sep = "")

# ゲットしにいく
res_repo_issues <- getURI(url = get_url_repo_issues,
                   httpheader = c('User-Agent'="kazutan",
                                  Accept="application/vnd.github.VERSION.full+json")) %>% 
  fromJSON()
```

これで取得した情報を`listviewer::jsonedit()`で一部表示してみた内容がこちら:

![get_repo_issue.png](https://qiita-image-store.s3.amazonaws.com/0/35118/55ecc98b-be9e-17f2-aab1-fbb31a2a8702.png)

なお，このissue情報(全体取得でも)は，コメントの内容までは持ってきてくれません。issueについたコメントを取得するには，もう一段階降りる必要があります。

#### issue内についたコメントを取得

今回は直上の単一のissue情報で取得した`res_repo_issues`内にある`comment_url`を利用して取得してみます:

```r 
# イシュー#2の全てのコメントをゲットするためのurlを作成
get_url_comme_all <- paste(res_repo_issues$comments_url, token, sep = "")

# ゲットしにいく
res_repo_issues_comme_all <- getURI(url = get_url_comme_all,
                          httpheader = c('User-Agent'="kazutan",
                                         Accept="application/vnd.github.VERSION.full+json")) %>% 
  fromJSON()
```

取得した内容の一部はこんな感じです:

![get_issues_comme.png](https://qiita-image-store.s3.amazonaws.com/0/35118/a8c40a6e-eb3d-7c93-ea46-f066762c102c.png)

今回の場合，#2のissueには2件コメントをつけていたので，それを取得しています。また，1レコード(行)がコメント1件となっているdata.frame型となって返ってきました。

## おわりに

手順とポイントさえ抑えておけば，あとはそれほど難しいものではないです。今回はissueとそのコメントの閲覧に絞りましたが，これをちょっと変更すればcommit情報なども取得できるようになるはずです。ただ詳しいところは[公式のドキュメント](https://developer.github.com/v3/)を参照してください。

また，私はエンジニアでもない素人なので，間違いがありましたらご指摘いただけると助かります。

**Enjoy!**

### 実際にやりたかったこと(蛇足)

実のところ，これらで取得したコメントデータを整形してレポートにしたかった。結局ゴリゴリと以下のようなコードで作ってしまった…[^2]

[^2]: 実際のコードとは若干違いますが，大体こんな感じでした。

```r 
library(lubridate)

# modify data
title <- res_repo_issues$title
body_html_all <- c(res_repo_issues$body_html, res_repo_issues_comme_all$body_html) %>%
  paste(paste("#### no.", 1:length(.)), ., sep = "\n\n") %>% 
  paste(collapse = "\n\n<hr>\n\n")
update_time <- paste("最終更新:", ymd_hms(res_repo_issues$updated_at, tz = "Asia/Tokyo")) %>% 
  paste("### ", ., "\n\n<hr>\n\n")

# make .md and render to html
doc_md <- paste("#", title, "\n\n")
doc_md <- c(doc_md, update_time)
doc_md <- c(doc_md, body_html_all)
cat(paste0(doc_md, collapse = ""), file = "issue.md")
rmarkdown::render("issue.md")
```

かっこわるいけど，後学のため晒しときます。