使用MSBuild实现完整daily build流程 .
一、MSBuild
在微軟軟件開發中,每日構建是最重要的過程之一,被稱為微軟產品開發的“心跳”。簡單來看,每天構建系統將整個產品解決方案完整構建一遍,生成的目標文件和安裝文件被放置在一個共享位置。接著,安裝文件被自動部署到release server上,隨后可以自動運行BVT(build verification test),并將所有結果寄送每個team member的信箱。
微軟有一套完善的內部系統來完成整個自動化流程,以及流程管理、reporting等工作,而如果我們沒有這套系統,也想實現完整的daily build流程,該怎么做呢?
在VS.NET2003時代,IDE可以控制整個方案的構建,但是所有的構建邏輯被IDE控制,對于開發人員來說,整個構建流程就像一個黑箱,很難修改和管理。當然可以使用PreBuildEvent和PostBuildEvent來控制,但是這些event都寫在csproj/vbproj文件中,不便于修改,不適于擴展。而且使用IDE來做每日構建的話,要求構建系統本身裝有VS.NET,這會帶來額外的成本。另一種辦法是使用NAnt,通過XML配置文件,來管理構建流程,這會使得整個流程易于修改,可擴展,并且不要求構建系統安裝IDE,只需要有framework即可。問題是使用NAnt必須額外寫一堆復雜的XML配置文件,足以讓很多developer看了頭疼。
VS.NET2005中引入了一套全新的構建系統:MSBuild。簡單來講,MSBuild可以直接讀取csproj文件,控制csc/vbc等編譯器,生成整個方案。實際上,VS2005的IDE自身就是調用MSBuild來完成編譯的,這與VS2003有很大的不同。并且由于VS2005的csproj文件服從MSBuild的配置schema,因此我們可以直接使用csproj,稍稍修改一下,就能組織起完整的構建流程了。
二、示例項目的組織
來看一個完整的例子。
我們將建立一個簡單的Hello方案,包括一個HelloService(Windows NT Service),一個HelloSite(ASP.NET Web Site),和一個共用組件(class library)。如圖所示。
build目錄中,將用來存放構建使用的配置文件。private目錄中存放解決方案本身。public目錄中存放用來完成構建所使用的編譯器,例如WiX(用來生成安裝包)。先在private目錄中新建一個空解決方案,可以命名為“HelloSolution”。然后依次新建SharedComponents、HelloService和HelloSite項目,并建立引用關系:HelloService引用了SharedComponents。最后的文件組織如圖所示。
刪除Default.aspx第一行的引用,刪除Default.aspx.cs,添加一個App_Code目錄,在App_Code中新建一個Hello.cs文件,保持初始代碼不用修改。
在IDE中編譯整個Solution,沒問題。可以關閉IDE了。
打開SDK的控制臺,輸入兩條命令:
CD /d C:\Hello\private\HelloSolution
msbuild
很快就能看到構建結果了:
但這并不完全是我想要的。例如我想將所有的項目輸出都放在C:\Hello\target目錄;我想讓HelloSite有一個自己的主目錄;我想自動生成MSI安裝包,并且也放在target目錄下。
三、修改構建流程
首先我們將SharedComponent.csproj和HelloService.csproj文件copy至build目錄下,并將擴展名改名為proj。用記事本打開SharedComponents.proj,看到如下內容。
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{FF79BA82-D6CE-4E89-9AFA-C5EF83A62C2D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SharedComponents</RootNamespace>
<AssemblyName>SharedComponents</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
觀察可以發現,紅色的部分是給VS IDE用的,與MSBuild無關,因此可以刪除。最后幾行中的BeforeBuild和AfterBuild暫時沒用,也可以刪除。
從第一行開始看:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
首先看到一個屬性組,里面的每一條屬性都可以理解成一個環境變量。屬性組第一行是說,如果環境變量“Configuration”為空,那么設置屬性 “Configuration”為“Debug”。同樣,第二行是說,如果環境變量“Platform”為空,那么設置屬性“Platform”為“AnyCPU”。這里我不想使用“AnyCPU”,于是將其改成“x86”。
<OutputType>Library</OutputType>
<AssemblyName>SharedComponents</AssemblyName>
</PropertyGroup>
OutputType指定了輸出類型為類庫。AssemblyName指定輸出文件名,改為Hello.SharedComponents。
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
在這一段中,如果Configuration屬性并上“|” 并上Platform屬性,等于“Debug|AnyCPU”的話,那么定義一個屬性組。換句話說,就是為debug、AnyCPU的組合配置一段編譯器使用的屬性。將第一行的Condition改成“'$(Configuration)' == 'Debug'”(假設我們并不需要在其它platform上進行編譯)。以同樣的方式修改Release的PropertyGroup。
接著是一個ItemGroup,指定了這個項目引用的組件。
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
然后又是一個ItemGroup,指定了參加編譯的源代碼文件。
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
再接下來,引入了一個targets文件:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
$(MSBuildBinPath)是一個環境變量,或者是之前定義的屬性。Microsoft.CSharp.targets位于C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727目錄下,用記事本打開,查找“Name="CoreCompile"”,可以找到真正控制編譯器運行的核心配置。其中$(xxx)表示一個之前定義的屬性,@(xxx)表示之前定義的ItemGroup。可以發現,先前在SharedComponents.proj中定義的屬性和Item,最后實際上都是給這一段CoreCompile用的。由這個target來控制csc編譯器執行最終的編譯。
在第一個PropertyGroup中添加一個屬性:SrcDir,其值為“C:\Hello\private\HelloSolution\Shared\SharedComponents”,表示此項目源代碼文件的位置。相應修改Compile項目組的Include屬性為:
<ItemGroup>
<Compile Include="$(SrcDir)\Class1.cs" />
<Compile Include="$(SrcDir)\Properties\AssemblyInfo.cs" />
</ItemGroup>
回到HelloService.proj文件,依上所述,進行類似的修改。
注意ProjectReference這個ItemGroup,這一段將會被用來解析依賴關系,需要對Include屬性做些修改。
最后形成的兩個文件為:
SharedComponents.proj
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SrcDir>C:\Hello\private\HelloSolution\Shared\SharedComponents</SrcDir>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>Library</OutputType>
<AssemblyName>Hello.SharedComponents</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(SrcDir)\Class1.cs" />
<Compile Include="$(SrcDir)\Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
HelloService.proj
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SrcDir>C:\Hello\private\HelloSolution\Services\HelloService</SrcDir>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<OutputType>WinExe</OutputType>
<AssemblyName>Hello.HelloService</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(SrcDir)\Service1.cs" />
<Compile Include="$(SrcDir)\Service1.Designer.cs" />
<Compile Include="$(SrcDir)\Program.cs" />
<Compile Include="$(SrcDir)\Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="SharedComponents.proj" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
最后參考上面的兩個文件和MSDN上MSBuild的資料,新建HelloSite.proj文件:
<Project DefaultTargets="PrecompileWeb" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VirtualPath>/Hello</VirtualPath>
<PhysicalPath>C:\Hello\private\HelloSolution\Web\HelloSite\</PhysicalPath>
<TargetPath>Web</TargetPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugCompile>true</DebugCompile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugCompile>false</DebugCompile>
</PropertyGroup>
<Target Name="PrecompileWeb">
<AspNetCompiler
VirtualPath="$(VirtualPath)"
PhysicalPath="$(PhysicalPath)"
TargetPath="$(TargetPath)"
Force="true"
Debug="$(DebugCompile)"
Updateable="true" />
</Target>
</Project>
轉到控制臺,在C:\Hello\build目錄下執行msbuild HelloService.proj,觀察執行結果,發現MSBuild成功解析出HelloService引用了SharedComponent組件,并首先編譯了被引用的組件,然后才編譯目標組件。如圖所示:
再執行msbuild HelloSite.proj,構建也成功了。
四、進一步完善
在這部分中,我們使用環境變量來替代長路徑,把項目輸出放到指定位置,將公用的屬性配置放在一個引用文件里。由于在MSBuild系統中,系統環境變量和屬性是通用的,因此這些目標并不難完成。
在C:\Hello\build目錄中新建一個include.cmd文件。
@echo off
@set public=%inetroot%\public
@set private=%inetroot%\private
@set target=%inetroot%\target
@set product=%private%\HelloSolution
@set setup=%product%\Setup
@set wix=%public%\WiX
@set Platform=%PROCESSOR_ARCHITECTURE%
call "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\sdkvars.bat"
在include.cmd中,我們指定了所需的環境變量,并調用了SDK的環境變量設置命令。
新建include.property文件,內容為:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<BaseIntermediateOutputPath>$(target)\</BaseIntermediateOutputPath>
<OutputPath>$(target)\$(Platform)\$(Configuration)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DebugCompile>true</DebugCompile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DebugCompile>false</DebugCompile>
</PropertyGroup>
</Project>
修改SharedComponents.proj:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="include.property" />
<PropertyGroup>
<SrcDir>$(product)\Shared\SharedComponents</SrcDir>
<OutputType>Library</OutputType>
<AssemblyName>Hello.SharedComponents</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(SrcDir)\Class1.cs" />
<Compile Include="$(SrcDir)\Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
修改HelloService.proj:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="include.property" />
<PropertyGroup>
<SrcDir>$(product)\Services\HelloService</SrcDir>
<OutputType>WinExe</OutputType>
<AssemblyName>Hello.HelloService</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(SrcDir)\Service1.cs" />
<Compile Include="$(SrcDir)\Service1.Designer.cs" />
<Compile Include="$(SrcDir)\Program.cs" />
<Compile Include="$(SrcDir)\Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="SharedComponents.proj" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
修改HelloSite.proj:
<Project DefaultTargets="PrecompileWeb" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="include.property" />
<PropertyGroup>
<VirtualPath>/Hello</VirtualPath>
<PhysicalPath>C:\Hello\private\HelloSolution\Web\HelloSite\</PhysicalPath>
<TargetPath>$( OutputPath)\Web</TargetPath>
</PropertyGroup>
<Target Name="PrecompileWeb">
<AspNetCompiler
VirtualPath="$(VirtualPath)"
PhysicalPath="$(PhysicalPath)"
TargetPath="$(TargetPath)"
Force="true"
Debug="$(DebugCompile)"
Updateable="true" />
</Target>
</Project>
在C:\Hello目錄下新建一個build.proj文件:
<Project DefaultTargets="Compile"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<MSBuild Projects="build\HelloService.proj" />
<MSBuild Projects="build\HelloSite.proj" />
</Target>
</Project>
在C:\Hello目錄中新建一個build.cmd文件:
@echo off
@set Configuration=Debug
msbuild build.proj /t:Build
@set Configuration=Release
msbuild build.proj /t:Build
在桌面上新建一個快捷方式,命名為“Hello”,Target設置為:
C:\WINDOWS\system32\cmd.exe /K set inetroot=C:\Hello&"C:\Hello\build\Include.cmd"
Start in設置為C:\Hello,Option中選上“QuickEdit mode”。
退出命令行,雙擊桌面上的Hello快捷方式,運行build,大約五秒鐘后,整個方案就被成功構建了,所有的項目輸出都在C:\Hello\target目錄下。
五、Installer
VS.NET中可以新建一個安裝項目,用來編譯生成安裝包,但是這種生成方式類似用IDE來build項目一樣,不適于擴展,而且很難通過命令行來執行編譯。
替代的方法是使用WiX toolset。WiX是Windows Installer XML的縮寫,是微軟的第一個開源項目,可以在SourceForge上下載。
在C:\Hello\private\HelloSolution目錄下新建一個Setup目錄。新建一個HelloService.wxs文件:
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="YOURGUID" Language="1033" Manufacturer="Hello Corporation" Name="HelloService" Version="1.0.0.0">
<Package Id="YOURGUID"
Description='Hello Service Windows Installer package'
Manufacturer='Hello Corporation' InstallerVersion='200' Compressed='yes' />
<Condition Message="You need to be an administrator to install this product.">
Privileged
</Condition>
<Condition Message='This product can only be installed on Windows Server 2003'>
VersionNT = 502
</Condition>
<Media Id="1" Cabinet='product.cab' EmbedCab='yes' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='Hello' Name='Hello'>
<Directory Id='INSTALLDIR' Name='Service'>
<Component Id='MainExecutable' Guid=' YOURGUID '>
<File Id='HelloSvc' Name='Svc.exe' LongName='Hello.HelloService.exe' DiskId='1' src='$(env.target)\$(env.Platform)\$(env.Configuration)\Hello.HelloService.exe' Vital='yes' ProcessorArchitecture="x86" />
<ServiceInstall Id='ServiceInstall' DisplayName='Hello Service' Name='HelloService' ErrorControl='normal' Start='demand' Type='ownProcess' Vital='yes' Description="Hello service" />
<ServiceControl Id="ServiceUninstall" Name="HelloService" Stop="both" Remove="uninstall" Wait="yes" />
</Component>
<Component Id="ReferencedLib" Guid='YOURGUID'>
<File Id='SharedComponents' Name='shared.dll' LongName='Hello.SharedComponents.dll' DiskId='1' src='$(env.target)\$(env.Platform)\$(env.Configuration)\Hello.SharedComponents.dll' Vital='yes' ProcessorArchitecture="x86" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='ReferencedLib' />
</Feature>
</Product>
</Wix>
其中的YOURGUID需要用一個自己生成的guid來代替,可以用C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\guidgen.exe來生成guid。
新建HelloSite.wxs文件:
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="YOURGUID" Language="1033" Manufacturer="Hello Corporation" Name="HelloSite" Version="1.0.0.0">
<Package Id="YOURGUID"
Description='Hello Site Windows Installer package'
Manufacturer='Hello Corporation' InstallerVersion='200' Compressed='yes' />
<Condition Message="You need to be an administrator to install this product.">
Privileged
</Condition>
<Condition Message='This product can only be installed on Windows Server 2003'>
VersionNT = 502
</Condition>
<Media Id="1" Cabinet='product.cab' EmbedCab='yes' />
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='PFiles'>
<Directory Id='Hello' Name='Hello'>
<Directory Id='INSTALLDIR' Name='Site'>
<Component Id='Page' Guid='YOURGUID'>
<File Id='Default_aspx' Name='Default.asp' LongName='Default.aspx' DiskId='1' src='$(env.target)\$(env.Platform)\$(env.Configuration)\Web\Default.aspx' Vital='yes' />
</Component>
<Directory Id='binDir' Name='bin'>
<Component Id="ReferencedLib" Guid='YOURGUID'>
<File Id='AppCode' Name='App_Code.dll' LongName='App_Code.dll' DiskId='1' src='$(env.target)\$(env.Platform)\$(env.Configuration)\Web\bin\App_Code.dll' Vital='yes' ProcessorArchitecture="x86" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
<Component Id='SiteInstall' Guid='YOURGUID'>
<WebSite Id='DefaultWebSite' Description='Default Web Site' Directory='INSTALLDIR' DirProperties='webSiteProp'>
<WebAddress Id='AllUnassigned' Port='80' />
<WebApplication Id='HelloSite' Name='HelloSite' />
</WebSite>
</Component>
</Directory>
<Feature Id='Complete' Level='1'>
<ComponentRef Id='Page' />
<ComponentRef Id='ReferencedLib' />
<ComponentRef Id='SiteInstall' />
</Feature>
<WebDirProperties Id='webSiteProp' Script='yes' />
<CustomAction Id='ToggleASPNETVersion' ExeCommand='aspnet_regiis -s W3SVC/1/Root/' />
</Product>
</Wix>
注意HelloSite將在把Site程序安裝在WebSite下,因此不要在你的關鍵機器上安裝這個示例,并且安裝HelloSite前要備份你的IIS設置。
修改build.cmd文件:
@echo off
@set Configuration=Debug
msbuild build.proj /t:Build
if not exist "%target%\%Platform%\%Configuration%\Setup" (mkdir "%target%\%Platform%\%Configuration%\Setup") ELSE (del "%target%\%Platform%\%Configuration%\Setup\*.*" /q)
%wix%\candle %setup%\HelloService.wxs -out "%target%\%Platform%\%Configuration%\Setup\\"
%wix%\light "%target%\%Platform%\%Configuration%\Setup\HelloService.wixobj" /out "%target%\%Platform%\%Configuration%\Setup\HelloService.msi"
%wix%\candle %setup%\HelloSite.wxs -out "%target%\%Platform%\%Configuration%\Setup\\"
%wix%\light "%target%\%Platform%\%Configuration%\Setup\HelloSite.wixobj" "%wix%\ca\sca.wixlib" /out "%target%\%Platform%\%Configuration%\Setup\HelloSite.msi"
@set Configuration=Release
msbuild build.proj /t:Build
if not exist "%target%\%Platform%\%Configuration%\Setup" (mkdir "%target%\%Platform%\%Configuration%\Setup") ELSE (del "%target%\%Platform%\%Configuration%\Setup\*.*" /q)
%wix%\candle %setup%\HelloService.wxs -out "%target%\%Platform%\%Configuration%\Setup\\"
%wix%\light "%target%\%Platform%\%Configuration%\Setup\HelloService.wixobj" /out "%target%\%Platform%\%Configuration%\Setup\HelloService.msi"
%wix%\candle %setup%\HelloSite.wxs -out "%target%\%Platform%\%Configuration%\Setup\\"
%wix%\light "%target%\%Platform%\%Configuration%\Setup\HelloSite.wixobj" "%wix%\ca\sca.wixlib" /out "%target%\%Platform%\%Configuration%\Setup\HelloSite.msi"
運行build,構建完成后,發現target目錄中,MSI installer也被生成了。接下去運行
msiexec /i %target%\%Platform%\%Configuration%\Setup\HelloService.msi
C:\Program Files\Hello\Service目錄中出現了安裝好的文件。打開services.msc,找到“Hello Service”,試著運行一下。
運行msiexec /x %target%\%Platform%\%Configuration%\Setup\HelloService.msi卸載。
運行msiexec /i %target%\%Platform%\%Configuration%\Setup\HelloSite.msi安裝Web程序。
運行msiexec /x %target%\%Platform%\%Configuration%\Setup\HelloSite.msi卸載。
六、自動化
最后一個任務就是實現自動化,每日定時構建。
在C:\Hello目錄中新建一個DailyBuild.bat文件:
@echo off
@set inetroot=C:\Hello
call C:\Hello\build\Include.cmd
call C:\Hello\build.cmd
在Services.msc中enable “Task Scheduler”服務。在控制面板的“Scheduled Tasks”中,新建一個任務:Build Hello,指定其每天03:00AM運行C:\DailyBuild.bat。
右鍵點擊這個task,選擇運行,可以先看一下結果。
就這樣,daily build的任務完全實現自動化了。
七、擴展
在示例方案中,由于MSI安裝包都已經自動生成了,接下去能做的就更多了,例如實現自動部署,自動測試(BVT),自動report結果,等等。這些工作需要與tester合作,本文不再展開。
自動化流程是保持項目良好運作的關鍵,在微軟公司,這一流程受到高度的重視,通常由developer manager直接負責。如果哪天出現了build break,那么developer在開始一天的coding之前,必須先找到昨天的build哪里出現了問題,先去修復,重新build,直到build成功為止,沒有例外。
轉自:http://blog.csdn.net/dz45693/article/details/6752653
轉載于:https://www.cnblogs.com/xgcblog/archive/2011/09/17/2179507.html
總結
以上是生活随笔為你收集整理的使用MSBuild实现完整daily build流程 .的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VMware View 5.0 Read
- 下一篇: Mylyn 2.0,第 2 部分: 自动