[インデックス 13529] ファイルの概要
このコミットは、Go言語プロジェクトのダッシュボードシステムにおけるコードレビューア情報の更新方法を変更するものです。具体的には、これまでメール送信によって行われていたレビューア情報の更新を、gobot
と呼ばれるサービスを介したHTTPリクエストに切り替えることで、より自動化された堅牢なプロセスへと移行しています。
コミット
commit e53351013df40af9a56380dc979762ce13851fa0
Author: David Symonds <dsymonds@golang.org>
Date: Mon Jul 30 14:13:12 2012 +1000
misc/dashboard/codereview: switch to using gobot to update CL reviewer info.
R=rsc
CC=golang-dev
https://golang.org/cl/6453063
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e53351013df40af9a56380dc979762ce13851fa0
元コミット内容
misc/dashboard/codereview: switch to using gobot to update CL reviewer info.
R=rsc
CC=golang-dev
https://golang.org/cl/6453063
変更の背景
この変更の背景には、Goプロジェクトのコードレビュープロセスにおけるレビューア情報の更新の自動化と信頼性の向上が挙げられます。元の実装では、コードレビュー(CL: Change List)にレビューアを追加する際、Google App Engineのmail
サービスを使用してメールを送信していました。このメールには、Rietveld(Googleのコードレビューツール)が解釈できる形式でレビューア情報が含まれており、これによりRietveld上でレビューアが設定されるという、いわば「ソーシャルな慣習」に依存した仕組みでした。
しかし、コミットメッセージに「We can't do this easily, as we need authentication to edit an issue on behalf of a user, which is non-trivial. For now, just send a mail with the body "R=
そこで、gobot
という専用のサービスを導入し、このgobot
に対してHTTPリクエストを送信することで、より直接的かつプログラム的にレビューア情報を更新する仕組みへと移行しました。これにより、レビューア設定のプロセスが自動化され、手動でのメール送信やRietveldの課題編集といった手間が省かれ、よりスムーズな開発ワークフローが実現されます。
前提知識の解説
Rietveld (リエトフェルト)
Rietveldは、Googleが開発したWebベースのコードレビューツールです。PerforceのMondrianをベースにしており、主にSubversionやGitなどのバージョン管理システムと連携して使用されます。Goプロジェクトでは、初期のコードレビューにRietveldが広く利用されていました。開発者は変更を提案する際に「Change List (CL)」を作成し、Rietveld上でそのCLに対するレビューを依頼します。レビューアはCLの差分を確認し、コメントを付けたり、承認したりすることができます。
Change List (CL)
Change List (CL) は、コードレビューシステムにおける変更の単位です。Goプロジェクトでは、RietveldやGerritといったコードレビューツールにおいて、提案される一連のコード変更をCLとして扱います。開発者はCLを作成し、レビューアにレビューを依頼します。CLが承認されると、その変更はメインのコードベースにマージされます。
Google App Engine (GAE)
Google App Engineは、Googleが提供するPlatform as a Service (PaaS) です。開発者はインフラストラクチャの管理を気にすることなく、Webアプリケーションやモバイルバックエンドを構築・デプロイできます。Goプロジェクトのダッシュボードシステムは、このGoogle App Engine上で動作していました。App Engineは、スケーラビリティ、信頼性、セキュリティなどの面で多くのメリットを提供します。
gobot
gobot
は、このコミットで導入された新しいサービスです。コミットメッセージやコードの変更内容から判断すると、gobot
はRietveldのコードレビューシステムと連携し、CLのレビューア情報を更新する役割を担っています。具体的には、HTTPリクエストを受け取り、そのリクエストに含まれるCL番号とレビューア情報に基づいて、RietveldのAPIを呼び出すなどしてレビューアを自動的に設定する機能を提供していると考えられます。これにより、Goプロジェクトのダッシュボードから直接Rietveldのレビューア情報を操作できるようになります。
appengine/urlfetch
appengine/urlfetch
は、Google App Engineアプリケーションが外部のHTTP(S)リソースにアクセスするためのサービスです。このコミットでは、gobot
サービスにHTTPリクエストを送信するためにurlfetch.Client(c).Get(url)
が使用されています。これにより、App Engineアプリケーションが安全かつ効率的に外部サービスと通信できます。
技術的詳細
このコミットの主要な技術的変更点は、コードレビューア情報の更新メカニズムを、メール送信からgobot
へのHTTPリクエストに切り替えたことです。
変更前(メールによる更新)
変更前は、handleAssign
関数内で新しいレビューアが見つかった場合、appengine/mail
パッケージを使用してメールを送信していました。このメールは、Rietveldがコードレビューの課題を更新するために解釈する特定の形式(例: Subject: CL Subject (issue CL_NUMBER)
, Body: R=reviewer_email
)を持っていました。
netmail "net/mail"
とappengine/mail
の利用: メールアドレスの解析やメール送信のためにこれらのパッケージがインポートされ、使用されていました。- 認証の課題: コミットメッセージにあるように、ユーザーに代わってRietveldの課題を直接編集するには認証が複雑であったため、メールという間接的な方法が取られていました。
mail.Send(c, msg)
: この関数呼び出しによって、レビューア情報を含むメールが送信されていました。
変更後(gobotによる更新)
変更後は、gobot
という新しいサービスに対してHTTP GETリクエストを送信することで、レビューア情報を更新するようになりました。
netmail "net/mail"
とappengine/mail
の削除: メール送信が不要になったため、これらのパッケージのインポートと関連コードが削除されました。gobotBase
定数の追加:const gobotBase = "http://research.swtch.com/gobot_codereview"
という新しい定数が追加され、gobot
サービスのURLが定義されました。urlfetch.Client(c).Get(url)
の利用:appengine/urlfetch
パッケージを使用して、gobotBase
にCL番号とレビューア情報をクエリパラメータとして含むURLを構築し、HTTP GETリクエストを送信しています。url := fmt.Sprintf("%s?cl=%s&r=%s", gobotBase, n, rev)
: この行で、gobot
に送信するURLが生成されます。cl
パラメータにはCL番号、r
パラメータにはレビューアのメールアドレスが含まれます。resp, err := urlfetch.Client(c).Get(url)
: 実際にHTTP GETリクエストを送信し、レスポンスを受け取ります。
- エラーハンドリングの強化: HTTPリクエストの失敗(ネットワークエラー、HTTPステータスコードが200以外)に対するエラーハンドリングが追加されました。
c.Errorf("Gobot GET failed: %v", err)
: リクエスト送信自体のエラー。if resp.StatusCode != 200
:gobot
からのレスポンスが成功(HTTP 200 OK)でなかった場合のエラー。
- レスポンスの確認:
gobot
からのレスポンスステータスをログに出力しています (c.Infof("Gobot said %q", resp.Status)
)。
この変更により、レビューア情報の更新がより直接的かつプログラム的に行われるようになり、メール送信に依存する間接的な方法よりも信頼性と効率性が向上しました。
コアとなるコードの変更箇所
--- a/misc/dashboard/codereview/dashboard/cl.go
+++ b/misc/dashboard/codereview/dashboard/cl.go
@@ -14,7 +14,6 @@ import (
"io"
"io/ioutil"
"net/http"
- netmail "net/mail"
"net/url"
"regexp"
"sort"
@@ -23,7 +22,6 @@ import (
"appengine"
"appengine/datastore"
- "appengine/mail"
"appengine/taskqueue"
"appengine/urlfetch"
"appengine/user"
@@ -35,6 +33,7 @@ func init() {
}
const codereviewBase = "http://codereview.appspot.com"
+const gobotBase = "http://research.swtch.com/gobot_codereview"
var clRegexp = regexp.MustCompile(`\d+`)
@@ -184,34 +183,21 @@ func handleAssign(w http.ResponseWriter, r *http.Request) {
if !found {
c.Infof("Adding %v as a reviewer of CL %v", rev, n)
- // We can't do this easily, as we need authentication to edit
- // an issue on behalf of a user, which is non-trivial. For now,
- // just send a mail with the body "R=<reviewer>", Cc'ing that person,
- // and rely on social convention.
- cl := new(CL)
- err := datastore.Get(c, key, cl)
+ url := fmt.Sprintf("%s?cl=%s&r=%s", gobotBase, n, rev)
+ resp, err := urlfetch.Client(c).Get(url)
if err != nil {
- c.Errorf("%s", err)
+ c.Errorf("Gobot GET failed: %v", err)
http.Error(w, err.Error(), 500)
return
}
- msg := &mail.Message{
- Sender: u.Email,
- To: []string{preferredEmail[rev]},
- Cc: cl.Recipients,
- // Take care to match Rietveld's subject line
- // so that Gmail will correctly thread mail.
- Subject: cl.Subject + " (issue " + n + ")",
- Body: "R=" + rev + "\n\n(sent by gocodereview)",
- }
- if cl.LastMessageID != "" {
- msg.Headers = netmail.Header{
- "In-Reply-To": []string{cl.LastMessageID},
- }
- }
- if err := mail.Send(c, msg); err != nil {
- c.Errorf("mail.Send: %v", err)
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ c.Errorf("Gobot GET failed: got HTTP response %d", resp.StatusCode)
+ http.Error(w, "Failed contacting Gobot", 500)
+ return
}
+
+ c.Infof("Gobot said %q", resp.Status)
}
}
コアとなるコードの解説
削除されたインポート
- netmail "net/mail"
: メールアドレスの解析やメールヘッダーの操作に使用されていたパッケージです。メール送信機能が削除されたため、不要になりました。- "appengine/mail"
: Google App Engineのメール送信サービスを利用するためのパッケージです。gobot
へのHTTPリクエストに切り替わったため、不要になりました。
追加された定数
+ const gobotBase = "http://research.swtch.com/gobot_codereview"
:gobot
サービスのベースURLを定義する新しい定数です。このURLに対してHTTPリクエストが送信されます。
handleAssign
関数の変更
handleAssign
関数は、コードレビューにレビューアを割り当てる際のロジックを処理します。この関数内の変更がこのコミットの核心です。
-
メール送信ロジックの削除:
- 以前は、
mail.Message
構造体を構築し、mail.Send(c, msg)
を呼び出してレビューア情報をメールで送信していました。このコードブロック全体が削除されました。 - これに伴い、
cl := new(CL)
やdatastore.Get(c, key, cl)
といった、メール送信に必要なCL情報を取得する処理も削除されています。これは、gobot
へのリクエストにはCLオブジェクト全体ではなく、CL番号とレビューア情報のみが必要になったためです。
- 以前は、
-
gobot
へのHTTPリクエストロジックの追加:url := fmt.Sprintf("%s?cl=%s&r=%s", gobotBase, n, rev)
:fmt.Sprintf
を使用して、gobotBase
にCL番号 (n
) とレビューアのメールアドレス (rev
) をクエリパラメータとして追加した完全なURLを生成しています。cl
パラメータはCL番号を、r
パラメータはレビューアのメールアドレスをgobot
に渡すために使用されます。
resp, err := urlfetch.Client(c).Get(url)
:appengine/urlfetch
パッケージのClient(c)
メソッドでHTTPクライアントを取得し、そのGet
メソッドを使って生成したURLにHTTP GETリクエストを送信しています。c
はApp Engineのコンテキストを表し、リクエストの認証やロギングなどに利用されます。
if err != nil
:- HTTPリクエストの送信中にエラーが発生した場合(例: ネットワーク接続の問題)のハンドリングです。エラーメッセージをログに出力し、HTTP 500エラーをクライアントに返します。
defer resp.Body.Close()
:- HTTPレスポンスボディを読み終えた後、またはエラーが発生した場合でも、必ずレスポンスボディをクローズするように
defer
キーワードを使用しています。これにより、リソースリークを防ぎます。
- HTTPレスポンスボディを読み終えた後、またはエラーが発生した場合でも、必ずレスポンスボディをクローズするように
if resp.StatusCode != 200
:gobot
からのレスポンスのHTTPステータスコードが200 (OK) でなかった場合のエラーハンドリングです。これは、gobot
サービス側で何らかの問題が発生したことを示します。エラーメッセージをログに出力し、HTTP 500エラーをクライアントに返します。
c.Infof("Gobot said %q", resp.Status)
:gobot
からのレスポンスステータス(例: "200 OK")をログに出力しています。これはデバッグや監視に役立ちます。
この変更により、レビューアの割り当てが、メールという間接的な手段から、gobot
という専用サービスを介した直接的なAPI呼び出しへと進化しました。これにより、レビューア情報の更新がより信頼性が高く、自動化されたプロセスになりました。
関連リンク
参考にした情報源リンク
- GitHub: golang/go commit e53351013df40af9a56380dc979762ce13851fa0
- golang.org/cl/6453063 (Goのコードレビューシステムへのリンク、現在はGerritに移行しているため直接アクセスできない可能性がありますが、当時のCL番号です)
- Rietveld - Wikipedia
- Google App Engine - Wikipedia
- Go App Engine urlfetch package (当時のドキュメントとは異なる可能性がありますが、urlfetchの概念を理解するのに役立ちます)
- Go App Engine mail package (当時のドキュメントとは異なる可能性がありますが、mailパッケージの概念を理解するのに役立ちます)