Team Foundation サービスによる Windows ストア アプリのビルドと検証
Thomas LeBrun
Team Foundation サービスは 2012 年 10 月に最終版がリリースされました。この Team Foundation サービスは、Visual Studio Team Foundation Server (TFS) のクラウド版で、優れた品質のソフトウェアを配信するのに役立つ多くの機能を提供します。そこで、このサービスを使って Windows 8 を対象とするソフトウェアを開発しようと考えても不思議はありません。
Windows 8 と Team Foundation サービスという 2 つの製品の能力を組み合わせることは可能なのでしょうか。つまり、Team Foundation サービスを使って Windows ストア アプリをビルドできるのでしょうか。残念ながら、いくつかの制限事項により、何も手を加えないでこれを実現することはできません。この制限事項については、今回の後半で紹介します。ただし、今回は、この制限事項を回避するのに必要な手順を示し、ビルド プロセス中に Windows ストア アプリを検証できるようにします。
まず、Team Foundation サービスについて簡単に紹介しておきましょう。
Team Foundation サービスの概要
Team Foundation サービスはクラウドベースのサービスなので、開発者はインストールや管理に手間をかけることなく、TFS が提供する機能にアクセスできます。bit.ly/ZusqUYからサインアップ (無料) するだけです。
この製品が提供するサービスには、高品質のソフトウェアを開発および配信するための主な機能が 3 つあります。
ソース コード管理: 現在使用しているツールと、お気に入りの言語でソース管理機能を利用できます。ソース管理機能では、事実上すべての種類のファイル (C#、C++、HTML、PHP、Java など) を処理できます。Visual Studio や Eclipse などの IDE を使用していれば、アプリの開発とソース管理へのファイルのチェックインに引き続き使用できます。
ソース管理のアーキテクチャでは、ソース コードのローカル コピーを格納するローカル ワークスペースが提供されます。クラウドに接続されていない状態では、すべての変更がこのワークスペースで行われます。その後再び接続するときに、単にコードをチェックインしてサーバーにプッシュし、すべてのバージョンの完全な履歴を管理し、変更を追跡してロールバックできるようにします。
グループ作業: Team Foundation サービスは、主にタスク ボードというツールを利用して、複数の開発者が連携して作業できるようにします。このタスク ボードには、カスタム ダッシュボードを作成できる最新のブラウザーからアクセスできます。タスク ボードを使って、作業項目、ビルド状態、テスト結果などの情報を管理します (図 1 参照)。
図 1 Team Foundation サービスのサンプル ダッシュボード
ビルド サービス: 本稿の執筆時点ではまだプレビュー段階ですが、ビルド サービスは TFS 2010 の一部であるチーム ビルドに基づいていて、クラウドでの自動ビルドを実現します。
ビルド サービスでは、継続的インテグレーション、夜間ビルド、ゲート チェックイン ビルドなど、チーム ビルドのすべての標準機能を使用できます。そのうえ、ビルド テンプレートは完全にカスタマイズ可能です。Windows Azure に継続的に展開するための既成テンプレートもあります (ソース管理でコードをチェックインして、Windows Azure Web サイトで更新を確認します)。
ビルド サービスは、Windows Server 2008 R2、チーム ビルド、Visual Studio 2010 以降などで展開されたビルド サーバーでホストされます (必要なソフトウェアとオプションの完全なリストについては、次のページの下部を参照してください bit.ly/12Sf99Z(英語))。ほとんどのアプリは既定の構成で適切に機能しますが、Windows ストア アプリは例外です。図 2に示すように、Windows ストア アプリは Windows 8 (または、Windows Server 2012) でビルドする必要がありますが、Windows ストア アプリはビルド サーバーにはインストールされません。
図 2 Team Foundation サービスはそのままでは Windows ストア アプリをビルドできない
既に述べたように、Team Foundation サービスでは、何も手を加えずに Windows ストア アプリをビルドすることができません。ただし、回避方法はあります。基本的には、Windows 8 コンピューターをインストールすることで回避します。このコンピューターは、Team Foundation サービスの Windows ストア アプリ専用の新しいビルド エージェントになります。ここからは、コンピューターの実装方法を示します。
Team Foundation サービスによる Windows ストア アプリのビルド
Team Foundation サービスを使って Windows ストア アプリをビルドするために必要な手順は以下のとおりです。
ビルド サービスのインストール: まず、Windows 8 を実行するコンピューターが必要です。インターネット経由でアクセスできれば、物理コンピューターでも仮想マシン (VM) でも構いません。次に、そのコンピューターに TFS 2012 をインストールします。TFS をインストールしただけで、構成が完了し、使用準備が整うわけではありません。インストールするのは、ビルド サービスを構成できるようにすることだけが目的です。Team Foundation Application Server は、Team Foundation サービスから入手できるため、取得する必要はありません。
ビルド サービスをインストールしたら、専用のチーム プロジェクト コレクションを使ってサービスを構成します。今回の場合は、他の TFS コンポーネントを設定しないで、Team Foundation サービスだけを使うため、Team Foundation サービス アカウントで利用できるチーム プロジェクト コレクションを指定して、構成を完了します (図 3 参照)。
図 3 専用のチーム プロジェクト コレクションを使った Team Foundation ビルド サービスのインストール
ビルド サービスの構成: 次の手順に進む前に、TFS とビルド アーキテクチャの基礎をいくつか理解しておく必要があります。
それぞれの TFS には、専用のビルド コントローラーのセットがあります。ビルド コントローラーは、専用のビルド エージェントを使ってビルド要求を受け取り、実行するエンドポイントです。ビルド エージェントは、ビルドの最も重要な作業を行います。つまり、ソース管理からファイルを取得し、コードをコンパイルして、単体テストを実行します。
Team Foundation サービスには専用のビルド コントローラー (ホスト型のビルド コントローラー) があるため、必要なのはこのコントローラーで実行する新しいエージェントを作成することだけのように思えますが、残念ながら、オンプレミスのビルド エージェントはホスト型のビルド コントローラーにアタッチできません。別のビルド コントローラーを選択するか、新しくビルド コントローラーを作成しなければなりません。
説明を簡単にするために、新しくビルド コントローラーを作成することにしましょう (図 4 参照)。
図 4 新しいビルド コントローラーの作成
コントローラーを作成して稼働させたら、次は Windows ストア アプリのビルド専用に新しいエージェントを設定します。新しいビルド エージェントは、[新規エージェント] リンクをクリックし、フィールドに入力するだけで簡単に作成できます。実際の運用環境では、ビルド コントローラーには多くのエージェントを設定し、Windows ストア アプリは Windows 8 で実行するエージェントでのみビルドするように専用のタグを追加します (図 5参照)。これは必須ではありませんが、後でビルド定義を作成する際にこのタグを指定して、このエージェントのみをビルド プロセスに使用するように設定できます。
図 5 新しいビルド エージェントの作成
続いて、[ビルド サービス] プロパティを開き、対話型で実行するように設定します。Windows ストア アプリをビルドするだけであれば、この手順は必須ではありません。ただし、アプリを検証する場合は、Team Foundation サービスとビルド サービスがアプリをビルド コンピューターにインストールして起動することになるため、ビルド サービスを対話型で実行するように構成する必要があります。
Visual Studio Team Explorer の [ビルド] ページで、[アクション] をクリックし、次に [ビルド コントローラーの管理] をクリックして、インストールされたすべてのビルド コントローラー (および専用のエージェント) のリストを表示するウィンドウを開きます。構成が成功した場合、新しいコントローラーとエージェントが表示されます。
単体テストを実行するためのビルド エージェントの準備: ビルド エージェントをホストするコンピューターを単体テストの実行に使用する場合は、さらに手順が必要です。まず、Windows 8 の開発者ライセンスをコンピューターにインストールする必要があります。開発者ライセンスは無料で、30 日ごとに更新する必要があります (Windows ストア アカウントがある場合は 90 日ごと)。また、既に Microsoft アカウントをお持ちであれば必要なだけ利用できます。開発者ライセンスを取得する方法は 2 つあります。ビルド コンピューターで Windows ストア アプリを作成してもかまわない場合は、ダイアログ ボックスを開き、有効なライセンスを取得します。ビルド コンピューターにフェイク アプリを作成したくない場合は、次の Windows PowerShell コマンドを実行して同じダイアログ ボックスを表示します。
C:\PS> Show-WindowsDeveloperLicenseRegistration
開発者ライセンスを取得したら、ビルド エージェントで (実行する単体テストを含むコード プロジェクトから) 単体テスト証明書を生成してインストールする必要があります。この手順のために、開発者のコンピューターでアプリ パッケージを生成します。Visual Studio で、[ストア]、[アプリ パッケージの作成] の順にクリックします。これにより、Windows ストア アプリ (拡張子 .appx のファイル内) とその証明書を含むフォルダーが作成されます。
ビルド コンピューターに証明書をインストールするには、管理者としてコマンド プロンプトを開き、次のコマンドを入力します。
certutil -addstore root certificate_file
certificate_file は、証明書ファイルへのパスを表します。
Windows ストア アプリのビルド: コントローラーとエージェントを実行したら、Windows ストア アプリのビルドは他の種類のアプリのビルドと同じです。新しいビルド定義を設定し、設定したばかりの新しいビルド コントローラーを使用することを指定するだけです。ビルド プロセスが Windows 8 で実行するビルド エージェントを使用するように、ビルド定義の [プロセス] タブで、ビルド エージェントを作成した際に指定したタグを選択します (図 6 参照)。
図 6 指定したタグを使ったビルド プロセスの作成
これを行ったら、作成したばかりのビルド定義を使って新しいビルドをキューに登録することでビルドが起動され、指定されたタグによって正しいエージェントでビルドが実行されることが保証されるため、失敗することはなくなります。
ご覧のように、Team Foundation サービスを使って Windows ストア アプリをビルドするのは非常に簡単で、きわめて強力なうえ、ビルド プロセスを完全にカスタマイズできます。ただし、まだ問題が残っています。ビルドが成功しても、アプリが適切に実行されることや、検証の基本的な手順にすべて合格することが保証されるわけでもありません。ここからは、アプリの検証方法と、検証が成功したかどうかをユーザーに (ビルド レポートを通じて) 示す方法を説明します。
チーム ビルド中の Windows ストア アプリの検証
ご存知とは思いますが、Windows ストアに公開するには、アプリが認証されていなければなりません。つまり、必要な検証手順に合格する必要があります。アプリは、ビルド プロセス中に検証できます。そのためには、ビルド後のイベントを追加し、Windows アプリ認定キット (ACK) を起動して、アプリを検証するだけです。ただし、何も手を加えなければ、検証の結果がユーザーに通知されません。以下に、ビルド プロセスを拡張してこの手順を含める方法を示します。
ビルド プロセス中に ACK の実行を組み込むには、プロジェクト ファイルを変更して、次の PostPackageEvent を追加する必要があります。
<Target Name="PostPackageEvent" AfterTargets="_GenerateAppxPackage">
<Exec Command=""$(TargetPlatformSdkPath)App Certification Kit\appcert.exe" reset"/>
<Exec Command=""$(TargetPlatformSdkPath)\App Certification Kit\appcert.exe" test -apptype windowsstoreapp -AppxPackagePath "$(FinalAppxPackage)" –reportoutputpath "$(outdir)\ValidationResult.xml"" />
<Exec Command="copy "$(userprofile)\appdata\Local\Microsoft\appcertkit\ValidationResult.htm" "$(outdir)\ValidationResult.htm""/>
</Target>
このコードが実行されると、ValidationResult.html ファイルが作成され、ACK によって実行された検証の結果が含まれます。ビルドの実行時にビルド サーバーに接続している場合は、ACK による検証のためアプリが起動されるのがわかります。これが通常の処理です。アプリは、インストールされ、検証された後、テスト完了時に自動的に削除されます。ビルド サービスを対話型で実行するように構成し、アプリのインストールと実行を許可したことを思い出してください。これを行っていないと、ビルド中にエラーが発生する場合があります。
ビルド プロセス自体は検証結果に影響されないため、ユーザーはテスト結果を確認してアプリに検証エラーが発生したかどうかを把握できる必要があります。さいわい、ビルド レポートを強化して、検証でなんらかのエラーが発生したかどうかをユーザーに通知するようにできます。そこで、ビルド レポートをカスタマイズして ACK ツールの検証結果をレポートに統合する方法を示します。
ビルド レポートのカスタマイズ: ACK は HTML ファイルと XML ファイルを両方作成し、選択したフォルダーに保存します。この XML ファイルを使って、ユーザーに検証結果を通知するようにビルド レポートを変更するカスタム ワークフロー アクティビティを作成します。
このアクティビティを作成するコードは非常に単純です。(検証結果を含む) XML ファイルを見つけ、そのファイルを読み取り、"OVERALL_RESULT" 属性の値を探して値を返します。図 7に、CheckWackResultsActivity アクティビティを作成するコードを示します。
図 7 CheckWackResultsActivity
[BuildActivity(HostEnvironmentOption.All)]
public sealed class CheckWackResultsActivity : CodeActivity<bool>
{
[RequiredArgument]
public InArgument<string> DropLocation { get; set; }
[RequiredArgument]
public InArgument<string> WackResultsFilename { get; set; }
[RequiredArgument]
public InArgument<string> WackReportFilename { get; set; }
public OutArgument<string> WackReportFilePath { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override bool Execute(CodeActivityContext context)
{
string dropLocation = context.GetValue(this.DropLocation);
string wackResultsFilename =
context.GetValue(this.WackResultsFilename);
string wackReportFilename = context.GetValue(this.WackReportFilename);
var dropLocationFiles = Directory.GetFiles(dropLocation, "*.*",
SearchOption.AllDirectories);
if (dropLocationFiles.Any())
{
var resultFile = dropLocationFiles.FirstOrDefault(
f => Path.GetFileName(f).ToLowerInvariant() ==
wackResultsFilename.ToLowerInvariant());
if (!string.IsNullOrWhiteSpace(resultFile))
{
var xDocument = XDocument.Load(resultFile);
var reportElement = xDocument.Element("REPORT");
if (reportElement != null)
{
var resultAttribute = reportElement.Attribute("OVERALL_RESULT");
if (resultAttribute != null)
{
context.SetValue(this.WackReportFilePath,
Path.GetDirectoryName(resultFile));
var validationResult = resultAttribute.Value;
// Fail or Pass
if (validationResult.ToLowerInvariant() == "fail")
{
return false;
}
return true;
}
}
}
throw new InvalidOperationException(
"Unable to find the Windows App Certification Kit results file!");
}
else
{
throw new InvalidOperationException(
"There are no files in the drop location!");
}
throw new InvalidOperationException(
"Unknow error while checking the content of the Windows App
Certification Kit results file!");
}
}
既定では、ビルド アクティビティはビルド エージェントで実行されます。ただし、シナリオによっては、ビルド開始前の手順や、ビルド完了直前の手順でアクティビティを実行することも考えられます。このような柔軟性を持たせるには、エージェントではなく、コントローラーでアクティビティを実行する必要があります。これは BuildActivityAttribute 属性を使って実現します。この属性は引数として列挙値 HostEnvironmentOption.All を受け取ります (図 7 参照)。適切な HostEnvironmentOption オプションを使用しないと、ビルド プロセス中にエラーが発生することに注意します。
CheckWackResultsActivity クラスは CodeActivity を継承し、結果値からビルド レポートに適切なメッセージを表示できるようにします。このようなメッセージを表示するには、TFS 2012 から導入された新しいアクティビティ WriteCustomSummaryInfo を使用できます。このアクティビティは、シンプルなテキストを追加する代わりに、ビルド レポートで専用のカテゴリを追加できるようにするため、ビルド レポートにメッセージを追加する場合に非常に便利です。
次のプロパティを指定する必要があります。
- Message: レポートに表示するテキスト。
- SectionDisplayName: セクションのヘッダーに相当。
- SectionKey: セクションの一意値。
- SectionPriority: レポートでの新しいセクションの位置を定義します (0 が最も優先順位が高く、標準セクションは 100 から始まります)。
そのため、新しいアクティビティと WriteCustomSummaryInfo を使って、ビルド プロセスを変更して検証結果をチェックし、ビルド レポートに新しいセクションを追加できます。図 8 に、変更したビルド プロセスの XAML コードを示します。
図 8 変更後のビルド プロセス
<Sequence DisplayName="Windows 8" sap2010:WorkflowViewState.IdRef="Sequence_4">
<Sequence.Variables>
<Variable x:TypeArguments="x:Boolean" Name="WackToolRanSuccessfully" />
<Variable x:TypeArguments="x:String" Name="WackReportFilePath" />
</Sequence.Variables>
<c:CheckWackResultsActivity DropLocation="[DropLocation]"
sap2010:WorkflowViewState.IdRef="CheckWackResultsActivity_3"
Result="[WackToolRanSuccessfully]"
WackReportFilePath="[WackReportFilePath]"
WackReportFilename="ValidationResult.html"
WackResultsFilename="ValidationResult.xml" />
<If Condition="[Not WackToolRanSuccessfully]"
sap2010:WorkflowViewState.IdRef="If_4">
<If.Then>
<Sequence sap2010:WorkflowViewState.IdRef="Sequence_6">
<mtbwa:WriteCustomSummaryInformation
sap2010:WorkflowViewState.IdRef=
"WriteCustomSummaryInformation_2"
Message="["Windows App Certification Kit ran with errors.
Click [here](" & WackReportFilePath & ") to
access the folder containing the report."]"
SectionDisplayName="Windows 8" SectionKey="Windows8"
SectionPriority="75"
mva:VisualBasic.Settings=
"Assembly references and imported namespaces
serialized as XML namespaces" />
<mtbwa:WriteBuildError
sap2010:WorkflowViewState.IdRef="WriteBuildError_1"
Message="Windows App Certification Kit ran with errors." />
<mtbwa:SetBuildProperties
CompilationStatus=
"[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Failed]"
DisplayName="Set Status and CompilationStatus to Failed"
sap2010:WorkflowViewState.IdRef="SetBuildProperties_1"
mtbwt:BuildTrackingParticipant.Importance=
"Low" PropertiesToSet="CompilationStatus" />
</Sequence>
</If.Then>
<If.Else>
<mtbwa:WriteCustomSummaryInformation
sap2010:WorkflowViewState.IdRef="WriteCustomSummaryInformation_1"
Message="["Windows App Certification Kit ran with success.
Click [here](" & WackReportFilePath & ") to
access the folder containing the report."]"
SectionDisplayName="Windows 8" SectionKey="Windows8"
SectionPriority="75"
mva:VisualBasic.Settings=
"Assembly references and imported namespaces
serialized as XML namespaces" />
</If.Else>
</If>
</Sequence>
図 8で、検証が失敗すると、コンパイル状態が "Failed (失敗)" に設定され、ビルド プロセスを続行できなくなります。これは必須ではなく、検証の結果にかかわらず、常にビルド プロセスを完了させる場合は削除できます。
これで、ビルドがトリガされるたびに、ビルド レポートは Windows 8 専用の新しいセクションを表示して検証結果を示すようになります (図 9 参照)。
図 9 検証結果を表示するビルド レポートの新しいセクション
WriteCustomSummaryInfo を使用し、テキストとリンクだけを使ってビルド レポートを強化できます。より複雑な変更が必要な場合でも (画像の追加など)、TFS 2010 で使用した手法を適用できます。
Windows ストア アプリ用のビルド プロセス テンプレートをカスタマイズするには多くの可能性があり、さいわい、こうしたカスタマイズは Team Foundation サービスでもオンプレミス TFS でもほぼ同じです。
Thomas Lebrun は、Infinite Square のテクニカル リーダーです。同社は、フランスでのマイクロソフトのパートナーで Windows 8/Windows Phone、Team Foundation Server、SharePoint などのテクノロジに取り組んでいます。Lebrun は、Windows Presentation Foundation と Model-View-ViewModel パターンに関する 2 冊のフランス語の本の著者であり、フランスのイベントで定期的に講演しています。彼のブログ blog.thomaslebrun.net(英語) とツイッター twitter.com/thomas_lebrunを参照してください。
この記事のレビューに協力してくれた技術スタッフの Chris Patterson (マイクロソフト) に心より感謝いたします。