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

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

このコミットは、Goプロジェクトのダッシュボードシステムにおいて、サブリポジトリのビルド結果が常に最新のGo tip(開発ブランチの最新コミット)と同期されるようにするための改善を目的としています。具体的には、ビルドシステムがGoのメインリポジトリのコミットを処理し終えた後、サブリポジトリの最新コミットがGo tipでビルドされているかを確認し、もしビルドされていない場合は、ビルダーに対してGo tipの再ビルドを要求するロジックが追加されました。これにより、Goのメインリポジトリとサブリポジトリ間の依存関係が適切に管理され、テスト結果の鮮度が保たれるようになります。

コミット

commit faa1bf04fdea86d89583ea0063561c2cdc959b2d
Author: Andrew Gerrand <adg@golang.org>
Date:   Mon Jan 30 14:50:36 2012 +1100

    dashboard: ask builders to re-build Go tip to freshen subrepos
    
    This ensures we always have results for subrepo-tip at go-tip.
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/5569091

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/faa1bf04fdea86d89583ea0063561c2cdc959b2d

元コミット内容

dashboard: ask builders to re-build Go tip to freshen subrepos

This ensures we always have results for subrepo-tip at go-tip.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5569091

変更の背景

Goプロジェクトでは、メインのGoリポジトリとは別に、go.toolsgo.netといった「サブリポジトリ」が存在します。これらのサブリポジトリは、Goのメインリポジトリの特定のコミット(特にtip、つまり開発ブランチの最新版)と組み合わせてテスト・ビルドされる必要があります。

これまでのダッシュボードのビルドシステムでは、Goのメインリポジトリのコミットがビルドされた後、サブリポジトリの最新状態がそのGo tipでビルドされているかどうかの確認が不十分でした。その結果、Go tipが更新されても、サブリポジトリのビルド結果が古いGo tipに基づいている可能性があり、Go tipとサブリポジトリの最新状態の組み合わせに対するテストカバレッジが不足していました。

このコミットの目的は、この問題を解決し、Go tipが更新されるたびに、関連するサブリポジトリも最新のGo tipで再ビルドされるようにビルドプロセスを調整することです。これにより、Go tipとサブリポジトリの最新版の組み合わせにおける潜在的な回帰バグを早期に発見できるようになります。

前提知識の解説

  • Go ダッシュボード (Go Dashboard): Goプロジェクトの継続的インテグレーション (CI) システムの一部であり、様々なプラットフォームや構成でのGoのビルドとテストの結果を表示するウェブアプリケーションです。ビルドの状態、テストの合否、パフォーマンスの変化などを一元的に監視するために使用されます。
  • Go tip: Goのメイン開発ブランチ(通常はmasterまたはmain)の最新コミットを指します。Goの最新の機能やバグ修正が含まれていますが、まだ安定版としてリリースされていない状態です。
  • サブリポジトリ (Subrepos): Goプロジェクトでは、標準ライブラリの一部ではないが、Goエコシステムに密接に関連するコードベースが独立したGitリポジトリとして管理されています。これらは「サブリポジトリ」と呼ばれ、例えばgolang.org/x/toolsgolang.org/x/netなどが該当します。これらはGoのメインリポジトリとは独立してバージョン管理されますが、Goの特定のバージョン(特にtip)との互換性が重要です。
  • ビルダー (Builder): Goダッシュボードシステムにおいて、実際にGoのコードをビルドし、テストを実行するエージェントまたはマシンを指します。様々なOS、アーキテクチャ、コンパイラバージョンで動作し、結果をダッシュボードに報告します。
  • appengine.Context: Google App Engine (GAE) のGo SDKで使用されるコンテキストオブジェクトです。GAE環境でのデータストアアクセス、ロギング、URLフェッチなどのサービス呼び出しに必要となります。このコミットのコードがGAE上で動作するダッシュボードアプリケーションの一部であることを示唆しています。
  • datastore: Google App EngineのNoSQLデータストアサービスです。Goダッシュボードはビルド結果、コミット情報、パッケージ情報などをこのデータストアに保存しています。

技術的詳細

このコミットの主要な変更は、Goダッシュボードのビルドキューを管理するロジック、特にbuildTodo関数にあります。buildTodo関数は、ビルダーが次に何をビルドすべきかを決定する役割を担っています。

変更前は、buildTodo関数は主にGoのメインリポジトリのコミットや特定のパッケージのビルドタスクを優先的に処理していました。Goのコミットがすべて処理された後、関数はpanic("unreachable")で終了していました。

変更後は、Goのメインリポジトリのコミットがすべて処理され、かつ現在処理中のタスクがGoツリー(メインリポジトリ)のビルドではない場合(つまり、packagePathが空でない場合)、関数はnil, nilを返して終了します。

しかし、もしGoツリーのコミットがすべて処理され、かつpackagePathが空の場合(つまり、Goツリー自体のビルドタスクを探している場合)、新たなロジックが導入されます。このロジックは以下のステップで動作します。

  1. Go tipタグの取得: GetTag(c, "tip")を呼び出して、現在のGo tipのハッシュ(コミットID)を取得します。
  2. サブリポジトリパッケージの取得: Packages(c, "subrepo")を呼び出して、監視対象となっているすべてのサブリポジトリパッケージのリストを取得します。
  3. サブリポジトリの最新コミットとGo tipでのビルド結果の確認:
    • 各サブリポジトリパッケージについて、pkg.LastCommit(c)を呼び出して、そのサブリポジトリの最新コミットを取得します。
    • 取得したサブリポジトリの最新コミットが、現在のGo tipのハッシュ(tag.Hash)で既にビルドされているかどうかをcom.Result(builder, tag.Hash) == nilで確認します。
    • もしビルド結果が存在しない(nilである)場合、それはそのサブリポジトリの最新コミットが現在のGo tipでまだビルドされていないことを意味します。
  4. Go tipの再ビルド要求:
    • ビルドされていないサブリポジトリが見つかった場合、tag.Commit(c)を呼び出してGo tipに対応するCommitオブジェクトを取得し、それをビルドタスクとして返します。これにより、ビルダーはGo tipを再ビルドし、その過程でサブリポジトリも最新のGo tipでテストされることになります。
    • この処理は、TODO(adg): do the same for "weekly" and "release" tags.というコメントがあり、将来的にはweeklyreleaseといった他のタグに対しても同様のロジックを適用する意図が示されています。

また、build.goにはTag型にCommitメソッドが追加されました。これは、特定のTag(例: "tip")に対応するCommitオブジェクトをデータストアから取得するためのヘルパー関数です。

test.goでは、この新しいロジックをテストするための新しいテストケースが追加されています。特に、/todoエンドポイントがbuild-go-commitタイプのタスクを返し、それが特定のGoコミット(この場合は0005)をビルドするように要求するシナリオがテストされています。

ui.goでは、エラーロギングのレベルがc.Errorfからc.Warningfに変更されており、サブリポジトリの最新コミットが見つからない場合に致命的なエラーではなく警告として扱うようになっています。

コアとなるコードの変更箇所

このコミットで変更された主要なファイルと、その変更の概要は以下の通りです。

  1. misc/dashboard/app/build/build.go:

    • Tag構造体にCommitメソッドが追加されました。このメソッドは、Tagが持つハッシュ(コミットID)に対応するCommitオブジェクトをデータストアから取得します。
  2. misc/dashboard/app/build/handler.go:

    • buildTodo関数が大幅に修正されました。
    • Goツリーのコミットがすべて処理された後、サブリポジトリの最新コミットがGo tipでビルドされているかを確認する新しいロジックが追加されました。
    • もしサブリポジトリがGo tipでビルドされていない場合、ビルダーにGo tipの再ビルドを要求するCommitオブジェクトを返します。
    • 既存のpanic("unreachable")が削除され、より洗練された終了ロジックに置き換えられました。
  3. misc/dashboard/app/build/test.go:

    • testRequests変数に、新しいbuildTodoロジックをテストするためのエントリが追加されました。具体的には、Go tipの再ビルド要求シナリオをシミュレートするテストケースが含まれています。
    • テストのアサーション部分で、コミットハッシュの比較ロジックが微調整されました。
  4. misc/dashboard/app/build/ui.go:

    • TagState関数内で、pkg.LastCommit(c)がエラーを返した場合のロギングレベルがc.Errorfからc.Warningfに変更されました。これは、サブリポジトリの最新コミットが見つからない状況を致命的ではない警告として扱うためです。

コアとなるコードの解説

最も重要な変更はmisc/dashboard/app/build/handler.gobuildTodo関数にあります。

 // Nothing left to do if this is a package (not the Go tree).
 if packagePath != "" {
  return nil, nil
 }

 // If there are no Go tree commits left to build,
 // 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.
 tag, err := GetTag(c, "tip")
 if err != nil {
  return nil, err
 }
 pkgs, err := Packages(c, "subrepo")
 if err != nil {
  return nil, err
 }
 for _, pkg := range pkgs {
  com, err := pkg.LastCommit(c)
  if err != nil {
   c.Warningf("%v: no Commit found: %v", pkg, err)
   continue
  }
  if com.Result(builder, tag.Hash) == nil {
   return tag.Commit(c)
  }
 }
 return nil, nil

このコードブロックは、buildTodo関数がGoのメインリポジトリのビルドタスクをすべて処理し終えた後に実行されます。

  1. if packagePath != "" { return nil, nil }

    • これは、現在のビルド要求が特定のパッケージ(サブリポジトリなど)に対するものであり、Goツリー全体に対するものではない場合に、それ以上Goツリーのビルドタスクを探す必要がないことを示しています。この場合、関数はnil, nilを返して終了します。
  2. tag, err := GetTag(c, "tip")

    • Goの最新開発バージョンを示す"tip"タグの情報をデータストアから取得します。これには、tipが指すGoのコミットハッシュが含まれます。
  3. pkgs, err := Packages(c, "subrepo")

    • "subrepo"カテゴリに属するすべてのパッケージ(つまり、Goのサブリポジトリ)のリストをデータストアから取得します。
  4. for _, pkg := range pkgs { ... }

    • 取得した各サブリポジトリパッケージについてループ処理を行います。
  5. com, err := pkg.LastCommit(c)

    • 現在のサブリポジトリパッケージの最新コミット情報を取得します。
  6. if com.Result(builder, tag.Hash) == nil { return tag.Commit(c) }

    • この行がこのコミットの核心です。
    • com.Result(builder, tag.Hash)は、現在のbuilderが、このサブリポジトリの最新コミット(com)を、Go tipのハッシュ(tag.Hash)と組み合わせてビルドした結果があるかどうかを確認します。
    • もし結果がnilであれば、それは「このサブリポジトリの最新コミットは、現在のGo tipではまだビルドされていない」ことを意味します。
    • この場合、return tag.Commit(c)が実行されます。これは、ビルダーに対してGo tipのコミットをビルドするよう要求するTodo(タスク)を返します。ビルダーがGo tipをビルドする際には、その依存関係としてサブリポジトリも最新のGo tipでテストされることになります。

このロジックにより、Go tipが更新されるたびに、関連するサブリポジトリも最新のGo tipでビルドされることが保証され、Goエコシステム全体の健全性が維持されます。

関連リンク

参考にした情報源リンク