連載:Team Foundation Server 2008の下流工程への適用

第4回 チーム・ビルドによる開発の安定化

アバナード株式会社 安藤 大祐
2009/08/12
Page1 Page2 Page3

カスタム・ビルドのサンプル

 以下では、実際に筆者がプロジェクトで行ったことのある、ビルドのカスタマイズ例を紹介する。

ケース1:アセンブリ・バージョン番号の自動更新

 MSDNで公開されているAssemblyInfoタスクを利用することで、アセンブリのバージョン番号を自動更新することが可能だ。

 処理の流れとしては、

(1)AssenblyInfo.csファイルをチェックアウト
(2)AssenblyInfo.csファイルのAssemblyVersion属性の数値を変更
(3)AssenblyInfo.csファイルをチェックイン

となる。これらはコンパイル前に実施する必要があるため、BeforeCompileターゲットをオーバーライドして、処理を追加する。上記の(1)(2)(3)は、下記のコードのに該当する。

……省略……
<ItemGroup>
  <AssemblyInfoFiles Include="$(SolutionRoot)\XXX\$AssemblyInfo.cs"/>   
  <AssemblyInfoFiles Include="$(SolutionRoot)\YYY\$AssemblyInfo.cs"/>
  <AssemblyInfoFiles Include="$(SolutionRoot)\XXX\$AssemblyInfo.cs"/>
  ……省略……
</ItemGroup>

<PropertyGroup>   
  <AssemblyBuildNumberType>AutoIncrement</AssemblyBuildNumberType>
  <AssemblyRevisionType>NoIncrement</AssemblyRevisionType>
</PropertyGroup>

<Target   
  Name="BeforeCompile"
  DependsOnTargets="UpdateAssemblyInfoFiles;" />

<Target Name="UpdateAssemblyInfoFiles" >
  <SourceTfs.Checkout    
    Path="%(AssemblyInfoFiles.Identity)"
    TfsVersion="2008" />

  <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFiles)"   
       AssemblyMajorVersion="$(AssemblyMajorVersion)"
       AssemblyMinorVersion="$(AssemblyMinorVersion)"
       AssemblyBuildNumber="$(AssemblyBuildNumber)"
       AssemblyRevision="$(AssemblyRevision)"
       AssemblyBuildNumberType="$(AssemblyBuildNumberType)"
       AssemblyBuildNumberFormat="$(AssemblyBuildNumberFormat)"
       AssemblyRevisionType="$(AssemblyRevisionType)"
       AssemblyRevisionFormat="$(AssemblyRevisionFormat)">
    <Output TaskParameter="MaxAssemblyVersion"
            PropertyName="MaxAssemblyVersion"/>
  </AssemblyInfo>

  <SourceTfs.Checkin   
    Path="%(AssemblyInfoFiles.Identity)"
    Comments="アセンブリ・バージョン番号を更新します。"
    overrideText="チーム・ビルドによる更新。"
    TfsVersion="2008" />
</Target>
……省略……
アセンブリ・バージョン番号の自動更新スクリプト(TfsBuild.projファイル)
アセンブリ番号の自動更新はコンパイル前に実施する必要があるため、BeforeCompileターゲットをオーバーライドして、そこに更新処理を追加する。
  更新対象のAssemblyInfo.csファイルのリストを指定。
  アセンブリ番号の更新ポリシーを定義。この例では、アセンブリ・ビルド番号をインクリメントする設定を行っている。ほかにも、固定値や日時などを設定することが可能。詳細は、AssenmlyInfoタスクに含まれるヘルプ(AssemblyInfoTask.chm)を参照すること。
  BeforeCompileターゲットをオーバーライドしている。DependentsOnTargets属性に、BeforeCompileターゲットがコールされたときに実行されるターゲットのリストを指定する(セミコロン区切り)。
  ソース管理から、AssenmblyInfo.csファイルをチェックアウトしている。チーム・ビルドでは、ファイルのチェックイン・アウト用のタスクは用意されていないため、ここでは、オープンソースのSDC Tasks Libraryを利用している。
  AssenmblyInfo.csファイルを更新している。
  更新されたファイルを、ソース管理へチェックインする処理。

ケース2:複数環境用のパッケージ作成

 これは本番環境と検証環境でWeb.configファイルの内容を書き換えるための方法だ。チーム・ビルドのドロップ処理(=出力/配置処理)をカスタマイズし、環境ごとにWeb.configファイルが構成されたビルド結果を出力できる。

 Web.configファイルを修正する方法はいくつかあるが、今回は、MSBuild Community TasksのXmlMassUpdateタスクを利用する。XmlMassUpdateタスクは、複数のXMLファイルを簡単にマージすることが可能だ。

 例えば、開発環境用に作られているWeb.configファイルをベースに、検証環境や本番環境などの環境ごとに異なる差分情報を記述したWeb.config.substitutionsファイルの内容を(環境別に)マージして、各環境用のWeb.configファイルを生成する。XmlMassUpdateタスクの詳細については本稿では割愛するが、詳細は、以前に筆者がブログに記載したものがあるので、そこを参考にしていただきたい。

……省略……
<PropertyGroup>
  <SkipDropBuild>true</SkipDropBuild>   
</PropertyGroup>

<Target   
  Name="AfterDropBuild"
  DependsOnTargets="DeployWebSite;" />

<Target Name="DeployWebSite">

  <PropertyGroup>
    <WebSiteRoot>
      $(BinariesRoot)\Mixed Platforms\Release\_PublishedWebsites\MyWebSite
    </WebSiteRoot>
    <DeployTargetRoot>
      $(DropLocation)\$(BuildNumber)
    </DeployTargetRoot>
  </PropertyGroup>

  <ItemGroup>
    <CopyContents Include="$(WebSiteRoot)\**\*.*" />
  </ItemGroup>

  <!-- 配置用Webサイトを、検証環境用、本番環境用に分けてコピーする -->
  <Copy
    SourceFiles="@(CopyContents)"   
    DestinationFiles="@(CopyContents->'$(DeployTargetRoot)\STD\%(RecursiveDir)%(Filename)%(Extension)')" />
  <Copy
    SourceFiles="@(CopyContents)"
    DestinationFiles="@(CopyContents->'$(DeployTargetRoot)\PRD\%(RecursiveDir)%(Filename)%(Extension)')" />

  <!-- 検証環境用、本番環境用に、Web.configファイルを更新する -->
  <XmlMassUpdate   
    ContentFile="$(DeployWebsiteRoot)\Web.config"
    ContentRoot="/configuration"
    SubstitutionsFile="$(WebsiteRoot)\Web.config.substitutions"
    SubstitutionsRoot="/configuration/substitutions/STD"
    MergedFile="$(DeployTargetRoot)\STD\Web.config" />
  <XmlMassUpdate
    ContentFile="$(DeployWebsiteRoot)\Web.config"
    ContentRoot="/configuration"
    SubstitutionsFile="$(WebsiteRoot)\Web.config.substitutions"
    SubstitutionsRoot="/configuration/substitutions/PRD"
    MergedFile="$(DeployTargetRoot)\PRD\Web.config" />

  <!-- Web.config.substitutionsファイルを削除する -->
  <Delete   
    Files="$(DeployTargetRoot)\STD\Web.config.substitutions" />
  <Delete
    Files="$(DeployTargetRoot)\PRD\Web.config.substitutions" />

</Target>
……省略……
複数環境用のパッケージ作成スクリプト(TfsBuild.projファイル)
XmlMassUpdateタスクを使って、Web.configファイルとWeb.config.substitutionsファイルをマージして、環境ごとのWeb.configファイルを作成する。
  この例では、ドロップ処理を独自処理で置き換えるため、既存のドロップ処理はスキップさせる。
  AfterDropBuildターゲットをオーバーライドし、DeployWebSiteターゲットの呼び出しを追加。
  ビルドにより出力されたプリコンパイル済みWebサイトを、検証環境(STD)向け、本番環境(PRD)向けフォルダへそれぞれコピー。
  XmlMassUpdateタスクを利用し、(Web.config.substitutionsファイルの内容を環境別にマージして)各環境向けのWeb.configを更新する。各環境用の値は、Web.configと同じフォルダに配置されている、Web.config.substitutionsファイルに記述されている。
  最後に、不要になったWeb.config.substitutionsファイルを削除。

 次のコードは、Web.config.substitutionsファイルの例。

<?xml version="1.0" encoding="utf-8"?>
<configuration>   
  <substitutions
      xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">

    <!-- 本番環境用 -->
    <PRD>   
      <connectionStrings>
        <add xmu:key="name" name="Default"
             connectionString
                 ="Data Source=XXXX;Initial Catalog=XXX;" />
      </connectionStrings>
      <system.web>
        <sessionState xmu:action="Remove" />
        <sessionState mode="SQLServer"
                      sqlConnectionString="Data Source=XXXX;"
                      cookieless="false" timeout="30" />
      </system.web>
      <appSettings>
        <add xmu:key="key" key="DebugMode" value="false" />
      </appSettings>
    </PRD>

    <!-- 検証環境用 -->
    <STD>   
      <connectionStrings>
        <add xmu:key="name" name="Default"
             connectionString
                 ="Data Source=YYYY;Initial Catalog=YYY;" />
      </connectionStrings>
      <system.web>
        <sessionState xmu:action="Remove" />
        <sessionState mode="SQLServer"
                      sqlConnectionString="Data Source=YYYY;"
                      cookieless="false" timeout="30" />
      </system.web>
      <appSettings>
        <add xmu:key="key" key="DebugMode" value="true" />
      </appSettings>
    </STD>

  </substitutions>
</configuration>
Web.config.substitutionsファイルのサンプル
検証環境や本番環境などの環境ごとに異なる差分情報を記述している。
  configuration要素の下に、substitutions要素を作成。差分のマージの対象となる範囲をマークする。
  本番環境(PRD)、検証環境(STD)それぞれ固有の値を記述する範囲をマークする。

ケース3:データベースの差分DDL文の作成

 Visual Studio 2008 Database Editionを利用することで、特定のデータベースと、ビルド結果のデータベース・スキーマの差分DDL文(つまりは、ALTER文)を自動生成することが可能だ。といっても、完全に信頼できるというレベルには正直、達成しておらず、あくまでSQL生成の元ネタとして利用するにとどめた方が無難だ。それでも、かなり強力な機能である。

 次のコードは、差分DLL文を作成するスクリプトの例だ。

……省略……
<Target
  Name="AfterDropBuild"
  DependsOnTargets="CreateDatabasePackage;" />

<Target Name="CreateDatabasePackage" >

  <PropertyGroup>
    <VSDBCMD>"C:\Program Files\Microsoft Visual Studio 9.0\VSTSDB\Deploy\vsdbcmd.exe"</VSDBCMD>
    <DiffDbCS>Data Source=XXXX;Initial Catalog=DiffDB;Integrated Security=True</DiffDbCS>   
    <DropDatabasePath>$(DropLocation)\$(BuildNumber)\MyDatabase\</DropDatabasePath>
  </PropertyGroup>

  <Exec    
    Command="$(VSDBCMD) /dsp:Sql /cs:&quot;$(DiffDbCS)&quot; /model:MyDatabase.dbschema /p:TargetDatabase=MyDatabase /a:Deploy /manifest:MyDatabase.deploymanifest /script:MyDatabase.DDL.sql"
    WorkingDirectory="$(DropDatabasePath)" />

</Target>
……省略……
差分DLL文作成スクリプト(TfsBuild.projファイル)
Visual Studio 2008 Database Editionの機能を使って、差分DLL文を作成する。
  この例では、ドロップ処理を独自処理で置き換えるため、既存のドロップ処理はスキップさせる。
  Visual Studio 2008 Database Editionに付属するVSDBCMD.exeファイルをコマンドライン呼び出すことで、差分DLL文を作成する。

[参考]チーム・ビルドと本番環境がつながっていない場合の差分SQL文の出力方法

 Visual Studio 2008 Database Editionで追加された“VSDBCMD.exe”は、コマンド・プロンプトからデータベースを配置することができるツールであるが、もう1つの大きな特徴として、Visual Studioがインストールされていない環境でも利用可能であることが挙げられる。

 つまり、TFSやチーム・ビルドが稼働している開発環境と、スキーマの比較先である本番環境のデータベースが物理的に切断されていても、VSDBCMD.exeファイルの機能を利用した差分スキーマ(=本番稼働しているデータベースとビルド結果に含まれるデータベース・スキーマの差分)を生成することができる。

 詳細は、MSDNのデータベースのビルドおよびステージング環境または稼働環境への配置を参照してほしい。

まとめ

 今回は、チーム・ビルドの概要とカスタマイズのノウハウについて紹介した。ここで紹介したものはごく一般的なものであり、ほかにも、ClickOnceのマニフェスト・ファイルの作成や、.MSIインストーラの作成、コード・ドキュメント、検証環境配置後の機能テストも自動で実行してしまう……など、ビルド・プロセスで実行しなければならないことは多い。

 が、その基本は本稿で説明したとおりで、後はMSBuildのテクニック次第の話であり、そんなに難しいことはない。皆さんのプロジェクトでもチーム・ビルドを活用し、プロジェクトをどんどんスピーディなものにしてもらえればと思う。End of Article

 

 INDEX
  [連載] Team Foundation Server 2008の下流工程への適用
  第4回 チーム・ビルドによる開発の安定化
    1.チーム・ビルドのアーキテクチャ
    2.自動ビルドの効果と種類
  3.ビルド・プロセスのカスタマイズ

インデックス・ページヘ  「Team Foundation Server 2008の下流工程への適用」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間