Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11487] ファイルの概要

本コミットは、Go言語プロジェクトのダッシュボードにおけるサブモジュールのビルドステータス表示に関するUIレイアウトの改善を目的としています。具体的には、misc/dashboard/app/build/ui.gomisc/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を求めていました。

この背景から、本コミットでは、サブリポジトリのビルドステータス表示を改善し、より多くの情報(特に各ビルダーでの結果)を、より整理されたレイアウトで提供することを目指しました。

前提知識の解説

本コミットの理解には、以下の技術的知識が役立ちます。

  1. Go言語 (Golang):

    • Goの基本構文: 関数、構造体(struct)、インターフェース、エラーハンドリング(os.Errorは古いGoでのエラー型で、現在はerrorインターフェースが使われます)。
    • GoのWeb開発: net/httpパッケージを用いたHTTPハンドラの作成、テンプレートエンジン(html/template)の利用方法。
    • Goのサブリポジトリ: Goプロジェクトがどのように複数の独立したGitリポジトリ(サブリポジトリ)で構成されているか。これらはGoの標準ライブラリの一部として扱われることもありますが、独立した開発サイクルを持つことがあります。
  2. HTML/CSS:

    • HTMLのテーブル構造: <table>, <thead>, <tbody>, <tr>, <th>, <td>などの要素を用いた表の作成。特にcolgroupspan属性は、複雑なテーブルレイアウトを制御するために重要です。
    • CSSの基本: 要素のスタイリング(margin, padding, backgroundなど)とクラスセレクタの利用。
  3. Google App Engine (GAE):

    • 本ダッシュボードはGoogle App Engine上で動作していることがコードから示唆されます(appengine.Contextの利用)。GAEはGoogleが提供するPaaS(Platform as a Service)であり、Webアプリケーションのデプロイとスケーリングを容易にします。
    • GAEのデータストア(Datastore)は、アプリケーションのデータを永続化するために使用されます。コミットやビルド結果などの情報は、このデータストアに保存されていると考えられます。
  4. 継続的インテグレーション (CI):

    • ダッシュボードはCIシステムの一部として機能し、Goプロジェクトの各コミットやサブリポジトリのビルド結果を可視化します。CIは、コードの変更が自動的にビルド、テスト、デプロイされるプロセスを指します。
  5. Git:

    • コミット、ハッシュ、リポジトリといった基本的なGitの概念。

技術的詳細

本コミットの技術的な変更点は、主に以下の2つの側面から構成されます。

  1. バックエンドのデータ構造の再設計 (misc/dashboard/app/build/ui.go):

    • TagState構造体の導入: 以前はTagState関数が[]*PackageStateを直接返していましたが、新しいTagState構造体が導入されました。この構造体は、特定のタグ(例: "tip")におけるGoのコミット情報(Tag *Commit)と、そのタグ時点での各サブリポジトリの状態(Packages []*PackageState)をカプセル化します。これにより、テンプレートに渡されるデータがより意味的に整理され、扱いやすくなりました。
    • PackageState構造体の簡素化: 以前のPackageStateResultsOKといったビルド結果に関する情報も直接保持していましたが、新しいPackageStatePackage *PackageCommit *Commitのみを保持するようになりました。これは、ビルド結果の詳細は、CommitオブジェクトのResultsメソッドを呼び出す際に、Goのコミットハッシュ(goHash)を引数として渡すことで動的に取得されるように変更されたためです。この変更により、データモデルの責務が明確化され、PackageStateは純粋にパッケージとそのコミット情報を表すようになりました。
    • TagStateByName関数の導入と変更: 以前のTagState関数はTagStateByNameにリネームされ、そのシグネチャと内部ロジックが変更されました。この関数は、指定されたタグ名(例: "tip")に対応するTagStateオブジェクトを構築し、返します。また、サブリポジトリのステータス表示は、最初のページ(page == 0)でのみ行われるように条件が追加されました。これは、大量のデータを常に表示するのではなく、ユーザーが最も関心を持つ最新の情報を優先的に表示するためのパフォーマンス最適化またはUIの簡素化と考えられます。
    • commitBuilders関数の変更: この関数は、コミットに関連するビルダーの名前を返すものですが、Goのコミットハッシュ(goHash)を引数として受け取るようになりました。これにより、特定のGoのコミットに関連するビルド結果をフィルタリングしてビルダーを特定できるようになり、より柔軟なデータ取得が可能になりました。
  2. フロントエンドの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-top10pxから20pxに増加され、セクション間の視覚的な区切りがより明確になりました。
    • メインコミットテーブルのHTML構造の整理: 既存のコミット表示テーブルも、<td>要素のネストや{{with}}ブロックの利用方法が整理され、より読みやすく、保守しやすいHTML構造になっています。

これらの変更により、ユーザーは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}}
            &nbsp;
            {{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}}
                            &nbsp;
                        {{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のコミット情報とサブリポジトリのパッケージ情報をまとめて扱うことが可能になりました。
  • TagStatePackageStateの役割分担: 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プロジェクト全体の健全性をより効率的に監視できるようにすることを目的としています。

関連リンク

参考にした情報源リンク