近年、出版社でも原稿管理にGitの導入が進んでおり[要出典]、GitHubのようなWebサービスへの需要が高まっている[要出典]。 これに伴い、WebブラウザでGitHub上の原稿に対する特定のコミットを開き、そこに行コメントを残すといった利用も増えている[要出典]。 以下に例を挙げる。
この「特定のコミットに対して行コメントを残す」機能は、ワープロソフトの編集履歴ツールと同じ感覚で原稿に局所的なツッコミを入れられるという点で大変に使い勝手が良い。 しかし難点が一つあって、GitHubのWebページではこのコメントを一覧で表示できない。 そのため、コメントに気付かずスルーしてしまうという、文書の編集において最悪の事態を招くことがある。
ただ、一覧表示する術がまったくないかというとそういうわけでもなく、GitHubが公開しているREST API v3経由で取得できる。
- Comments | GitHub Developer Guide: List commit comments for a repository
https://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository
Go言語であれば、このREST APIを使って、以下の要領でコメントの本文をすべて取得できる。
package main import ( "encoding/json" "io/ioutil" "net/http" "fmt" ) type Comment struct { Body string `json:"body"` } func main () { req, err := http.NewRequest("GET", "https://api.github.com/repos/〈アカウント〉/〈リポジトリ〉/comments", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "token 〈好きなトークンを指定しよう〉") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var comments []Comment err = json.Unmarshal(body, &comments) if err != nil { fmt.Println(err.Error()) return } fmt.Println(comments) defer resp.Body.Close() }
おなじみ、http.NewRequest
でリクエストを作ればいいのだが、そのヘッダには"Authorization"
エントリでGitHubから取得したトークンを指定する必要がある。
"Content-Type"
で"application/json"
を指定しているのは、GitHub API v3のマニュアルに従ったものである。
- GitHub API v3 | GitHub Developer Guide
https://developer.github.com/v3/
そうやって作ったHTTPリクエストをhttp.DefaultClient.Do
で発行し、ioutil.ReadAll
でレスポンスを読み込んで、それをjson.Unmarshal
する。
ここでは事前に定義したComment
型の構造体に、コメントの各エントリを取り込むようにしている。
Comment
型の構造体としては、とりあえずコメントの本文を表す"body"
エントリだけを残すようにしてみた。
さっそく実行してみよう。〈アカウント〉に当社のGitHubアカウント、〈リポジトリ〉にとあるn月刊ラムダノートの記事のリポジトリを指定し、go build
して実行みると、現時点では2つのコメントが残されているっぽいことが判明した。
$ ./github-comments [{Common Lispと見出しレベルが揃ってなかったので揃えました。目次に影響ありそう} {ありがとうございます。これどうしようかちょっと迷ってたところでした。}]
もちろん、これだけだと誰のコメントなのかわからないので、もうちょっとComment
型を作りこむ必要があるだろう。
また、いつ書き込まれたコメントかわからないのは不便なので、日時くらいは取得するようにしたい。
さらに、せっかくならWebブラウザで関係者が閲覧できるようにして、該当のコメントが残されているコミットへのリンクを貼り、クリックすれば前後の本文の状況を確かめられるようにしたい。
そこで、JSONから取得したコメントを"html/template"
モジュールを使ってHTMLのテーブルに流し込むようにし、HerokuかどこかでWebサーバとして動かすようにしよう。
ようするにこういうことである。
package main import ( "os" "encoding/json" "html/template" "io/ioutil" "net/http" "fmt" ) type Comment struct { Body string `json:"body"` Date string `json:"created_at"` URL string `json:"html_url"` Author struct { Login string `json:"login"` } `json:"user"` } func getComments (w http.ResponseWriter, r *http.Request) { req, err := http.NewRequest("GET", "https://api.github.com/repos/〈アカウント〉/〈リポジトリ〉/comments", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "token 〈好きなトークンを指定しよう〉") req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var comments []Comment err = json.Unmarshal(body, &comments) if err != nil { fmt.Println(err.Error()) return } t := template.New("template.tpl") t, _ = t.ParseFiles("template.tpl") err = t.Execute(w, comments) if err != nil { panic(err) } defer resp.Body.Close() } func main () { port := os.Getenv("PORT") http.HandleFunc("/", getComments) http.ListenAndServe(":"+port, nil) }
template.tpl
は適当に用意しよう。
それらをHerokuに挙げてWebブラウザから閲覧するとこんな感じになる。
日時の欄をクリックすると、コメントがあるコミットのページに飛ぶようになっている。
net/http
にあるBasicAuth()
を使った簡単な認証をかけて、このページを関係者と共有してもいいだろう。