kkamegawa's weblog

Visual Studio,TFS,ALM,VSTS,DevOps関係のことについていろいろと書いていきます。Google Analyticsで解析を行っています

.NET CoreアプリをVSTSで継続的インテグレーションする(Windows版)

はじめに

昨日dotnetConf関西で行ったセッション資料ではCI/CDの細かいやり方はのせていませんでしたので、ブログで詳細の解説を行います。 CIそのものはメニューのBuild & Releaseから構築します。この記事では新しいUIで説明していますが、以前のUIでもあまり関係ありません。
長くなったので、Linux版は別にします。

VSTSとビルドエージェント

VSTSには内蔵のビルドエージェント(Hosted Agent)があります。Hostedは今のところWindowsのエージェントのみになっているので、LinuxやMac環境でビルドする場合、独自のビルドサーバーを用意する必要があります。
ビルドエージェントは一台までであれば無料で接続できます。httpsのoutboundだけ通信できていればいいので、Firewallがある環境でも大体大丈夫です。

有料($15/月)支払って、一つのプールに二台以上のビルドエージェントを運用すると、並列でビルドができるようになります。並列可能ということ以外にも、エージェントを占有するので、占有しているエージェントではリポジトリのクローンが頻発しなくなるはずです。
原則1台1エージェントですが、登録するときにエージェントの名前を変えれば、一台のサーバーに複数のエージェントが登録できます。例えば、TFSとVSTSそれぞれ登録するとかもできます。サーバーの性能次第ですが、複数のVSTS/TFSを使っているときは試してみてください。

エージェントの対応OS

  • .NET CoreがサポートするWindows
  • Ubuntu 14.04/16.04(サービスとして動かす場合は16.04必須)
  • Red Hat Enterprise Linux 7.x
  • OS X 10.10/10.11

TFS 2015に接続する場合、WindowsではTFSに付属しているエージェントを使ってください。TFS "15"ではPAT(Personal Access Token)をサポートするので、.NET Core版のエージェントが使用可能になります。
VSTSのエージェントはソースも公開されています。

github.com

Windows(Hosted)で.NET Coreアプリをビルドする

では、実際にビルド定義を作ってみましょう。ASP.NET Core MVCアプリケーションを作ってコミットしておきます。
Visual Studioのテンプレートを使ってもいいですが、大部分を削除することになります。

NuGetの復元タスクを追加

f:id:kkamegawa:20160919120827p:plain

Add build stepからUtilityにあるCommand Lineを追加します。

NuGetパッケージを復元する
Tool: "c:\Program Files\dotnet\dotnet.exe"
Arguments : restore Working Folder : Project.jsonのあるフォルダ

ビルドタスク

ビルド用のCommand LineをAdd build stepで追加します。

Tool: "c:\Program Files\dotnet\dotnet.exe"
Arguments : build -c $(BuildConfiguration) Working Folder : Project.jsonのあるフォルダ

※:BuildConfigrationはVariablesでreleaseと作っておいてください(Visual Studioのテンプレートから作った場合は作られています)

f:id:kkamegawa:20160919141406p:plain

テストプロジェクトのNuGetパッケージを復元する

テストプロジェクトのNuGetパッケージ復元のCommand LineをAdd build stepで追加します。

Tool: "c:\Program Files\dotnet\dotnet.exe"
Arguments : restore Working Folder : テストプロジェクトのProject.jsonがあるフォルダ

テストの実行

テスト実行用のCommand LineをAdd build stepで追加します。

Tool: "c:\Program Files\dotnet\dotnet.exe"
Arguments : test -xml TestResult.xml Working Folder : テストプロジェクトのProject.jsonがあるフォルダ

Visual Studioでビルドする場合と異なり、プロジェクト単位でdotnet restoreを実行する必要があるので気を付けてください。

-xml にはテスト結果を出力するxmlファイルを指定します。テストプロジェクトごとに異なる名前にしてください。後で集計することができなくなります。

dotnetコマンドはフルパスで指定しなくても実行できますが、ビルド時に警告が出るので、フルパスを指定するほうが無難です。

テスト結果をVSTSにアップロード

f:id:kkamegawa:20160919120828p:plain

Add build stepで"Publish Tests Results"タスクを追加して、ビルド結果をVSTSにアップロードします。VSTEST以外にもXUnit,NUnit,JUnit(Javaなので.NET Coreには関係ないですが)などに対応しています。

f:id:kkamegawa:20160919142327p:plain

テスト結果をVSTSにアップロードすると、このようにテスト結果の品質を追跡することができます。

LnuxもしくはOS/Xでビルドする場合、出力するXMLファイル名の大文字小文字に気を付けてください。

コードカバレッジも取れるはず…Visual Studioでは取れていますが、VSTSでは集計されていません。これは少し調査します。

パッケージの出力

パッケージ出力用のCommand LineをAdd build stepで追加します。

f:id:kkamegawa:20160919120829p:plain

出力パッケージを作ります。具体的にはproject.jsonで定義されているpublishの動作が実行されます。

docs.microsoft.com

Tool: "c:\Program Files\dotnet\dotnet.exe"
Arguments : publish src/{プロジェクト名} --configuration $(BuildConfiguration) --output $(PublishOutput) --framework $(NETCoreVersion)

注意点として、publishコマンドはデフォルトでデバッグ版を出力しています。--configurationで明示的にrelease版(ここではvariablesで指定しています)を指定してください。Azureではデバッグ版実行できない(エラーになる)はずなのですが、なぜかデバッグ版をデプロイしてもApp Serviceで動いてしまってます。長い間気づきませんでした。

Framework Runtimeは組み込むか、システムインストールを使用するかはご自由に。今回はシステム組み込みのランタイムを使用する前提でやっています。

f:id:kkamegawa:20160919142328p:plain

bin\$(BuildConfiguration)\ にあるアプリケーションの実体をコピーするタスクです。このタスクは非.NET CoreのASP.NET前提のタスクのようで、フォルダ構成をそのままコピーしてくれません。

IIS(Azure App Service)にデプロイする場合、これで問題ないのですが、Linuxにデプロイするとこのタスクでは実行時に「\bin\$(BuildConfiguration)\netcoreapp1.0\モジュール名」が存在しないというエラーになります。

特別にタスクを作るか、project.jsonのpublishOptionsにbin/releaseを含めるしかないように思います。今回はproject.jsonに入れています。あと、各種jsonファイルも入っていない場合、Linux(たぶんOS/Xも)実行失敗するので、jsonファイルを忘れないようにpublishOptionsに入れましょう。

  "publishOptions": {
    "include": [
      "wwwroot",
      "Views",
      "Areas/**/Views",
      "appsettings.json",
      "project.json",
      "bin/release",
      "web.config"
    ]
  }

リリース作業用PowerShellスクリプト追加

f:id:kkamegawa:20160919120830p:plain

ここはApp ServiceにリリースするためのPowerShellスクリプトをリリース成果物としてコピーするタスクですビルド時にデプロイするなら不要です。

WebDeploy用zipファイル作成

f:id:kkamegawa:20160919120831p:plain

IIS(Azure App Service)にwebdeployでデプロイする場合、zipパッケージを作っておく必要があります。webdeployを使わない場合は不要です。

VSTSにリリース成果物を登録

f:id:kkamegawa:20160919120832p:plain

最後に成果物をVSTSにコピーします。特定のファイル共有にコピーするか、VSTSに保存します。ファイル共有はUNCでVSTSもしくはビルドエージェントからアクセスできる必要があります。

UNCで共有フォルダにコピーする場合、独自のビルドエージェントからになるでしょうね。

プログラマ的にWindows 10 Anniversary Updateのうれしいところ

10個あるかな、と思ったのですが、今のところ思いついたものをあげてみました。うーん、まだあるはずなんですが。とりあえず、つらつらと書いてみます。Inkとかは純粋にプログラマ向けとしてどうかなーと思って、あえて入れていません(ぉ)。

他にもお気に入りの機能があれば紹介してください。

Docker互換のコンテナ

言わずと知れたこれですね。Docker for Windowsを使えば現在でも使えます。

docs.docker.com

ただ、こちらはHyper-VでLinux仮想マシン(初期で2GB )が動くので、少しメモリがきつい。なによりもWindowsで動くコンテナであればWindowsネイティブの機能を使うことになります。

msdn.microsoft.com

コマンドはdockerコマンドで共通のようです。PowerShellコマンドレットも用意されるようですが、基本はdockerコマンドで、詳細な情報を見たいときはPowerShellという住み分けになるようです。

MAX_PATHが260バイトの制限から解き放たれる

実は今までもファイル名のprefixに\\?\とつけて、UnicodeでコンパイルしたWin32アプリケーションであれば、64KBまでのパスを使えることができました。しかし、ExplorerがWindows 95時代からのANSIモードで動いていたり、世の中MAX_PATHが260バイトという決め打ちで動いていたり、.NET FrameworkもWindows 95とかを引きずっていた都合上、最大パスは260バイトまで、となっていました。

Anniversary Update以降、グループポリシーでEnable NTFS long pathsを有効に設定すれば、Win32アプリケーションでも有効になります。もちろん、MAX_PATHが260と決め打ちしているような大多数(99.9999%くらい?)のアプリケーションに長いパスを与えると即死、もしくはバッファオーバーフロー起こすので、十分評価してからにしましょう。

betanews.com

Desktop ConverterでWin32/.NETアプリケーションの簡単展開

既存の.NETアプリケーションやWin32アプリケーションにUWPのガワだけかぶせて、ストアでより簡単に配信ができるようになるというDesktop Converterです。間違えないで欲しいのは、あくまでも「ストアに公開できるようになる」というだけで、「UWP化される(mobileやXBoxで動くようになる)わけではありません

ただし、何でもかんでもコンバートできるわけではなく、制限があります。特にVisual C++ランタイムと.NET Frameworkが限られるので、古いVCランタイムを使っているアプリケーションの場合、一度移行してから、ということもあるので、注意してください。

Convert your desktop application to a Universal Windows Platform (UWP) app

UACで特権昇格が必要なアプリや、他のアプリと連携する(AppDataに書き込む)ようなアプリがダメ、というのはややきついものの、大多数のアプリケーションでは問題無いでしょう。ただし、その前にインストーラーでインストールされるようなアプリケーションでなくてはなりませんが。

インストーラーがないようなアプリの場合、コンテナ使うしかないですかね。

ネットワークが高速化

ネットワークは門外漢ですが、Linuxなどではすでに対応している新しいRFCもしくはドラフトの規格に対応しているそうです。TFOとかは素人目に見ても頻繁にopen/closeするようなサーバにアクセスする場合の高速化が見込まれると思われます。

blogs.technet.microsoft.com

PowerShell (WMF 5.1)

WMF 5.1 リリース ノート (プレビュー)

Bashに持って行かれた感がありますが、Windows における自動化、スクリプトでの運用管理を行いたい場合はWMF(PowerShell)なのは変わりません。いろいろ聞かれましたが、Bashは(今のところ)Windows 10を開発者モードに変更しないと使用できません。つまり、Bashは管理者がシステム管理のために使うのではなく、あくまでも開発者向けのツールセットの一部となっています。

PowerShellはWindowsクライアントおよびサーバの管理、自動化のためのものです。

PowerShell 5.0 にあったバグや、高速化、PowerShell DSCをはじめとした機能強化が盛りだくさんです。

.NET Framework 4.6.2

先ほどWin32アプリケーション向けの長いファイル名を扱うようにする設定を紹介しましたが、.NETの場合はapplication manifestに指定することにより、プロセス単位で制御することが可能です。

<?xml version="1.0" encoding="utf-8" ?>  
 <configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" />
  </runtime>
</configuration>

.NET Coreおよび、.NET Framework 4.6.2がインストールされたWindows 10 Anniversary Update(1607)で有効だそうです。

blogs.msdn.microsoft.com

長いファイル名の他にもモニタごとのDPIを認識するようになったとか、新しい暗号化に対応したとか、着実な強化が行われています。

blogs.msdn.microsoft.com

Bash on Ubuntu on WindowsでツールセットがLinux共通に

//Build 2016での話題は間違いなくこれだったでしょうね。cygwinとかもまぁいいのですが、なんとなくもどかしさを感じていました。PowerShellのすべてがオブジェクトになるというのは.NETなどの相互運用で大変便利です。

しかし、他のプラットフォームの方に使ってもらおうとする場合、そのへんが足かせにもなっていました。移行のためにコマンドレットにエイリアスを登録されているものもある(lsやwgetとか)のですが、結局オプションが違うから使わないんですよね。

あと、長いファイル名の扱いも、UnicodeアプリであったとしてもWindowsだから260バイト固定とかになっているものも少なからずあり、困っていました。node.jsもしばらく困ったなぁ…。

しかしそんな時代もさようなら。パスさえ少し考慮すればUbuntuで動いているものがまぁ大体動くようです。もちろんまだ実装されていないシステムコールや実装されないであろうシステムコールもありますが、コマンドラインの開発用ツールセットは割りと動くようですね。

blogs.msdn.microsoft.com

詳細な仕組みなどは上記のブログで。もしも困る場合はGitHubにissueをたててみればいいようです。

github.com

UWPアプリのバックグラウンド実行サポート

通知ではなく、バックグラウンドで実行したいような場合よさそう?

blogs.windows.com

VSTSの新ビルドで単体テスト結果を確認する

ASP.NET MVC(.NET Framework 4.6)のプロジェクトをVisual Studio Team Servicesでビルドしたいとします。作成したデフォルトのビルド定義には単体テストを実行するタスクがあり、有効にしています。

f:id:kkamegawa:20160316220108p:plain

しかし、ビルドしても、このようにテスト結果が表示されません。もちろんローカルでは表示されます。これはどういうことでしょうか?

f:id:kkamegawa:20160316220110p:plain

原因はvstestに指定するターゲットフレームワークの指定がFramework4(.NET 4)になっているからじゃないかな、と思います。ビルドタスク内のTestのAdvanced Execution OptionsのOther Console Optionsに"/UseVsixExtensions:false /Framework:framework45"と指定してください。

f:id:kkamegawa:20160316220109p:plain

こんな感じ。/UseVsixExtensionsはVSIXの拡張機能を使用しない、という指定です。コンソールで実行するテストのときあっても意味がないので無効化しています。

f:id:kkamegawa:20160316220111p:plain

ビルド後、単体テスト結果やカバレッジ結果が正しく表示されるようになりました。この指定はRun Settings Fileに指定したテスト構成ファイルでもできるはずなのですが、リポジトリに追加するのも面倒なので、実行時引数に指定しています。

VSTest.Console.exe のコマンド ライン オプション

VSTSの新ビルドにゲートチェックインが追加

先日のVSTSの更新で新ビルドシステムでもやっとTFVCのゲートチェックインが復活しました。やってみましょう。

f:id:kkamegawa:20160226065549p:plain

ビルド定義のTriggersにGated Check-inがあるので、これを有効にします。フォルダ配下で特定の範囲にチェックインが行われた場合、対象にすることができます。

f:id:kkamegawa:20160226065545p:plain

ゲートチェックインが有効になると、ビルドを開始するとこのようにメッセージが出るようになります。以前と同じですね。

f:id:kkamegawa:20160226065548p:plain

ビルドが失敗するとチェックインが拒否されます。

f:id:kkamegawa:20160226065550p:plain

こんな風にビルド結果も失敗したと出てきます。余談ですが、ここ数日Test Resultsがアップロードできなくて、こんな風にテスト結果が可視化されず、すごく悩んでました…たぶんVSTS側の問題だったんでしょう。

f:id:kkamegawa:20160226065546p:plain

しかし、ビルド履歴はSucessのままです。これは直近のチェックインが成功したビルドステータスをもとに表示しているためです。

f:id:kkamegawa:20160226065547p:plain

チェックイン履歴を見ても、今日のチェックインは行われておりません。これでTFVCでも安心して実行できますね!