Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2311

TFS Build Service筆記

$
0
0

公司的專案版控由VSS換到TFS版已經很久了,自動組建(Build)專案的工作原本靠CruiseControl.NET搞定,一直沒研究如何改接TFS,但漸漸陷入危機,CCNET主機裝在Windows 2003,註定與.NET 4.5專案無緣,非升級不可。一不做二不休,索性棄守CCNET,另建TFS Build Service處理新專案。

第一次玩TFS Build Service,一路不斷踩到水坑跌進洞裡,耗費多時,終於Build第一個專案! 記錄斑斑血淚於後:

比較之下,安裝TFS Build Service反而是程序最單純的部分,細節可參考Franma的圖形化安裝手冊(連結為2012版,2013版在這裡),在此不多贅述,僅筆記我遇到的大小狀況及心得。

TFS Build Service裝好,下一步是要在Visual Studio的Team Explorer中建立組建定義(Build Definition),做法安裝手冊有介紹,一般小專案應該都能一舉成功。但不巧我試作的解決方案專案結構複雜,人生歷練豐富(.sln搬過家),Build Service的環境特殊,簡單任務頓成天堂路~

問題1:

設好組建定義,第一次建置時冒出The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk. 訊息。檢查TFS Build Service主機,有找到\MSBuild\Microsoft\VisualStudio\v11.0\,但其下沒有WebApplications目錄,猜想是TFS Build Service安裝的MSBuild版本不若Visual Studio安裝的版本齊全,未支援WebApplication型別。從已安裝VS的機器複製補足檔案是一種做法,但我決定在TFS Build Service上安裝Visual Studio 2013以求省事。

問題2:

裝好Visual Studio 2013,在MSBuild資料夾裡看到WebApplications目錄,心想這下OK了。沒想到繼續冒出The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets" was not found.錯誤!

定神一看,才發現安裝VS2013後,MSBuild一併升級,原本的v11.0目錄變成v12.0,而TFS 2010 Build Service仍傻傻去找v11.0撲了空。爬文沒找到強制Build Agent改用v12.0的做法,但組建定義有地方可以指定MSBuild參數,如下圖補上/p:VisualStudoVersion=12.0可以解決。猜想應該可以從Build Controller設定,但我沒找出方法,十方大德若有人知曉請再補充。

補充一點,組建定義預設在每次組建失敗會建立一個新任務進行追蹤,在實務上很有用,理論上程式碼得通過編譯才能簽入版控,編譯失敗意味著有人犯錯,就該追蹤到問題解決為止。但像是第一次嘗試TFS組建,過程難免會有些問題需要排除,此設定會產生一堆無意義任務(就還搞不定咩!有什麼好追蹤的?)及一波Mail通知轟炸,建議可先關閉,正常運作後再打開。(上圖的Create WorkItem on Failure)

問題3:

TFS Build Service所處的網段被禁止存取網際網路,故連不上NuGet主機,NuGet Package Restore功能宣告破功,Log冒出一堆找不到參照元件錯誤。最簡單的解決方法是將整個packages資料夾也簽入TFS,但缺點是未來每次新増或更新NuGet Package得一併簽入packages資料夾的異動;但這樣也有優點,Build Service不需要每次建置都重新用NuGet取檔,節省時間也節省網路傳輸,感覺更務實。packages資料簽入後,參照錯誤問題排除,另一個專案卻爆出錯誤:This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is D:\Works\1\APP\MyWeb\src\\.nuget\NuGet.targets.

比對發現出錯的是後期建立的新專案,csproj多了以下片段,應是NuGet升級後增加的檢查:

<TargetName="EnsureNuGetPackageBuildImports"BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing 
on this computer. Enable NuGet Package Restore to download them. 
 For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. 
The missing file is {0}.</ErrorText>
</PropertyGroup>
<ErrorCondition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')"
Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))"/>
</Target>

移除上述設定可避免問題,但既然是新版NuGet行為,後續再開新專案預期仍會有類似困擾,補上.nuget\NuGet.targets才是治本之道。將.nugets資料夾也簽入TFS,錯誤就消失了。關於packages與.nuget簽入TFS的注意事項,可參考前文:NuGet Packages資料夾該不該加入TFS版控?

問題4:

這回花最多時間的地方在這一段,原因是先前解決方案(.sln)曾搬過目錄,由Boo/Web/MyWeb.sln移到Boo/MyWeb.sln,而NuGet Packages目錄跟著.sln,因此部分專案csproj的參數<HintPath>仍指向Boo/Web/packages。Visual Studio有許多奇妙法則能找到替代DLL,例如:所參照其他專案帶來的同Package DLL其他軟體用過的其他版本… packages路徑不對的問題一直被掩蓋,直到改用MSBuild才一次爆出來,必須全部修正才能繼續~

要排除前述packages路徑錯誤,可將解決方案由本機刪除再重新由TFS取回,或另找一台電腦由TFS取得原始碼,重新用Visual Studio編譯就可讓錯誤現形。這也是我推薦在TFS Build Service主機安裝Visual Studio的理由之一,面對這類問題時特別能展現優勢。Build Agent每次執行會由TFS抓取最新版程式碼寫入Build Service主機的工作目錄,用VS開啟工作目錄下的.sln檔,會與MSBuild面對環境一致,較容易重現錯誤狀況。Build Agent的工作目錄可以查這裡:

就這樣,使用Visual Studio開啟D:\Works下的sln檔案,手動組置重現錯鋘再一一排除,總算闖關成功。

另外還有幾個TypeScript編譯失敗的小問題,也在更新VS2013 Update 4、TypeScript 1.4 for VS後陸續排除,在Build Service安裝VS2013確實讓射茶包難度降低許多。

心得5:

常見的專案檔案架構會類似這樣:sln放在/src下,packages目錄也在/src下,src下再分成一個專案一個資料夾。/src可能有多個sln,A.sln包含專案A1、A2、Share,B.sln包含B1、B2、B3、Share,放在同一個src下可共用Share專案及packages。在組建定義設定Source時,若設定Source Control Folder為/src,則每次組建時Build Service將下載src下的所有資料夾,把packages、A1、A2、Share、B1、B2、B3全部都抓回來。當我們只想編譯A.sln,多抓B1、B2、B3只是浪費頻寬,還拖慢組建時間。此時可善用組建定義Source Settings可分別列舉應下載(Active)及不要下載(Cloaked)項目的特性,組合出建置所需的最少檔案,提升效率。

心得6:

第一次使用Build Service編譯MVC後楞了一下,輸出資料夾只有bin下的一堆DLL檔案,Scripts、Contents、Views都不見了。後來才發現可部署的網站內容另外放在輸出資料夾的_PublishedWebsites子目錄下,裡面的內容相當於Visual Studio發佈網站的產出結果。

心得7:

Build Service預設提供了幾種建置流程範本(Build Process Template),決定建置流程有幾個步驟,如何抓Source Code、怎麼執行測試… 等等,還可定義控制參數,顯示於下方供使用者調整,這些細節都定義在Windows Workflow Foundation(WWF)規格的XAML檔案,可用Visual Studio編譯修改,為專案量身打造專屬的建置流程,微軟很貼心地在UI 附上教學。呃… 這下連說「我不會」的機會都沒了,夠狠!(淚)

不過,如果只是要在建置時加入執行外部程式、複製檔案等步驟,可考慮在csproj加入額外步驟,用Condition="'$(BuildingInsideVisualStudio)' == ''" 的技巧,設定成MSBuild建置時才觸發(使用Visual Studio建置時不執行),會比客製建置流程範本簡單。

<TargetName="Copy Files"Condition="'$(BuildingInsideVisualStudio)' == ''"
AfterTargets="Build">
<Exec
Command="xcopy &quot;$(SolutionDir)\Web\Boo&quot; &quot;$(DeployPath)\&quot;"
Condition="'$(DeployPath)' != ''">
</Exec>
</Target>

【延伸閱讀】


Viewing all articles
Browse latest Browse all 2311

Trending Articles