日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

[转]在.NET环境中实现每日构建(Daily Build)--NAnt篇

發(fā)布時間:2025/7/14 asp.net 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转]在.NET环境中实现每日构建(Daily Build)--NAnt篇 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文轉自:http://dragon.cnblogs.com/archive/2005/07/29/203189.html

?

前言

關于每日構建這個話題,也已經有很多很好的文章討論了。本文的寫作過程中也參考了這些文章。本文之所以繼續(xù)這個題目,是因為在查閱了網上的資源后,發(fā)現(xiàn)沒有一個比較通用的過程。所以本文就主要討論了利用NAnt構建一個通用日編譯的方案。利用這個方案,日編譯的維護者可以不需要對每個要編譯的方案都要做很多維護。只要定義一個屬性文件就可以了。


?

關鍵詞: Daily Build, NAnt?


1.?????? 簡介

?

1.1.????? 每日構建的優(yōu)點:

每日構建(Daily Build)也可稱為持續(xù)集成(Continuous Integration),強調完全自動化的、可重復的創(chuàng)建過程,其中包括每天運行多次的自動化測試。每日構建的作用日益顯得重要。它讓開發(fā)者可以每天進行系統(tǒng)集成,從而減少了開發(fā)過程中的集成問題。

持續(xù)集成可以減少集成階段"捉蟲"消耗的時間,從而最終提高生產力。它使得絕大多數(shù)bug在引入的同一天就可以被發(fā)現(xiàn)。而且,由于一天之中發(fā)生變動的部分并不多,所以可以很快找到出錯的位置。

?

1.2.????? 每日構建完成的任務

實現(xiàn)自動化每日構建需要做以下幾部分的工作:

l????????? 使創(chuàng)建過程完全自動化,讓任何人都可以只輸入一條命令就完成系統(tǒng)的創(chuàng)建。

l????????? 使測試完全自動化,讓任何人都可以只輸入一條命令就運行一套完整的系統(tǒng)測試。

l????????? 確保所有人都可以得到最新、最好的可執(zhí)行文件。

?

2.?????? 每日構建所使用的工具

.NET環(huán)境下建立每日構建可以使用一系列開源工具:

Nant: 完成代碼的自動編譯,自動運行測試工具。http://nant.sourceforge.net/builds/

NantContrib:自動從源碼庫中獲取源代碼。http://nantcontrib.sourceforge.net/nightly/builds/

NUnit2Report:將NUnit測試工具產生的XML報告轉換為HTML報告形式。http://NUnit2Report.sourceforge.net

VSS:Visual Source Safe,微軟源碼管理工具

Draco.NET: 用于自動檢測VSS中源代碼變動情況,調用Nant完成自動編譯

????? http://sourceforge.net/projects/draconet/

下載所需的工具后,按照如下步驟進行安裝:

在服務器上安裝VSS源碼管理工具

安裝下載的Draco Server 和 Draco Web,修改安裝后的Draco Web目錄下的web.config文件,設置正確的Draco Server安裝路徑

NAnt、NAntContrib、NUnit2Report壓縮包解壓,將三個Bin目錄中的內容復制到一個公用目錄,比如D:\DailyBuildTools,然后將該路徑加入系統(tǒng)的Path路徑列表中,具體為“控制面板-〉系統(tǒng)屬性-〉環(huán)境變量-〉Path”

?

3.?????? NAnt自動腳本

NAnt腳本實現(xiàn)了每日構建的主體功能,它具體分為下面幾部分

l????????? 定義每日構建所需的一些環(huán)境變量,比如從VSS上下載的源碼的保存目錄,發(fā)布目錄等

l????????? 清除舊的代碼并從VSS源碼庫中下載最新源代碼

l????????? 編譯源代碼并運行測試代碼集

l????????? 將編譯后的目標代碼拷貝到發(fā)布目錄進行發(fā)布

為了盡可能少的改動NAnt的腳本文件,簡化日常維護的工作量,我們把一些對所有項目都基本相同的過程抽取出來,如環(huán)境變量定義,清除舊代碼獲取新代碼,編譯源代碼,對目標代碼進行發(fā)布的過程都可以寫成通用的腳本,而一個具體項目的每日構建腳本則調用通用過程完成

本文采取的目錄體系如下所示:

D:\DailyBuild\

<project1>\Source:存放<project1>源代碼的目錄

<project1>\Build:存放<project1>編譯后的目標代碼的目錄

<project1>\Publish:存放<project1>的WEB發(fā)布文件的目錄

<project1>\log:存放<project1>的日志文件

?

3.1.????? Nant的基礎知識

l????????? Nant腳本代碼文件的基本結構

<?xml version="1.0" encoding="gb2312"?>

<project name="Projects" default="prebuild">

?????? <target name="prebuild" depends="namecheck,clean " description="…">

?????????????????? ……

?????? </target>

?????? <target name="namecheck" >

?????????????????? ……

?????? </target>

</project>

說明:encoding="gb2312"使得腳本文件可以支持中文

<project>標簽定義了項目屬性,一個腳本文件只能有一個項目定義

default="prebuild"說明該項目缺省從prebuild任務開始執(zhí)行

<target>標簽定義了一項任務,任務是Nant腳本具體執(zhí)行動作的最小單元

depends="namecheck,clean "說明該任務執(zhí)行前需要namecheck和clean任務先執(zhí)行

description描述了該任務的一些說明性信息

?

l????????? 定義變量

<property name="<變量名>" value="$<變量值>"/>

如上所示,定義變量使用<property>標簽,name屬性定義了變量的名稱,value屬性定義變量的值,其中name屬性可以使用字母、數(shù)字、點號、下劃線等符號,而value屬性可以使用字符串或是已經定義的變量,Nant內建的函數(shù)等,

要使用已經定義的變量,可以用${<變量名>},要使用內建函數(shù),可以使用${<函數(shù)名稱>}

: <property name="solution.basedir" value="${core.basedir}\${solution.name}"/>

使用了已定義變量core.basedir和solution.name來定義變量solution.basedir;

<property name="curdir" value="${directory::get-current-directory()}"/>

使用了NAnt內建函數(shù)directory::get-current-directory()來定義curdir變量

?

?

?

3.2.????? 定義環(huán)境變量

定義環(huán)境變量的腳本代碼寫在Common。Config文件里

主要有以下幾類信息的定義:

l????????? 每日構建所在的根目錄

??????? <property name="curdir" value="${directory::get-current-directory()}"/>

??????? <property name="core.basedir" value="${curdir}"/>

說明:${directory::get-current-directory()}內建函數(shù)獲取當前文件所在路徑信息

l????????? 被編譯的解決方案的目錄結構,和前面提到的目錄體系一致

??????? <property name="solution.basedir" value="${core.basedir}\${solution.name}"/>

??????? <property name="solution.source" value="${solution.basedir}\source"/>

??????? <property name="solution.build" value="${solution.basedir}\build"/>

??????? <property name="solution.log" value="${solution.basedir}\log"/>

說明:以上代碼是定義了要編譯的解決方案的目錄結構信息,其中${solution.name}是由外部傳入的解決方案的名稱,后面的代碼將根據(jù)該名稱在日編譯的根目錄下生成和solution.name指定的名稱同名的目錄,并在該目錄下生成source,buld,log等子目錄

l????????? VSS源代碼管理系統(tǒng)的基本信息

<!--vss數(shù)據(jù)庫登錄信息-->???

<property name="vss.username" value="autobuild"/>

<property name="vss.password" value="autobuild"/>

<!--vss數(shù)據(jù)庫所在的位置-->

<property name="vss.dbpath" value="\\10.136.238.231\vss\srcsafe.ini"/>

<!--vss中工程的根目錄-->

<property name="vss.basepath" value="$/"/>

說明:定義了和VSS源碼管理系統(tǒng)相關的一些信息,其中VSS數(shù)據(jù)庫所在位置可以是網絡路徑,也可以是本地路徑

l????????? ??????? <編譯時的一些參數(shù)

<!--編譯版本號-->

<property name="build.number" value="1.0"/>

<!--決定編譯是Debug版本還是Release版本-->

<property name="build.configuration" value="Release"/>

?

3.3.????? 建立目錄結構,獲取源代碼

腳本代碼寫在CheckSource.build.xml文件里

l????????? 包含在Common.config文件里定義的公共變量

<include buildfile="common.config"/>

l????????? 檢查是否存在solution.name變量

<target name="namecheck" description="檢查solution.name變量是否設置">

?????? <!--檢查解決方案名稱是否已經定義-->????????

?????????????????? <ifnot test="${property::exists('solution.name')}">

?????????????????????????????? <fail message="未定義解決方案名稱solution.name"/>

?????????????????? </ifnot>

?????????????????? <!--去掉可能的空格字符-->

?????????????????? <property name="solution.name" value="${string::trim(solution.name)}"/>

?????????????????? <!--檢查solution.name變量是否為空字符-->

?????????????????? <if test="${string::get-length(solution.name)==0}">

?????????????????????????????? <fail message="未定義解決方案的名稱solution.name"/>

?????????????????? </if>

</target>

說明:${property::exists('<變量名>')}是NAnt內建函數(shù),用于測試某變量是否存在

${string::get-length(<字符串變量>)==0}測試字符串的長度是否為0

<ifnot test=<邏輯表達式> … </ifnot>:如果test表達式值為假,執(zhí)行<ifnot>標簽內的代碼

<if test=<邏輯表達式> … </if>:如果test表達式值為假,執(zhí)行<if>標簽內的代碼

?

l????????? 建立解決方案的目錄結構

<target name="clean" depends="namecheck" description="移除舊目錄,建立新目錄">

?????????????????? <!--刪除舊的解決方案代碼所在目錄-->

?????????????????? <delete dir="${solution.basedir}" failοnerrοr="false"/>

?????????????????? <!--重新建立目錄-->

?????????????????? <mkdir dir="${solution.basedir}\" failοnerrοr="false"/>

?????????????????? <mkdir dir="${solution.source}" failοnerrοr="false"/>

?????????????????? <mkdir dir="${solution.build}" failοnerrοr="false"/>

?????????????????? <mkdir dir="${solution.log}" failοnerrοr="false"/>

</target>

說明:delete和mkdir標簽內的failonerror屬性表示即使操作文件夾的過程中出現(xiàn)了錯誤,也忽略錯誤向下執(zhí)行

?

l????????? 獲取源代碼:

VSS上獲取解決方案<solution.name>的源代碼

<target name="getsourcecode">

????????????? <!--檢查從VSS上下載解決方案的路徑是否設定-->???????????????

????????????? <!-- 如果不定義vss.projectpath,則缺省為solution.name?-->

????????????? <ifnot test="${property::exists('vss.projectpath')}">

????????????????????????? <property name="vss.projectpath" value="${solution.name}"/>

????????????? </ifnot>

????????????? <vssget

???????????? user="${vss.username}"

???????????? password="${vss.password}"

???????????? localpath="${solution.source}"

???????????? recursive="true"

???????????? replace="true"

???????????? dbpath="${vss.dbpath}"

???????????? path="${vss.basepath}${vss.projectpath}"

???????? />

</target>

說明:<vssget>標簽是NAntContrib的語法,用來從VSS源碼管理器上下載源代碼,user和password屬性表示登錄VSS服務器的信息;Localpath屬性是指下載的源代碼存放的路徑;recursive="true"表示遞歸獲取代碼;replace="true"表示如果本地有重復文件,則進行覆蓋;dbpath定義VSS的srcsafe.ini文件的路徑信息,包括srcsafe.ini文件名;path定義了要獲取的源代碼在VSS數(shù)據(jù)庫中的路徑,一般都是以$/為根目錄。

?

3.4.????? 編譯源代碼

l????????? 編譯命令

編譯解決方案的命令為

<solution?solutionfile="…" configuration="…" outputdir="…">

??????????????????????? <webmap>

??????????????????????????????????? <map url="… " path="…"/>

??????????????????????????????????? <map url="… " path="…"/>

????????? </webmap>

</solution>

其中solutionfile屬性表明了要編譯的解決方案文件的路徑信息,即以"sln"為擴展名的文件,

configuration屬性表明要編譯的是發(fā)行版還是調試版,取值為"Release"或"Debug"

outputdir表明了編譯后的動態(tài)鏈接庫或可執(zhí)行文件存放的目錄

solution中的嵌套標簽<webmap>用于當解決方案含有WEB項目的情況,有幾個WEB項目,就有幾項<map>標簽,map標簽中的url屬性為WEB項目的*.csproj文件的WEB路徑,path則為該*.csproj文件所在磁盤上的物理路徑,例如,解決方案中有WEB項目exam,則map標簽為 <map url="http://localhost/exam/exam.csproj" path="c:\exam\exam.csproj"

?

l????????? 根據(jù)解決方案名稱獲取解決方案文件的路徑信息

<target name="build" description="編譯解決方案">

??????????????????????? <!-- ????? 查找解決方案文件名 ??????? -->

??????????????????????? <foreach item="File" property="filename">

??????????????????????????????????? <in>

??????????????????????????????????????????????? <items>

??????????????????????????????????????????????????????????? <include name="**\${solution.name}.sln"/>

??????????????????????????????????????????????? </items>

??????????????????????????????????? </in>

??????????????????????????????????? <do>

??????????????????????????????????????????????? <!--根據(jù)文件名設置解決方案的名稱-->

??????????????????????????????????????????????? <property name="solution.file" value="${filename}"/>

??????????????????????????????????? </do>

??????????????????????? </foreach>

說明:<foreach>標簽是NAnt中處理循環(huán)的命令,item="File"說明foreach進行循環(huán)處理的對象是文件,<include>中的name變量表示要查找的文件信息,"**\"表示查找路徑包括子目錄。Foreach的屬性property="<變量名>"表示查找到的文件路徑信息保存在該變量中,可以在<do>標簽中引用.foreach每查找到一項符合條件的Item,都會執(zhí)行<do>標簽中的代碼,以上代碼執(zhí)行的結果就是查找到指定名稱的解決方案文件,供后面編譯代碼使用

l????????? 獲取解決方案中WEB項目的路徑信息

如果解決方案中含有WEB項目,則其編譯命令和不含WEB項目的解決方案編譯有所區(qū)別,所以要區(qū)別對待。如果解決方案含有多個WEB項目,則可以讓用戶將多個WEB項目的名稱放在一個變量中,如solution.webprojects,以逗號或分號或空格做分隔符。然后將項目名稱分別提取出來,根據(jù)Web項目的個數(shù)決定solution命令的形式,代碼如下

<!--將solution.webprojects中用",",";"或" "分隔的Web工程名提取出來,

分別設為webproject1,webproject2????????????? -->

<if test="${property::exists('solution.webprojects')}">

??????????? <foreach item="String" in="${solution.webprojects}" delim=";, " property="project">

????? ????? <if test="${property::exists('webproject1')}">

??????????? ?? ??????<property name="webproject2" value="${project}"/>

??????????? ???? </if>

??????????? ???? <ifnot test="${property::exists('webproject1')}">

??????????? ???????? <property name="webproject1" value="${project}"/>

??????????? ???? </ifnot>

??????????? ?</foreach>

</if>

以上代碼中foreach標簽的屬性item="String" in="${solution.webprojects}" delim=";, " property="project"表明循環(huán)對象是字符串,對in所代表的字符串

如果設定solution.webprojects="webprj1;webprj2”,則以上代碼執(zhí)行的結果是定義了兩個變量webproject1 ="webproj1"和webproject2 ="webproj2"

l????????? 查找WEB工程名

根據(jù)前面從solution.webprojects中提取出來的webproj1和webproj2變量,查找該WEB工程的文件名

<!-- ????? 查找WEB工程文件名 -->

??????????? <if test="${property::exists('webproject1')}">

??????????????????????? <echo message="test ${webproject1}" />

??????????????????????? <foreach item="File" property="filename">

??????????????????????? <in>

??????????????????????????????????? <items>

??????????????????????????????????????????????? <include name="**\${webproject1}.csproj"/>

??????????????????????????????????? </items>

??????????????????????? </in>

??????????????????????? <do>

??????????????????????? <!--根據(jù)Web項目的名稱獲取Web項目文件路徑,可以處理兩個Web項目的情況-->

??????????????????????????????????? <echo message="WebProject file=${filename}"/>

????????? ?<property name="webproject1.file" value="${filename}"/>

??????????????????????? </do>

??????????? </foreach>

</if>

同理可以處理存在第二個WEB工程項目的情況,設置webproject2.file變量

l????????? 編譯解決方案

最后是編譯解決方案,分別根據(jù)無WEB項目,有2個WEB項目,有一個WEB項目的三種情況處理

下面僅列出有兩個WEB項目的情況

??????????????????????? <!-- 存在2個Web工程 -->

??????????????????????? <if test="${property::exists('webproject2')}">

??????????????????????????????????? <solution

??????????????????????????????????????????????? solutionfile="${solution.file}"

??????????????????????????????????????????????? configuration="${build.configuration}"

??????????????????????????????????????????????? outputdir="${solution.build}"

??????????????????????????????????? >

??????????????????????????????????????????????? <webmap>

??????????????????????????????????????????????????????????? <map

??????????????????????????????????????????????????????????????????????? url="http://localhost/${webproject1}/${webproject1}.csproj"

??????????????????????????????????????????????????????????????????????? path="${webproject1.file}"

??????????????????????????????????????????????????????????? />

??????????????????????????????????????????????????????????? <map

??????????????????????????????????????????????????????????????????????? url="http://localhost/${webproject2}/${webproject2}.csproj"

??????????????????????????????????????????????????????????????????????? path="${webproject2.file}"

??????????????????????????????????????????????????????????? />

??????????????????????????????????????????????? </webmap>

??????????????????????????????????? </solution>

??????????????????????? </if>

?

3.5.????? 運行測試代碼

l????????? 測試命令

NAnt中關于測試的命令是<NUnit2>標簽

<nunit2>

?? <formatter type="Xml" usefile="true"

extension=".xml" outputdir="…"

/>

??????????????????????????????????? <test assemblyname="…" haltonfailure="false" />

</nunit2>

說明:<formatter>標簽中,type="Xml"表明了根據(jù)測試結果生成XML結構化信息,usefile="true"表明使用文件保存測試結果,extension=".xml"表明生成的文件擴展名為xml,outputdir指出了文件將被保存到哪個目錄

Test標簽中的assemblyname表明了被測試的dll程序集的路徑信息,haltonfailure="false"表明即使測試沒有通過仍然繼續(xù)執(zhí)行腳本文件

這樣在測試命令完成后,會在outputdir指出的目錄下生成一個XML形式的報告文件,為了增加測試結果的可讀性,可以使用另一個工具NUnit2Report,將測試結果轉換為直觀的HTML文件。具體命令如下

<nunit2report out="<文件名>" todir="<輸出目錄" >

??????? <fileset>

??????????????????????? ??????????? <includes name="<文件匹配符>" />

??????? </fileset>

</nunit2report>

說明:includes標簽用來搜索符合條件的XML文件,轉換出來的HTML文件保存為out指出的文件名,todir指出了HTML文件將保存的目錄信息

?

<if test="${property::exists('solution.testprojects')}">

<foreach item="String" in="${solution.testprojects}" delim=";, " property="project">

??????? <property name="testfile" value="${solution.build}\${project}.dll"/>

??????? <nunit2>

<formatter type="Xml" usefile="true"

?extension=".xml" outputdir="${solution.build}" />

??????? ??????????????????????? <test assemblyname="${testfile}" haltonfailure="false" />

</nunit2>

<nunit2report out="${project}.html" todir="${solution.log}" >

??????? ??????????? <fileset>

??????????????????????????????? <includes name="${solution.build}\*.xml" />

??????????????????? </fileset>

??????? </nunit2report>

</foreach>

</if>

?

3.6.????? 進行WEB發(fā)布

WEB發(fā)布主要針對有WEB工程項目的解決方案,其實現(xiàn)原理為利用NAnt的拷貝命令,將WEB工程下除了源代碼,資源代碼,VSS信息文件外的其他文件和編譯后的程序集拷貝到發(fā)布目錄,最后設置WEB虛擬路徑以供WEB訪問的過程。

設置WEB虛擬路徑的命令為

<mkiisdir dirpath="<物理路徑>" vdirname="<虛擬路徑>"/>

說明:設WEB項目發(fā)布在C:\Intepub\wwwroot\Exam,訪問該WEB項目用地址http://127.0.0.1/Example/default.aspx,則<物理路徑>為"C:\Intepub\wwwroot\Exam",虛擬路徑為"Example"(此處略去詳細代碼)。

????????

??????? 下載示例代碼

總結

以上是生活随笔為你收集整理的[转]在.NET环境中实现每日构建(Daily Build)--NAnt篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。