[インデックス 11487] ファイルの概要
本コミットは、Go言語プロジェクトのダッシュボードにおけるサブモジュールのビルドステータス表示に関するUIレイアウトの改善を目的としています。具体的には、misc/dashboard/app/build/ui.go
とmisc/dashboard/app/build/ui.html
の2つのファイルが変更されており、バックエンドのデータ構造の調整と、それに対応するフロントエンドのHTMLテンプレートの全面的な改修が行われています。これにより、サブリポジトリのビルド結果がより詳細かつ視覚的に整理された形で表示されるようになります。
コミット
commit 1f5f457ba350dfa9d5b03fe4b707967b000e1990
Author: Andrew Gerrand <adg@golang.org>
Date: Tue Jan 31 12:09:56 2012 +1100
dashboard: better ui layout for subrepo status
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5595048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1f5f457ba350dfa9d5b03fe4b707967b000e1990
元コミット内容
dashboard: better ui layout for subrepo status
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5595048
変更の背景
Go言語プロジェクトは、複数のサブリポジトリ(例: go.tools
, go.net
など)で構成されており、それぞれのサブリポジトリのビルドステータスを継続的に監視するダッシュボードが存在します。このダッシュボードは、プロジェクトの健全性を一目で把握するために非常に重要です。
本コミット以前のダッシュボードでは、サブリポジトリのビルドステータス表示が簡素であり、特に複数のビルド環境(ビルダー)での結果を比較したり、詳細な情報を確認したりする際に、視認性や情報量が不足しているという課題がありました。開発者は、各サブリポジトリの最新のビルド状況をより効率的に把握し、問題が発生した場合に迅速に原因を特定できるようなUIを求めていました。
この背景から、本コミットでは、サブリポジトリのビルドステータス表示を改善し、より多くの情報(特に各ビルダーでの結果)を、より整理されたレイアウトで提供することを目指しました。
前提知識の解説
本コミットの理解には、以下の技術的知識が役立ちます。
-
Go言語 (Golang):
- Goの基本構文: 関数、構造体(struct)、インターフェース、エラーハンドリング(
os.Error
は古いGoでのエラー型で、現在はerror
インターフェースが使われます)。 - GoのWeb開発:
net/http
パッケージを用いたHTTPハンドラの作成、テンプレートエンジン(html/template
)の利用方法。 - Goのサブリポジトリ: Goプロジェクトがどのように複数の独立したGitリポジトリ(サブリポジトリ)で構成されているか。これらはGoの標準ライブラリの一部として扱われることもありますが、独立した開発サイクルを持つことがあります。
- Goの基本構文: 関数、構造体(struct)、インターフェース、エラーハンドリング(
-
HTML/CSS:
- HTMLのテーブル構造:
<table>
,<thead>
,<tbody>
,<tr>
,<th>
,<td>
などの要素を用いた表の作成。特にcolgroup
とspan
属性は、複雑なテーブルレイアウトを制御するために重要です。 - CSSの基本: 要素のスタイリング(
margin
,padding
,background
など)とクラスセレクタの利用。
- HTMLのテーブル構造:
-
Google App Engine (GAE):
- 本ダッシュボードはGoogle App Engine上で動作していることがコードから示唆されます(
appengine.Context
の利用)。GAEはGoogleが提供するPaaS(Platform as a Service)であり、Webアプリケーションのデプロイとスケーリングを容易にします。 - GAEのデータストア(Datastore)は、アプリケーションのデータを永続化するために使用されます。コミットやビルド結果などの情報は、このデータストアに保存されていると考えられます。
- 本ダッシュボードはGoogle App Engine上で動作していることがコードから示唆されます(
-
継続的インテグレーション (CI):
- ダッシュボードはCIシステムの一部として機能し、Goプロジェクトの各コミットやサブリポジトリのビルド結果を可視化します。CIは、コードの変更が自動的にビルド、テスト、デプロイされるプロセスを指します。
-
Git:
- コミット、ハッシュ、リポジトリといった基本的なGitの概念。
技術的詳細
本コミットの技術的な変更点は、主に以下の2つの側面から構成されます。
-
バックエンドのデータ構造の再設計 (
misc/dashboard/app/build/ui.go
):TagState
構造体の導入: 以前はTagState
関数が[]*PackageState
を直接返していましたが、新しいTagState
構造体が導入されました。この構造体は、特定のタグ(例: "tip")におけるGoのコミット情報(Tag *Commit
)と、そのタグ時点での各サブリポジトリの状態(Packages []*PackageState
)をカプセル化します。これにより、テンプレートに渡されるデータがより意味的に整理され、扱いやすくなりました。PackageState
構造体の簡素化: 以前のPackageState
はResults
やOK
といったビルド結果に関する情報も直接保持していましたが、新しいPackageState
はPackage *Package
とCommit *Commit
のみを保持するようになりました。これは、ビルド結果の詳細は、Commit
オブジェクトのResults
メソッドを呼び出す際に、Goのコミットハッシュ(goHash
)を引数として渡すことで動的に取得されるように変更されたためです。この変更により、データモデルの責務が明確化され、PackageState
は純粋にパッケージとそのコミット情報を表すようになりました。TagStateByName
関数の導入と変更: 以前のTagState
関数はTagStateByName
にリネームされ、そのシグネチャと内部ロジックが変更されました。この関数は、指定されたタグ名(例: "tip")に対応するTagState
オブジェクトを構築し、返します。また、サブリポジトリのステータス表示は、最初のページ(page == 0
)でのみ行われるように条件が追加されました。これは、大量のデータを常に表示するのではなく、ユーザーが最も関心を持つ最新の情報を優先的に表示するためのパフォーマンス最適化またはUIの簡素化と考えられます。commitBuilders
関数の変更: この関数は、コミットに関連するビルダーの名前を返すものですが、Goのコミットハッシュ(goHash
)を引数として受け取るようになりました。これにより、特定のGoのコミットに関連するビルド結果をフィルタリングしてビルダーを特定できるようになり、より柔軟なデータ取得が可能になりました。
-
フロントエンドのUIレイアウトの全面的な改修 (
misc/dashboard/app/build/ui.html
):- サブリポジトリステータス表示の強化: 最も大きな変更は、"Other packages"セクションが"Sub-repositories at tip"に変わり、その表示方法が大幅に改善された点です。
- 新しいテーブル構造では、
colgroup
要素が導入され、各列(パッケージ名、コミットハッシュ、各ビルダーの結果、ユーザー、時間、説明)の幅とスタイルをより細かく制御できるようになりました。 - 特に、ビルダーの結果表示には複数の
<th>
要素が使用され、ビルダーのOSやアーキテクチャごとに結果がマトリックス形式で表示されるようになりました。これは、$.Builders | builderSpans
というテンプレート関数(HTMLテンプレート内でのみ参照されており、Goコードのdiffには含まれていませんが、その存在が示唆されます)によって実現されていると考えられます。この関数は、ビルダーのリストをOSやアーキテクチャに基づいてグループ化し、colspan
属性を適切に設定することで、ヘッダー行を動的に生成します。 - 各サブリポジトリの行では、パッケージ名、そのサブリポジトリのコミットハッシュ、そして各ビルダーでのビルド結果(成功/失敗、ログへのリンク)が明確に表示されます。これにより、どのサブリポジトリが、どのビルダーで、どのような結果になったのかを一目で把握できるようになりました。
- 新しいテーブル構造では、
- CSSの微調整:
h2
要素のmargin-top
が10px
から20px
に増加され、セクション間の視覚的な区切りがより明確になりました。 - メインコミットテーブルのHTML構造の整理: 既存のコミット表示テーブルも、
<td>
要素のネストや{{with}}
ブロックの利用方法が整理され、より読みやすく、保守しやすいHTML構造になっています。
- サブリポジトリステータス表示の強化: 最も大きな変更は、"Other packages"セクションが"Sub-repositories at tip"に変わり、その表示方法が大幅に改善された点です。
これらの変更により、ユーザーはGoプロジェクトのサブリポジトリのビルドステータスを、より詳細かつ直感的に理解できるようになりました。
コアとなるコードの変更箇所
misc/dashboard/app/build/ui.go
// uiHandler関数内の変更
func uiHandler(w http.ResponseWriter, r *http.Request) {
// ...
builders := commitBuilders(commits, "") // goHash引数が追加
// ...
var tipState *TagState // TagStateの型が変更
if page == 0 { // 最初のページでのみサブリポジトリの状態を表示
tipState, err = TagStateByName(c, "tip") // TagStateByNameにリネーム
// ...
}
// ...
p := &uiTemplateData{
Commits: commits,
Builders: builders,
TipState: tipState, // 型が*TagStateに変更
Pagination: pag,
}
// ...
}
// commitBuilders関数のシグネチャ変更
func commitBuilders(commits []*Commit, goHash string) []string {
builders := make(map[string]bool)
for _, commit := range commits {
for _, r := range commit.Results(goHash) { // goHashを引数として渡す
builders[r.Builder] = true
}
}
// ...
}
// 新しいTagState構造体の定義
type TagState struct {
Tag *Commit
Packages []*PackageState
}
// PackageState構造体の変更
type PackageState struct {
Package *Package
Commit *Commit
}
// TagStateByName関数のシグネチャとロジックの変更
func TagStateByName(c appengine.Context, name string) (*TagState, os.Error) {
tag, err := GetTag(c, name)
// ...
pkgs, err := AllPackages(c)
// ...
var st TagState
for _, pkg := range pkgs {
com, err := pkg.LastCommit(c)
// ...
st.Packages = append(st.Packages, &PackageState{pkg, com})
}
st.Tag, err = tag.Commit(c)
// ...
return &st, nil
}
misc/dashboard/app/build/ui.html
<!-- CSSの変更 -->
<style>
h2 {
margin-top: 20px; /* 10pxから変更 */
}
</style>
<!-- メインコミットテーブルのHTML構造の整理 -->
<table class="build">
<!-- ... -->
{{range $c := $.Commits}}
<tr class="commit">
<td class="hash"><a href="{{repoURL .Hash ""}}">{{shortHash .Hash}}</a></td>
{{range $.Builders}}
<td class="result">
{{with $c.Result . ""}}
{{if .OK}}
<span class="ok">ok</span>
{{else}}
<a href="/log/{{.LogHash}}" class="fail">fail</a>
{{end}}
{{else}}
{{end}}
</td>
{{end}}
<td class="user" title="{{.User}}">{{shortUser .User}}</td>
<td class="time">{{.Time.Time.Format "Mon 02 Jan 15:04"}}</td>
<td class="desc" title="{{.Desc}}">{{shortDesc .Desc}}</td>
</tr>
{{end}}
</table>
<!-- サブリポジトリステータス表示の全面的な改修 -->
{{with $.TipState}}
{{$goHash := .Tag.Hash}}
<h2>
Sub-repositories at tip
<small>(<a href="{{repoURL .Tag.Hash ""}}">{{shortHash .Tag.Hash}}</a>)</small>
</h2>
<table class="build">
<colgroup class="col-package"></colgroup>
<colgroup class="col-hash"></colgroup>
{{range $.Builders | builderSpans}}
<colgroup class="col-result" span="{{.N}}"></colgroup>
{{end}}
<colgroup class="col-user"></colgroup>
<colgroup class="col-time"></colgroup>
<colgroup class="col-desc"></colgroup>
<tr>
<!-- extra row to make alternating colors use dark for first result -->
</tr>
<tr>
<th></th>
<th></th>
{{range $.Builders | builderSpans}}
<th colspan="{{.N}}">{{.OS}}</th>
{{end}}
<th></th>
<th></th>
<th></th>
</tr>
<tr>
<th></th>
<th></th>
{{range $.Builders}}
<th class="result arch" title="{{.}}">{{builderArchShort .}}</th>
{{end}}
<th></th>
<th></th>
<th></th>
</tr>
{{range $pkg := .Packages}}
<tr class="commit">
<td><a title="{{.Package.Path}}">{{.Package.Name}}</a></td>
<td class="hash">
{{$h := $pkg.Commit.Hash}}
<a href="{{repoURL $h $pkg.Commit.PackagePath}}">{{shortHash $h}}</a>
</td>
{{range $.Builders}}
<td class="result">
{{with $pkg.Commit.Result . $goHash}}
{{if .OK}}
<span class="ok">ok</span>
{{else}}
<a href="/log/{{.LogHash}}" class="fail">fail</a>
{{end}}
{{else}}
{{end}}
</td>
{{end}}
{{with $pkg.Commit}}
<td class="user" title="{{.User}}">{{shortUser .User}}</td>
<td class="time">{{.Time.Time.Format "Mon 02 Jan 15:04"}}</td>
<td class="desc" title="{{.Desc}}">{{shortDesc .Desc}}</td>
{{end}}
</tr>
{{end}}
</table>
{{end}}
コアとなるコードの解説
misc/dashboard/app/build/ui.go
- データフローの変更:
uiHandler
関数は、以前はTagState
関数から直接[]*PackageState
を受け取っていましたが、変更後はTagStateByName
関数から新しい*TagState
型のオブジェクトを受け取るようになりました。これにより、テンプレートに渡されるデータ構造がより階層的になり、Goのコミット情報とサブリポジトリのパッケージ情報をまとめて扱うことが可能になりました。 TagState
とPackageState
の役割分担:TagState
は特定のタグ(例: "tip")におけるGo全体のコミットと、その時点での各サブリポジトリのパッケージリストを管理します。一方、PackageState
は個々のサブリポジトリのパッケージ情報とその最新コミット情報のみを保持するようになり、ビルド結果の詳細はCommit.Results
メソッドに委譲されました。この分離により、各構造体の責務が明確になり、コードの保守性が向上します。- 動的なビルド結果取得:
commitBuilders
関数やHTMLテンプレート内でcommit.Results(goHash)
が使用されるようになったことで、特定のGoのコミットハッシュに関連するビルド結果を動的にフィルタリングして取得できるようになりました。これは、ダッシュボードがGoのメインリポジトリとサブリポジトリのビルド結果を関連付けて表示するために重要です。
misc/dashboard/app/build/ui.html
- 新しいテーブルレイアウト: サブリポジトリのステータス表示は、以前のシンプルなリスト形式から、より複雑で情報量の多いテーブル形式へと進化しました。
colgroup
要素の導入は、テーブルの列のグループ化とスタイリングを容易にし、視覚的な整理に貢献しています。- ビルダーの結果をOSやアーキテクチャごとにグループ化して表示する
builderSpans
テンプレート関数の利用は、クロスプラットフォームでのビルド状況を一目で比較できるようにするための重要な改善です。これにより、どの環境で問題が発生しているのかを迅速に特定できます。 - 各サブリポジトリの行には、パッケージ名、そのサブリポジトリのコミットハッシュ、そして各ビルダーでのビルド結果が明確に表示されます。これにより、ユーザーは個々のサブリポジトリの健全性を詳細に把握できます。
- データバインディングの適応: バックエンドのデータ構造の変更に伴い、HTMLテンプレート内のデータバインディング(
{{range}}
,{{with}}
など)も新しいTagState
オブジェクトの構造に合わせて修正されています。特に、$.TipState.Packages
をイテレートし、その中で$.Builders
をイテレートして各ビルダーの結果を表示するロジックは、新しいデータモデルを効果的に活用しています。
これらの変更は、Goダッシュボードのユーザーエクスペリエンスを大幅に向上させ、開発者がGoプロジェクト全体の健全性をより効率的に監視できるようにすることを目的としています。
関連リンク
- Go言語公式ウェブサイト: https://go.dev/
- Google App Engine: https://cloud.google.com/appengine
- Goのサブリポジトリに関する情報 (GoのドキュメントやGitHubリポジトリを参照)
参考にした情報源リンク
- Go言語のドキュメント (特に
html/template
パッケージ): https://pkg.go.dev/html/template - Goのコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Google App Engineのドキュメント: https://cloud.google.com/appengine/docs
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージにある
https://golang.org/cl/5595048
はGerritの変更リストへのリンクです)