Nant daily build實踐

轉載自:http://blog.csdn.net/ljianl/archive/2007/04/27/1587067.aspx

 折騰了一個周,基於Nant的VS.NET項目每日構建終於成功了,在網上實際上有很多這樣的例子,但所集成的解決方案都比較簡單,我現在做的解決方案,有4個類庫項目和2個web項目,使用網上的資料時,編譯過程都不能成功,最後翻了不少資料,問了不少人才成功,其中主要過程參考了http://bitarray.co.uk/marc/這個博客,我的文章大部分內容就算是翻譯吧,寫出來希望對大家有用處,同時感謝給過幫助的朋友,包括coolbug的文章

       asp.net下開發產品的部署,不同於aspinterdev開發目錄和站點發布目錄相同的特點,在asp.net下,開發目錄實際上存在於VSS中,必須建立對應的發佈目錄,將編譯過的文件放到其中,建立應用程序的虛擬目錄才能完成asp.net的發佈,如果使用手動方式完成這一過程,則在項目多、或者迭代式開發的多次小規模發佈情況下,人工工作量大,且不易管理,本文的.net每日構建過程,可以自動的完成這一過程,簡化管理過程。
一、           系統需求
Win2000 以上操作系統   .NET 框架1.0以上運行平臺
二、           相關工具及下載地址
1.     Nant      開源工具,完成.net代碼自動編譯及其它工具的調用(必選)
2.     NantContrib 開源工具,Nant的擴展組件,實現NantVSS中獲取文件功能(必選)
3.     Visual Source Safe 源代碼管理工具,VSS6.0C以上版本(必選)
三.相關軟件安裝
1.   安裝VSS
       在指定服務器上安裝VSS6.0C以上版本
2.   安裝NANT和NantContrib
在網上下載最新版NANTNantContrib壓縮包
解壓Nant,複製其中bin目錄到安裝地點,如d:/DailyBuildTools/Nant/bin
解壓NantContrib,複製其中bin中所有內容到Nantbin目錄
注:如果NantNantContrib版本不兼容,需要重新編譯Nant,可下載源代碼後查看相關文檔
四.建立.Net項目,並簽入到VSS中指定位置,分配相應帳號(除相關開發和管理人員外,可爲Nant分配專用帳號)
五.定義項目發佈所包含的過程
Nant工具功能強大,配合nant、ndoc、fxcop等工具,可以完成代碼編譯,站點發布,文檔生成、代碼測試等功能,並可反向在VSS中加入基線。
一個比較通用的發佈過程如下:
5.1 定義發佈環境,如站點發布目錄,源代碼存放目錄、文檔存放目錄、發佈版本分發包存放目錄等
5.2 項目組人員編寫Nant所需要的運行文件default.build,並根據環境定義其中的相關變量,並提交到服務器
5.3服務器的計劃任務等自動過程每天定時運行Nant
5.4 Nant清除上一版本發佈時存放的文檔
5.5 Nant從VSS中獲取新的源代碼
5.6 Nant編譯從VSS中獲取的源代碼,並將生成的dll文件存放到指定目錄
5.8 生成測試報告
5.9 生成項目文檔(需要源代碼中加入充分的註釋)
5.10 如果包含web項目,Nant刪除不必要的如*.cs等文件後,將發佈需要的*.aspx、*.resx、*.js等文件按原有目錄結構複製到指定目錄
5.11 向VSS中加入基線定義(需要寫權限)
5.12 生成項目zip分發包,並用指定格式定義分發包文件名,存到指定目錄
5.13 發佈項目到指定目錄,如web站點將發佈到指定虛擬目錄,也可由Nant來完成虛擬目錄的建立過程
六.編寫Nant運行所需要的運行文件default.build
此文件要求在同一目錄下有且僅有一個存在,所以爲統一管理,所有項目可以統一使用一個default.build文件
該文件中將包含所有相關項目的vss帳戶信息,需要保證其安全
將些文件放在獨立的目錄中以便於管理
七.Default.build的編寫說明
根據上面描述的通用項目發佈過程,一個基於Nant的項目發佈過程主要爲以下幾步:
1 清除舊版本
2 獲取新版代碼
3 編譯
4 測試和文檔生成
5 發佈
因爲Nant在同一目錄下僅可有一個default.build的限制,可將每個項目的發佈過程定義爲4個xml文件,如對集團黃頁系統
TYS.Master.xml      build主文件,定義各種環境變量
TYS.PreBuild.xml    項目預處理過程定義文件,完成舊的文件的清除工作
TYS.Build.xml           主要構建過程定義文件,完成VSS中獲取,編譯、生成壓縮包的過程,並測試、生成文檔的過程
TYS.Deploy.xml      項目發佈到最終位置的過程定義文件
對於複雜的多層的項目,build文檔的編寫比較複雜,可以參考Nant和NantContrib的相關文檔,針對不同類型的項目,xxx.Build.xml文件的編寫可以使用不同方法,對於簡單項目,可以使用Nant的solution任務、對於複雜的項目,可以使用NantContrib的slingshot任務自動成生,不過可能需要做稍微的改動,
在合理的定義變量的條件下,上面4個文件中的XXX.PreBuild.xml、XXX.Build.xml、XXX.Deploy.xml實際上都是可以重用的,也就是說,每次項目發佈,項目組人員只需要提交XXX.Master.xml
八.Default.build的編寫過程
下面以集團黃頁系統TYS的default.build編寫爲例講述具體過程,先假定項目發佈服務器Nant配置完成,並存在以下結構的目錄設置
1)       項目所在vss目錄:vss.directory = d:/VSS/TYS
2)       項目構建工作和存放文件根目錄:core.basedir = d:/Daily_Build_Folder
3)       項目虛擬目錄位置:core.publish = d:/inetpub/wwwroot/tys
4)       所有項目源代碼存放目錄:Core.build = Core.basedir/source
5)       項目zip分發包存放目錄core.distribution = core.basedir/distribution
6)       項目日誌存放目錄core.logs = core.basedir/logs
7)       項目文檔存放目錄core.documentation = core.basedir/docs
1編寫XXX.Master.xml
這個文件實際上是通用的,對所有項目基本相同
3 編寫TYS.Build.xml文件,TYS.Build.xml文件根據項目複雜程度不同而不同,下面是一個只有一層,且爲web層的例子
<?xml version="1.0" encoding="GB2312"?>
<project name="TYS.Deploy" default="go">
    
<target name="go" depends="propertycheck,unzip,copyrequiredfiles"/>
    
<!--檢查必須的參數是否設置-->
    
<target name="propertycheck" >
        
<ifnot propertyexists="build.number">
            
<fail message="build.number 屬性沒有設置,不能進行部署" />
        
</ifnot>
        
<ifnot propertyexists="target.directory">
            
<fail message="target.directory 目錄沒有設置,不能進行文件複製" />
        
</ifnot>        
    
</target>
    
<target name="unzip">
        
<unzip 
        
zipfile="${build.publish}${project.name}--build-${build.number}.zip" 
        todir
="${target.directory}" />
    
</target>

    
<target name="copyrequirefiles">
        
<mkdir dir="${target.directory}webctrl_client" failonerror="false" />
        
<mkdir dir="${target.directory}aspnet_client" failonerror="false" />        
        
<!--複製web assets-->
        
<copy  todir="${target.directory}webctrl_client">
            
<fileset basedir="${core.publish}webctrl_client" >
                
<includes name="**"/>
            
</fileset>
        
</copy>
        
<copy  todir="${target.directory}aspnet_client">
            
<fileset basedir="${core.publish}aspnet_client" >
                
<includes name="**"/>
            
</fileset>
        
</copy>        
    
</target>    
</project>

本例中,並沒有給出生成文檔、日誌等功能的build代碼,實際上這個過程應該寫在TYS.Build.xml中,具體運用中,項目成員可根據需要參照相關文檔添加
三.自動運行過程
編寫全局使用的default.build,存放到buildconfig,在其中調用TYS.Master.xml,內容如下:
<?xml version="1.0" encoding="gb2312"?>
<project name="DNMCCIT" default="go">
       <target name="go" depends="DNMCCIT.TYS"/>
       <target name="DNMCCIT.TYS">
              <nant buildfile="TYS.Master.xml" target="go" inheritall="true"/>
       </target>
</project>
編寫批處理程序,內容可以簡單的只有一行
Nant,然後存放到d:/buildconfig下的makefile.bat中
在計劃任務中增加自動運行計劃,按自定計劃運行makefile.bat
四.其它解決方案
支持.net平臺、VSS做源代碼管理的每日構建,除了本文提到的Nant之外,還有微軟公司的BuildIt和MsBuild兩種工具,BuildIt工具因爲擴展功能不強,使用較少,MSBuild的開發借鑑了Nant的思想,很多方面使用方法和Nant類似,並且也使用xml格式的build定義文件,並且可以根據VS.NET的解決方案sln文件完全自動進行build,網上資料也較爲豐富,但MSBuild現在階段爲beta產品,僅在Visual Studio2005中提供,且需要.net framework2.0的支持,.net1.1下的產品只有有限有人員可以得到,待MSBuild正式發佈後,將會成爲另一有力工具
 
五.用於管理方便的部分自動發佈方式
上面講述的方法,有一個比較大的缺點,就是對於不熟悉nant的人來說,編寫build文件有一定難度,實際上如果僅從服務器管理方便的角度,完全可以使用一種比較簡便的方法,描述如下:
a)       每個具體的開發項目,在其VSS中建立BUILD項目,如對黃頁系統爲
$DNMCCIT.TYS.BUILD
b)       由開發人員,不定期從開發環境,將編譯好的build文件,以zip壓縮包的方式存放到$DNMCCIT.TYS.BUILD中
c)       修改服務器的nant編譯定義文件TYS.DeployZip.xml,過程僅爲從VSS中取得DNMCCIT.TYS.BUILD.zip,並在服務器上解壓並釋放到指定的目的目錄
此時的default.build將只調用TYS.DeployZip.xml即可,代碼如下:
Default.build
<?xml version="1.0" encoding="gb2312"?>
<project name="DNMCCIT" default="go">
       <target name="go" depends="DNMCCIT.TYS"/>
       <target name="DNMCCIT.TYS">
              <nant buildfile="TYS.DeployZip.xml" target="go" inheritall="true"/>
       </target>
</project>
TYS.DeployZip.xml
<?xml version="1.0" encoding="GB2312"?>
<project name="TYS.Deploy" default="go">
       <property name="core.basedir" value="d:/Daily_Build_Folder/"/>
       <property name="core.publish" value="D:/inetpub/wwwroot/TYS/"/>
       <property name="core.build" value="Build/"/>
       <!--項目相關信息-->
       <property name="project.manager" value=""/>
       <property name="project.developer" value=""/>
       <property name="project.name" value="DNMCCIT.TYS"/>
       <!--Build位置信息-->
       <property name="build.directory" value="${core.basedir}${core.build}${project.name}/"/>
       <!--VSS信息-->
       <property name="vss.username" value="aaaa"/>
       <property name="vss.password" value=""/>
       <property name="vss.dbpath" value="//t-net1/vss/8002TYS/srcsafe.ini"/>
       <property name="vss.path" value="$/DNMCCIT.TYS.BUILD/"/>
       <property name="vss.directory" value="D:/inetpub/wwwroot/TYS/"/>
       <target name="go" depends="clean,getzip,unzip"/>
       <target name="clean" description="Remove all files">
              <delete failοnerrοr="false">
                     <fileset>
                            <include name="${core.publish}**" />
                            <include name="${build.directory}" />
                     </fileset>
              </delete>
       </target>
       <!--VSS中取得源代碼-->
       <target name="getzip">
              <vssget
                     user="${vss.username}"
                     password="${vss.password}"
                     localpath="${build.directory}"
                     recursive="true"
                     replace="true"
                     dbpath="${vss.dbpath}"
                     path="${vss.path}"
                     />
       </target>     
       <target name="unzip">
              <unzip
              zipfile="${build.directory}${project.name}.BUILD.zip"
              todir="${core.publish}" />
       </target>
 
       <target name="copyrequirefiles">
              <mkdir dir="${target.directory}webctrl_client" failοnerrοr="false" />
              <mkdir dir="${target.directory}aspnet_client" failοnerrοr="false" />         
              <!--複製web assets-->
              <copy todir="${target.directory}webctrl_client">
                     <fileset basedir="${core.publish}/webctrl_client/" >
                            <includes name="**"/>
                     </fileset>
              </copy>
              <copy todir="${target.directory}aspnet_client">
                     <fileset basedir="${core.publish}/aspnet_client/" >
                            <includes name="**"/>
                     </fileset>
              </copy>       
       </target>     
</project> 
<?xml version="1.0" encoding="GB2312"?>
<project name="TYS.Build" default="go">
    
<target name="go" depends="compile,distribute"/>
    
<!--編譯解決方案-->
    
<target name="compile" >
        
<!--
        如果項目比較簡單,如只有一層或層之間關係比較簡單,可以直接使用項目的解決方案文件
        
-->
        
<solution 
            
solutionfile="${vss.directory}${solution.file}"
            configuration
="${build.configuration}"
            outputdir
="${build.directory}">
            
<webmap>
                
<map 
                    
url="http://localhost/DNMCCIT.TYS.WEB/DNMCCIT.TYS.WEB.csproj" 
                    path
="${vss.directory}TYS.WEBDNMCCIT.TYS.WEB.csproj" 
                
/>
            
</webmap>    
        
</solution>
    
</target>
    
<!--生成分發包-->
    
<target name="distribute">
<IMG src="/Images/OutliningIndicators/None.gif" _fcksavedurl=""/Images/OutliningIndicators/None.gif"" align=top
<?xml version="1.0" encoding="gb2312"?>
<project name="DNMCCIT.TYS" default="go">
    
<!-- 可配置屬性列表 -->
        
<!-- 主要屬性列表 -->
            
<property name="core.basedir" value="d:Daily_Build_Folder"/>
            
<property name="core.publish" value="D:inetpubwwwrootTYS"/>
            
<property name="core.build" value="Build"/>
            
<property name="core.distribution" value="Distribution"/>
            
<property name="core.logs" value="Logs"/>
            
<property name="core.documentation" value="Docs"/>
            
<property name="core.source" value="Source"/>
            
<property name="supportal.core" value="/SupportalServersupportal$files"/>
            
<property name="supportal.fxcop" value="${supportal.core}fxcop"/>
            
<property name="supportal.nunit" value="${supportal.core}nunit"/>
            
<property name="supportal.ndoc" value="${supportal.core}ndoc"/>
            
<!--項目相關信息-->
            
<property name="project.manager" value="[email protected]"/>
            
<property name="project.developer" value="[email protected]"/>
            
<property name="project.name" value="DNMCCIT.TYS"/>
            
<!--Build位置信息-->
            
<property name="build.configuration" value="Release"/>
            
<property name="build.number" value="1.0"/>
            
<property name="build.directory" value="${core.basedir}${core.build}${project.name}"/>
            
<property name="build.documentation" value="${build.directory}${core.documentation}"/>
            
<property name="build.logs" value="${build.directory}${core.logs}"/>
            
<property name="build.support" value="${core.publish}@support"/>
            
<property name="build.distribution" value="${core.basedir}${core.distribution}${project.name}"/>
            
<property name="build.publish" value="${core.publish}${project.name}"/>
            
<!--VSS信息-->
            
<property name="vss.username" value=""/>
            
<property name="vss.password" value=""/>
            
<property name="vss.dbpath" value="/t-net1vss8002TYSsrcsafe.ini"/>
            
<property name="vss.path" value="$/DNMCCIT.TYS/"/>
            
<property name="vss.directory"  value="${core.basedir}${core.source}${project.name}"/>
            
<!--VS.NET解決方案信息-->
            
<property name="solution.file" value="DNMCCIT.TYS.sln"/>
            
<!--程序集引用信息-->
            
<property name="solution.assembly.1" value="DNMCCIT.TYS.Data"/>
            
<property name="solution.assembly.2" value="DNMCCIT.TYS.Entity"/>
            
<property name="solution.assembly.3" value="DNMCCIT.TYS.Logic"/>
            
<property name="solution.assembly.4" value="DNMCCIT.TYS.Common"/>
            
<property name="solution.fxcop" value="${project.name}.fxcop"/>
        
<!--屬性列表結束-->
    
<target name="go" depends="prebuild,build"/>
    
<target name="prebuild">
        
<nant buildfile="TYS.PreBuild.xml" target="go" inheritall="true"/>
    
</target>
    
<target name="build">
        
<nant buildfile="TYS.Build.xml" target="go" inheritall="true"/>
    
</target>
    
<target name="deploy">
        
<nant buildfile="TYS.Deploy.xml" target="go" inheritall="true"/>
    
</target>
</project>
2編寫TYS.PreBuild.xml
<?xml version="1.0" encoding="GB2312"?>

<project name="TYS.PreBuild" default="go">
    
<target name="go" depends="clean,getsourcecode"/>
    
<target name="clean" description="Remove all files">
        
<delete dir="${build.directory}" failonerror="false"/>
        
<delete dir="${vss.directory}" failonerror="false"/>
        
<delete dir="${build.distribution}" failonerror="false"/>
        
<mkdir dir="${build.directory}"  />
        
<mkdir dir="${build.documentation}"   failonerror="false" />
        
<mkdir dir="${build.logs}"   failonerror="false" />
        
<mkdir dir="${vss.directory}"/>
        
<mkdir dir="${build.publish}" failonerror="false" />        
    
</target>
    
<!--從VSS中取得源代碼-->
    
<target name="getsourcecode">
        
<vssget
            
user="${vss.username}"
            password
="${vss.password}"
            localpath
="${vss.directory}"
            recursive
="true"
            replace
="true"
            dbpath
="${vss.dbpath}"
            path
="${vss.path}"
            
/>
    
</target>    
</project>


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1587067

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章