TFS2008を使い始めて早半年。まだまだ使いこなせいてませんが、今回は自動ビルドでのビルド番号を生成することにチャレンジしてみました。
役に立たないMSDNとインターネット検索で見よう見まねでコツコツと作り上げましたので、忘れないうちにアップしておきます。
何分素人が作成しているので間違いだらけだと思いますが、何をやったのか私自身忘れそうなのでメモとして残します。
まず役立たずのMSDNはこちらです。
方法 : ビルド番号をカスタマイズする
これを読むとターゲットって何?タスクって何?と疑問が次から次へと湧き出てきます。
ターゲットの説明はこちらにあります。
カスタマイズ可能な Team Foundation のビルド ターゲット
ビルドの作業手順がターゲットとして定義されており、その中でもカスタマイズできるターゲットとカスタマイズできないターゲットがあるとのことです。
ビルド番号を生成したいのならばBuildNumberOverrideTargetでやりなさいと言うことです。
続いてタスクですが、ターゲット内で実行されるコマンドのようなことです。
タスクの説明はこちらです。
MSBuild タスク リファレンス
スクリプトのコマンドがいくつか定義されており、これらで何とかせいと言うのがビルド定義のようです。
で、色々調べてビルド番号を保持する方法がわからず、始めはSQL Server上に専用のテーブルを構築し、そこからビルド番号を取得するプログラムを作成して参照するようにしていましたが、MSBuild Community Tasks Projectなるものを知り、そちらで実現させる方法に変更しました。
MSBuild Community Tasks Project
こちらからインストールモジュールをダウンロードしてインストールすればタスクが拡張されます。
<Import Project="$(MSBuildExtensionsPath)¥MSBuildCommunityTasks¥MSBuild.Community.Tasks.Targets" />
と記述すれば利用することができます。
ちなみにターゲットとタスクの関係がある程度理解できてきたら以下の場所に実際にターゲットが定義されているファイルがありますので参照してみると参考になります。
C:¥Program Files¥MSBuild¥Microsoft¥VisualStudio¥TeamBuild¥Microsoft.TeamFoundation.Build.targets
絶対にこのファイルは修正してはいけません。カスタマイズはビルドプロジェクトファイルで行ってください。
でもMSDNの説明ではどうやって使って良いのかわからないタスクなど、パラメータの設定方法など参考になることが沢山あります。
変数関係も私としてはとてもあやふやな状態です。
変数と言うよりパラメータと呼んだ方が良いようですが、<PropertyGroup>で定義するようです。これはターゲットの外で定義しても中で定義しても良いようですが、おそらくスコープは違うでしょう。
使い方は<名前>値</名前>が原則です。これを参照する場合は$(名前)となります。但し、このパターンは単一の値しか持たない変数です。リストと言うか配列として値を持つ場合には
<名前 Include="値"/>
<名前 Include="値"/>
<名前 Include="値"/>
と同じ名前で入れたい値を続けて指定します。この場合、指定する値はIncludeで指定します。これにより指定した値がリストとして積み上がります。
また、値のところにワイルドカードを指定するとファイルのリストが格納されます。
このリストを参照するのは@(値)となります。
さて、本題のビルド番号ですが、以下がそのコードです。
チームプロジェクトのルートにVersion.txtを配置します。このテキストの内容は「1.0.0.0」などとしておきます。
VersionタスクでBuildTypeにIncrementを指定することにより$(Build)にVersion.txtから1加えた値が返ってきます。またVersion.txtも「1.0.1.0」に変更されます。
VersionタスクでVersion.txtが変更されるので、その前にCheckoutしています。これをしておかないとGet直前は読み取り専用となっているのでエラーになります。
またBuildNumberOverrideTargetではまだソースコードを取得していません。よって、本来ならばGetしたときに作られているディレクトリをこのタイミングで作成し、Version.txtだけをGetしています。
Versionタスクを実行した後は忘れずにCheckinしておきましょう。
ビルド番号で重要なのが$(BuildNumber)です。ビルドする上でのビルド番号をこの変数に格納しておきます。この変数の値がそのまま出力先のフォルダ名になるので注意しましょう。
始めは$(BuildNumber)に数値だけのビルド番号を格納し、UpdateBuildNumberDropLocationタスクで出力先を変更すれば...と思っていたのですが、ビルドが終わった後のCopyタスクでは$(BuildNumber)を使って出力先フォルダを指定しているので何の意味もありませんでした。
よって$(BuildNumber)には出力先フォルダ名を指定するようにします。私の場合はどうしてもフォルダ名に日付が欲しかったのでTimeタスクから現在の日付を取得して日付付きのフォルダ名を生成するようにしています。
とりあえず今回はビルド番号を取得するまでのお話しです。次回はこのビルド番号をAssemblyVersionやAssemblyFileVersionに反映させる方法を説明したいと思います。
<PropertyGroup>
<TF>"$(TeamBuildRefPath)¥..¥tf.exe"</TF>
<SourceDir>$(SolutionRoot)</SourceDir>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)¥MSBuildCommunityTasks¥MSBuild.Community.Tasks.Targets" />
<Target Name="BuildNumberOverrideTarget">
<Time>
<Output TaskParameter="Month" PropertyName="Month" />
<Output TaskParameter="Day" PropertyName="Day" />
<Output TaskParameter="Year" PropertyName="Year" />
<Output TaskParameter="Hour" PropertyName="Hour" />
<Output TaskParameter="Minute" PropertyName="Minute" />
<Output TaskParameter="Second" PropertyName="Second" />
</Time>
<Exec Command="MKDIR $(SourceDir)" Condition="!Exists('$(SourceDir)')" />
<Exec WorkingDirectory="$(SourceDir)"
Command="$(TF) get Version.txt /all"/>
<Exec WorkingDirectory="$(SourceDir)"
Command="$(TF) checkout Version.txt"/>
<Version VersionFile="$(SourceDir)¥Version.txt" RevisionType="None" BuildType="Increment">
<Output TaskParameter="Major" PropertyName="Major" />
<Output TaskParameter="Minor" PropertyName="Minor" />
<Output TaskParameter="Build" PropertyName="Build" />
<Output TaskParameter="Revision" PropertyName="Revision" />
</Version>
<Exec WorkingDirectory="$(SourceDir)"
Command="$(TF) checkin /comment:"Daily-Build: Version Update ($(Major).$(Minor).$(Build).$(Revision)) " /noprompt /override:"Daily-Build: Version Update" Version.txt"/>
<CreateProperty Value="$(BuildDefinition)_$(Year).$(Month).$(Day)($(Major).$(Minor).$(Build).$(Revision))">
<Output TaskParameter="Value" PropertyName="BuildNumber" />
</CreateProperty>
</Target>