[インデックス 11580] ファイルの概要
このコミットは、Go言語の継続的インテグレーション(CI)システムであるGo Dashboardの一部であるmisc/dashboard/app/build/handler.go
ファイルに対する変更です。このファイルは、Goプロジェクトのビルドタスク("todo")の生成ロジックを扱っています。具体的には、様々なビルドワーカー(builder)に対して、Go本体やサブリポジトリのビルドを指示する役割を担っています。
コミット
dashboard: don't send failing Go commits as todos for subrepos
R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/5608044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aa716e36a6c0656730eeab753eaba9d07aab72e0
元コミット内容
dashboard: don't send failing Go commits as todos for subrepos
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5608044
変更の背景
Go Dashboardは、Go言語本体だけでなく、それに依存する多数のサブリポジトリ(例: golang.org/x/
配下のライブラリ群)のビルドとテストも継続的に実行しています。これまでの挙動では、Go本体の特定のコミットがビルドに失敗した場合でも、その失敗したGoコミットをベースとしてサブリポジトリのビルドタスク("todo")が生成されてしまう問題がありました。
このような状況では、サブリポジトリのビルドはGo本体のビルド失敗に起因して必ず失敗するため、無駄なビルド処理が実行されることになります。これは、ビルドリソースの無駄遣いであるだけでなく、ダッシュボード上に多数の失敗したビルドタスクが表示され、本当に問題のあるサブリポジトリの変更による失敗と区別がつきにくくなるという問題を引き起こしていました。
このコミットは、このような非効率性と混乱を解消するために導入されました。Go本体のコミットが特定のビルドワーカーで既に失敗している場合、そのコミットを基にしたサブリポジトリのビルドタスクは生成しないようにすることで、リソースの節約とダッシュボードの情報の明確化を図っています。
前提知識の解説
この変更を理解するためには、以下の概念を把握しておく必要があります。
- Go Dashboard: Go言語プロジェクトの公式な継続的インテグレーション(CI)システムです。Go本体のコミットや、
golang.org/x/
配下にあるような関連するサブリポジトリのビルド、テスト、リリースプロセスを自動化し、その結果をウェブインターフェースで可視化します。これにより、Go言語の安定性と品質が維持されています。 - Subrepositories (Subrepos): Goエコシステムにおいて、Go本体とは別のリポジトリで管理されているが、Go本体に強く依存しているプロジェクトやライブラリ群を指します。例えば、Goの標準ライブラリには含まれないが、Goチームによって公式にメンテナンスされているツールやパッケージ(例:
go.tools
、net/context
など)がこれに該当します。これらのサブリポジトリは、Go本体の変更によって影響を受ける可能性があるため、Go本体のコミットと連携してビルド・テストされる必要があります。 - ビルドの「todo」: Go Dashboardの文脈における「todo」とは、特定のビルドワーカー(builder)に対して発行される、ビルドやテストの実行指示(タスク)を意味します。ダッシュボードは、新しいコミットがプッシュされた際や、特定の条件が満たされた際に、これらの「todo」を生成し、ビルドワーカーに割り当てます。
- Google App Engine:
misc/dashboard/app/
というパスからわかるように、Go DashboardのアプリケーションはGoogle App Engine上で動作しています。appengine.Context
はそのApp Engineアプリケーションのコンテキストを表すオブジェクトで、データストアへのアクセスやログ出力など、App Engineのサービスを利用する際に必要となります。
技術的詳細
この変更は、misc/dashboard/app/build/handler.go
ファイル内のbuildTodo
関数にロジックを追加することで実現されています。buildTodo
関数は、特定のビルドワーカー(builder
引数)とGoのコミットハッシュ(goHash
引数)に基づいて、サブリポジトリのビルドタスクを生成するかどうかを決定します。
変更前は、buildTodo
関数はGo本体のコミットが正常にビルドされたかどうかに関わらず、サブリポジトリのビルドタスクの生成を試みていました。
変更後のロジックでは、サブリポジトリのビルドタスクを生成する前に、以下のチェックが追加されました。
- 現在のGoコミットの取得:
tag.Commit(c)
を呼び出して、現在のGoコミット(goHash
に対応するコミット)の情報を取得します。ここで取得されるcom
オブジェクトは、そのコミットに関するメタデータやビルド結果を保持していると考えられます。 - Goコミットのビルド結果の確認: 取得した
com
オブジェクトに対してcom.Result(builder, "")
を呼び出します。Result
メソッドは、指定されたbuilder
(ビルドワーカー)とパッケージパス(ここではGo本体のビルド結果を見るため空文字列""
)に対するビルド結果を返します。- 返された結果オブジェクトが
nil
でない(つまり、ビルド結果が存在する)かつ、!r.OK
である(つまり、ビルドが成功していない、失敗している)場合に、Go本体のビルドが失敗していると判断します。
- タスク生成の抑制: もしGo本体のビルドが失敗していると判断された場合、
return nil, nil
を実行します。これにより、buildTodo
関数はビルドタスクを生成せずに終了し、無駄なサブリポジトリのビルドが回避されます。
この変更により、Go Dashboardはより効率的に動作し、ビルド結果の表示もより正確になります。
コアとなるコードの変更箇所
--- a/misc/dashboard/app/build/handler.go
+++ b/misc/dashboard/app/build/handler.go
@@ -215,10 +215,22 @@ func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interf
// see if there are any subrepo commits that need to be built at tip.
// If so, ask the builder to build a go tree at the tip commit.
// TODO(adg): do the same for "weekly" and "release" tags.
+\n
tag, err := GetTag(c, "tip")
if err != nil {
return nil, err
}
+\n
+\t// Check that this Go commit builds OK for this builder.
+\t// If not, don't re-build as the subrepos will never get built anyway.
+\tcom, err := tag.Commit(c)
+\tif err != nil {
+\t\treturn nil, err
+\t}\
+\tif r := com.Result(builder, ""); r != nil && !r.OK {
+\t\treturn nil, nil
+\t}\
+\n
pkgs, err := Packages(c, "subrepo")
if err != nil {
return nil, err
@@ -233,6 +245,7 @@ func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interf
return tag.Commit(c)
}
}\n+\n return nil, nil
}
コアとなるコードの解説
追加されたコードブロックは以下の部分です。
// Check that this Go commit builds OK for this builder.
// If not, don't re-build as the subrepos will never get built anyway.
com, err := tag.Commit(c)
if err != nil {
return nil, err
}
if r := com.Result(builder, ""); r != nil && !r.OK {
return nil, nil
}
-
// Check that this Go commit builds OK for this builder.
// If not, don't re-build as the subrepos will never get built anyway.
このコメントは、追加されるロジックの目的を明確に説明しています。Go本体のコミットがこのビルドワーカーで正常にビルドされるかを確認し、もし失敗している場合は、サブリポジトリのビルドを再試行しないという意図が示されています。これは、サブリポジトリのビルドがGo本体のビルドに依存しているため、Go本体が失敗していればサブリポジトリも成功する見込みがないという前提に基づいています。 -
com, err := tag.Commit(c)
tag
オブジェクト(おそらくGetTag(c, "tip")
で取得された、現在のGoのtip
、つまり最新のコミットに関する情報を持つオブジェクト)のCommit
メソッドを呼び出し、現在のappengine.Context
c
を渡して、Go本体のコミット情報を取得しています。このcom
変数は、取得したコミットの詳細(ハッシュ、作者、日付、そしてビルド結果など)を保持するオブジェクトであると推測されます。エラーが発生した場合は、即座にnil, err
を返して処理を中断します。 -
if r := com.Result(builder, ""); r != nil && !r.OK {
この行が変更の核心部分です。r := com.Result(builder, "")
:com
オブジェクトのResult
メソッドを呼び出しています。- 第一引数
builder
は、現在処理しているビルドワーカーの名前です。 - 第二引数
""
(空文字列)は、特定のパッケージパスを指定しないことを意味します。これは、Go本体全体のビルド結果を参照していることを示唆しています。 - この呼び出しは、指定された
builder
におけるGo本体のビルド結果を返します。その結果はr
という変数に代入されます。
- 第一引数
r != nil
:Result
メソッドがnil
以外の値を返した場合、それはそのbuilder
に対するビルド結果が存在することを示します。!r.OK
:r
オブジェクトのOK
フィールドがfalse
である場合、それはそのビルドが成功しなかった(つまり、失敗した)ことを意味します。- この
if
文全体は、「もし、このGoコミットがこのビルドワーカーでビルド結果を持っており、かつそのビルドが成功していなかった場合」という条件をチェックしています。
-
return nil, nil
上記のif
条件が真(Go本体のビルドが失敗している)の場合、この行が実行されます。buildTodo
関数はnil, nil
を返します。これは、新しいビルドタスク(todo)を生成しないことを意味します。これにより、Go本体のビルド失敗に起因する無駄なサブリポジトリのビルドタスクの生成が抑制されます。
関連リンク
- Go Dashboard: https://build.golang.org/ (Go Dashboardの実際のウェブサイト)
- Go Code Review (CL): https://golang.org/cl/5608044 (このコミットに対応するGoのコードレビューページ)
参考にした情報源リンク
- Go Dashboardのソースコード(
misc/dashboard
ディレクトリ): Goリポジトリ内のこのディレクトリは、Go Dashboardのアプリケーションコードを含んでいます。 - Go言語の公式ドキュメント: Go言語のビルドシステムやパッケージ管理に関する一般的な情報。
- Google App Engineのドキュメント: Go DashboardがApp Engine上で動作しているため、
appengine.Context
などの理解に役立ちます。The user wants me to output the generated explanation to standard output. I have already constructed the entire Markdown content. I will now print it.# [インデックス 11580] ファイルの概要
このコミットは、Go言語の継続的インテグレーション(CI)システムであるGo Dashboardの一部であるmisc/dashboard/app/build/handler.go
ファイルに対する変更です。このファイルは、Goプロジェクトのビルドタスク("todo")の生成ロジックを扱っています。具体的には、様々なビルドワーカー(builder)に対して、Go本体やサブリポジトリのビルドを指示する役割を担っています。
コミット
dashboard: don't send failing Go commits as todos for subrepos
R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/5608044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aa716e36a6c0656730eeab753eaba9d07aab72e0
元コミット内容
dashboard: don't send failing Go commits as todos for subrepos
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5608044
変更の背景
Go Dashboardは、Go言語本体だけでなく、それに依存する多数のサブリポジトリ(例: golang.org/x/
配下のライブラリ群)のビルドとテストも継続的に実行しています。これまでの挙動では、Go本体の特定のコミットがビルドに失敗した場合でも、その失敗したGoコミットをベースとしてサブリポジトリのビルドタスク("todo")が生成されてしまう問題がありました。
このような状況では、サブリポジリのビルドはGo本体のビルド失敗に起因して必ず失敗するため、無駄なビルド処理が実行されることになります。これは、ビルドリソースの無駄遣いであるだけでなく、ダッシュボード上に多数の失敗したビルドタスクが表示され、本当に問題のあるサブリポジトリの変更による失敗と区別がつきにくくなるという問題を引き起こしていました。
このコミットは、このような非効率性と混乱を解消するために導入されました。Go本体のコミットが特定のビルドワーカーで既に失敗している場合、そのコミットを基にしたサブリポジトリのビルドタスクは生成しないようにすることで、リソースの節約とダッシュボードの情報の明確化を図っています。
前提知識の解説
この変更を理解するためには、以下の概念を把握しておく必要があります。
- Go Dashboard: Go言語プロジェクトの公式な継続的インテグレーション(CI)システムです。Go本体のコミットや、
golang.org/x/
配下にあるような関連するサブリポジトリのビルド、テスト、リリースプロセスを自動化し、その結果をウェブインターフェースで可視化します。これにより、Go言語の安定性と品質が維持されています。 - Subrepositories (Subrepos): Goエコシステムにおいて、Go本体とは別のリポジトリで管理されているが、Go本体に強く依存しているプロジェクトやライブラリ群を指します。例えば、Goの標準ライブラリには含まれないが、Goチームによって公式にメンテナンスされているツールやパッケージ(例:
go.tools
、net/context
など)がこれに該当します。これらのサブリポジトリは、Go本体の変更によって影響を受ける可能性があるため、Go本体のコミットと連携してビルド・テストされる必要があります。 - ビルドの「todo」: Go Dashboardの文脈における「todo」とは、特定のビルドワーカー(builder)に対して発行される、ビルドやテストの実行指示(タスク)を意味します。ダッシュボードは、新しいコミットがプッシュされた際や、特定の条件が満たされた際に、これらの「todo」を生成し、ビルドワーカーに割り当てます。
- Google App Engine:
misc/dashboard/app/
というパスからわかるように、Go DashboardのアプリケーションはGoogle App Engine上で動作しています。appengine.Context
はそのApp Engineアプリケーションのコンテキストを表すオブジェクトで、データストアへのアクセスやログ出力など、App Engineのサービスを利用する際に必要となります。
技術的詳細
この変更は、misc/dashboard/app/build/handler.go
ファイル内のbuildTodo
関数にロジックを追加することで実現されています。buildTodo
関数は、特定のビルドワーカー(builder
引数)とGoのコミットハッシュ(goHash
引数)に基づいて、サブリポジトリのビルドタスクを生成するかどうかを決定します。
変更前は、buildTodo
関数はGo本体のコミットが正常にビルドされたかどうかに関わらず、サブリポジトリのビルドタスクの生成を試みていました。
変更後のロジックでは、サブリポジリのビルドタスクを生成する前に、以下のチェックが追加されました。
- 現在のGoコミットの取得:
tag.Commit(c)
を呼び出して、現在のGoコミット(goHash
に対応するコミット)の情報を取得します。ここで取得されるcom
オブジェクトは、そのコミットに関するメタデータやビルド結果を保持していると考えられます。 - Goコミットのビルド結果の確認: 取得した
com
オブジェクトに対してcom.Result(builder, "")
を呼び出します。Result
メソッドは、指定されたbuilder
(ビルドワーカー)とパッケージパス(ここではGo本体のビルド結果を見るため空文字列""
)に対するビルド結果を返します。- 返された結果オブジェクトが
nil
でない(つまり、ビルド結果が存在する)かつ、!r.OK
である(つまり、ビルドが成功していない、失敗している)場合に、Go本体のビルドが失敗していると判断します。
- タスク生成の抑制: もしGo本体のビルドが失敗していると判断された場合、
return nil, nil
を実行します。これにより、buildTodo
関数はビルドタスクを生成せずに終了し、無駄なサブリポジトリのビルドが回避されます。
この変更により、Go Dashboardはより効率的に動作し、ビルド結果の表示もより正確になります。
コアとなるコードの変更箇所
--- a/misc/dashboard/app/build/handler.go
+++ b/misc/dashboard/app/build/handler.go
@@ -215,10 +215,22 @@ func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interf
// see if there are any subrepo commits that need to be built at tip.
// If so, ask the builder to build a go tree at the tip commit.
// TODO(adg): do the same for "weekly" and "release" tags.
+\n
tag, err := GetTag(c, "tip")
if err != nil {
return nil, err
}
+\n
+\t// Check that this Go commit builds OK for this builder.
+\t// If not, don't re-build as the subrepos will never get built anyway.
+\tcom, err := tag.Commit(c)
+\tif err != nil {
+\t\treturn nil, err
+\t}\
+\tif r := com.Result(builder, ""); r != nil && !r.OK {
+\t\treturn nil, nil
+\t}\
+\n
pkgs, err := Packages(c, "subrepo")
if err != nil {
return nil, err
@@ -233,6 +245,7 @@ func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interf
return tag.Commit(c)
}
}\n+\n return nil, nil
}
コアとなるコードの解説
追加されたコードブロックは以下の部分です。
// Check that this Go commit builds OK for this builder.
// If not, don't re-build as the subrepos will never get built anyway.
com, err := tag.Commit(c)
if err != nil {
return nil, err
}
if r := com.Result(builder, ""); r != nil && !r.OK {
return nil, nil
}
-
// Check that this Go commit builds OK for this builder.
// If not, don't re-build as the subrepos will never get built anyway.
このコメントは、追加されるロジックの目的を明確に説明しています。Go本体のコミットがこのビルドワーカーで正常にビルドされるかを確認し、もし失敗している場合は、サブリポジトリのビルドを再試行しないという意図が示されています。これは、サブリポジリのビルドがGo本体のビルドに依存しているため、Go本体が失敗していればサブリポジリも成功する見込みがないという前提に基づいています。 -
com, err := tag.Commit(c)
tag
オブジェクト(おそらくGetTag(c, "tip")
で取得された、現在のGoのtip
、つまり最新のコミットに関する情報を持つオブジェクト)のCommit
メソッドを呼び出し、現在のappengine.Context
c
を渡して、Go本体のコミット情報を取得しています。このcom
変数は、取得したコミットの詳細(ハッシュ、作者、日付、そしてビルド結果など)を保持するオブジェクトであると推測されます。エラーが発生した場合は、即座にnil, err
を返して処理を中断します。 -
if r := com.Result(builder, ""); r != nil && !r.OK {
この行が変更の核心部分です。r := com.Result(builder, "")
:com
オブジェクトのResult
メソッドを呼び出しています。- 第一引数
builder
は、現在処理しているビルドワーカーの名前です。 - 第二引数
""
(空文字列)は、特定のパッケージパスを指定しないことを意味します。これは、Go本体全体のビルド結果を参照していることを示唆しています。 - この呼び出しは、指定された
builder
におけるGo本体のビルド結果を返します。その結果はr
という変数に代入されます。
- 第一引数
r != nil
:Result
メソッドがnil
以外の値を返した場合、それはそのbuilder
に対するビルド結果が存在することを示します。!r.OK
:r
オブジェクトのOK
フィールドがfalse
である場合、それはそのビルドが成功しなかった(つまり、失敗した)ことを意味します。- この
if
文全体は、「もし、このGoコミットがこのビルドワーカーでビルド結果を持っており、かつそのビルドが成功していなかった場合」という条件をチェックしています。
-
return nil, nil
上記のif
条件が真(Go本体のビルドが失敗している)の場合、この行が実行されます。buildTodo
関数はnil, nil
を返します。これは、新しいビルドタスク(todo)を生成しないことを意味します。これにより、Go本体のビルド失敗に起因する無駄なサブリポジトリのビルドタスクの生成が抑制されます。
関連リンク
- Go Dashboard: https://build.golang.org/ (Go Dashboardの実際のウェブサイト)
- Go Code Review (CL): https://golang.org/cl/5608044 (このコミットに対応するGoのコードレビューページ)
参考にした情報源リンク
- Go Dashboardのソースコード(
misc/dashboard
ディレクトリ): Goリポジトリ内のこのディレクトリは、Go Dashboardのアプリケーションコードを含んでいます。 - Go言語の公式ドキュメント: Go言語のビルドシステムやパッケージ管理に関する一般的な情報。
- Google App Engineのドキュメント: Go DashboardがApp Engine上で動作しているため、
appengine.Context
などの理解に役立ちます。