Since we run Subversion for our source control system , there's need for us to identify a build with subversion revision number and the build date, this allowing us to track for bugs and related issues down to every single branch.
What we have is basically a build file , executing svn info for the revision then write it to the solution.version which the link to every project in the solution
<?xml version="1.0" encoding="utf-8" ?>
<project name="x2" default="help" xmlns="http://nant.sf.net/release/0.85-rc4/nant.xsd">
<property name="commit.message" value="" overwrite="false"/>
<property name="configuration" value="debug" overwrite="false"/>
<property name="db.name" value="x2o" overwrite="false"/>
<property name="create.db.sql" value="database\create_database.sql" overwrite="false"/>
<property name="project.name" value="x2.ed"/>
<property name="project.code" value="x2"/>
<property name="result.dir" value="result"/>
<property name="build.dir" value="bin"/>
<property name="src.dir" value="CS" />
<property name="expected.output" value="myniss.exe"/>
<property name="db.server" value="(local)\YUKON" overwrite="false"/>
<property name="help.message" value="OK" overwrite="false"/>
<property name="revision" value="0" overwrite="false"/>
<property name="ticks" value="0" overwrite="false"/>
<property name="solution.version.cs" value="Solution Items\solution.version.cs" overwrite="false"/>
<property name="has.db.schema.changes" value="false"/>
<property name="has.db.code.changes" value="false"/>
<property name="has.new.file" value="false"/>
<property name="base.version" value="1.1"/>
<property name="qa.build.dir" value="QaBuild" overwrite="false"/>
<property name="qa.build" value="false" overwrite="false"/>
<!-- update -->
<target name="up" description="update the current working copy">
<!-- check for property file -->
<if test="${not file::exists('property.template.xml')}">
<exec program="svn" commandline="up property.template.xml"/>
</if>
<if test="${not file::exists('property.xml')}">
<copy file="property.template.xml" tofile="property.xml"/>
</if>
<!-- invoke svn up, and examine the updated item if it contains table the rebuild database -->
<echo message="[Please inspect for anything that might be of interest" append="false" file="svn.update.log.txt"/>
<echo message="e.g. database schema changes, or some unwanted merged by subversion]" append="true" file="svn.update.log.txt"/>
<echo message="" append="true" file="svn.update.log.txt"/>
<exec program="svn" commandline="up" failonerror="true" output="svn.update.log.txt" append="true"/>
<!-- update the property file-->
<exec program="svn" commandline="log http://svn.bespoke.com.my:8080/svn/x2.ed/ --xml --revision HEAD" output="svnlog.xml"/>
<xmlpeek file="svnlog.xml" property="revision" xpath="/log/logentry/@revision" />
<delete file="svnlog.xml" failonerror="false"/>
<xmlpoke file="property.xml" xpath="/property/revision" value="${revision}"/>
<call target="create.version"/>
</target>
<!-- status -->
<target name="st" description="check status">
<!-- invoke svn up, and examine the updated item if it contains table the rebuild database -->
<echo message="[Please examine these new files" append="false" file="st.log.txt"/>
<echo message="if you need it then add , else delete or ignore]" append="true" file="st.log.txt"/>
<echo message="" append="true" file="st.log.txt"/>
<exec program="svn" commandline="st" failonerror="true" output="svn.st.log.txt" append="false"/>
<foreach item="Line" in ="svn.st.log.txt" property ="newfile">
<if test="${string::starts-with(newfile, '?')}">
<property name="has.new.file" value="true"/>
<echo message="${string::replace(newfile, '?', '')}" append="true" file="st.log.txt"/>
</if>
</foreach>
<if test="${has.new.file}">
<exec program="n" commandline="st.log.txt"/>
<exec program="cmdcolor" commandline='-c Red "Theres new uncommited file, ignore, delete or add"'/>
<fail message="There's new uncommited file, ignore, delete or add"/>
</if>
</target>
<!-- commit -->
<target name="ci" description="commit the working copy">
<call target="st"/>
<call target="unit.test"/>
<!-- make sure the client code is error free -->
<exec program="msbuild" commandline="/v:quiet /target:BuildClient" failonerror="true"/>
<if test="${25 > string::get-length(commit.message)}">
<echo message="${commit.message}"/>
<fail message="commit message must be at least 25 charaters length"/>
</if>
<property name="message" value="${string::replace(commit.message, '.', ' ')}"/>
<exec program="svn" commandline=' ci -m "${message}"'/>
</target>
<target name="cit" description="test commit script">
<echo message="${commit.message}"/>
</target>
<!--
*********************************************************************
BUILD
NOTE : we're still using exec task to execute MSBuild solution
***************************************************************************
-->
<target name="unit.test">
<exec program="msbuild" commandline="/v:quiet src\Test\Clinical.Test\Clinical.Test.csproj"/>
<exec program="msbuild" commandline="/v:quiet src\Test\Registration.Test\Registration.Test.csproj"/>
<exec program="msbuild" commandline="/v:quiet src\Test\Services.Test\Services.Test.csproj"/>
<exec program="msbuild" commandline="/v:quiet src\Test\SqlPersistence.Test\SqlPersistence.Test.csproj"/>
<exec program="msbuild" commandline="/v:quiet src\Test\Report.Test\Report.Test.csproj"/>
<exec program="msbuild" commandline="/v:quiet src\Test\SystemFrameworks.Test\SystemFrameworks.Test.csproj"/>
<echo message="------ Clinical.Test run ---------------------"/>
<exec program="nunit-console.exe" workingdir="src\nunit.test\Clinical.Test" commandline="/nologo /xml=Clinical.Test.result.xml Clinical.Test.nunit"/>
<echo message="------ Registration.Test run ---------------------"/>
<exec program="nunit-console.exe" workingdir="src\nunit.test\Registration.Test" commandline="/nologo /xml=Registration.Test.result.xml Registration.Test.dll.nunit"/>
<echo message="------ Services.Test run ---------------------"/>
<exec program="nunit-console.exe" workingdir="src\nunit.test\Services.Test" commandline="/nologo /xml=Services.Test.result.xml Services.Test.dll.nunit"/>
<echo message="------ SqlPersistence.Test run ---------------------"/>
<exec program="nunit-console.exe" workingdir="src\nunit.test\SqlPersistence.Test" commandline="/nologo /xml=SqlPersistence.Test.result.xml SqlPersistence.Test.dll.nunit"/>
<echo message="------ Report.Test run ---------------------"/>
<exec program="nunit-console.exe" workingdir="src\nunit.test\Report.Test" commandline="/nologo /xml=Report.Test.result.xml Report.Test.dll.nunit"/>
<!-- Report test -->
<echo message="------ SystemFrameworks.Test run ---------------------"/>
<exec program="nunit-console.exe" workingdir="src\nunit.test\SystemFrameworks.Test" commandline="/nologo /xml=SystemFrameworks.Test.result.xml SystemFrameworks.Test.dll.nunit"/>
</target>
<target name="simian" description="finds duplicate code">
<exec program="simian.exe" failonerror="false">
<arg value="-recurse=*.cs"/>
<arg value="-formatter=xml:simian.result.xml"/>
</exec>
</target>
<!-- cleaning -->
<target name="clean" description="Delete all previously compiled binaries.">
<delete>
<fileset>
<include name="**/bin/**"/>
<include name="test/**"/>
<include name="**/sbin/**"/>
<include name="**/obj/**"/>
<include name="output/bin/*.*"/>
<exclude name="references/entlib/bin/*.*"/>
<exclude name="references/*.dll"/>
</fileset>
</delete>
</target>
<!-- update version -->
<target name="create.version" description="change the solution version number">
<!-- get the revision number from subversion -->
<xmlpeek file="property.xml" property="revision" xpath="/property/revision" />
<delete file="svnlog.xml" failonerror="false"/>
<script language="C#" prefix="tick" >
<code>
<![CDATA[
[Function("get-ticks")]
public static int GetTicks( )
{
return (DateTime.Today - new DateTime(2000, 1, 1)).Days;
}
]]>
</code>
</script>
<property name="version.number" value="${base.version}.${tick::get-ticks()}.${revision}"/>
<!-- write the version to the SolutionVersion.cs file -->
<echo message="using System;" append="false" file="${solution.version.cs}"/>
<echo message="using System.Reflection;" append="true" file="${solution.version.cs}"/>
<echo message="using System.Runtime.CompilerServices;" append="true" file="${solution.version.cs}"/>
<echo message='[assembly: AssemblyVersion("${version.number}")]' append="true" file="${solution.version.cs}"/>
<!-- database version -->
<echo message="CREATE FUNCTION fn_Version ()" append="false" file="database\update_version.sql"/>
<echo message="/* ++ */" append="true" file="database\update_version.sql"/>
<echo message="RETURNS NVARCHAR(50)" append="true" file="database\update_version.sql"/>
<echo message="AS" append="true" file="database\update_version.sql"/>
<echo message="BEGIN" append="true" file="database\update_version.sql"/>
<echo message="RETURN '${version.number}'" append="true" file="database\update_version.sql"/>
<echo message="END" append="true" file="database\update_version.sql"/>
<!-- XSLT project -->
<exec program="svn" commandline="revert src\Client\Reports\xsltcopy.proj"/>
<xmlpoke value="${version.number}" xpath="/ms:Project/ms:PropertyGroup/ms:AssemblyVersion" file="src\Client\Reports\xsltcopy.proj" >
<namespaces>
<namespace prefix="ms" uri="http://schemas.microsoft.com/developer/msbuild/2003"/>
</namespaces>
</xmlpoke>
<!-- developement data in the database -->
<echo message="UPDATE [Oscc].[Locker] SET [Version] = '${version.number}'" append="false" file="update_locker_version.sql"/>
<exec program="sqlcmd" commandline="-E -S ${db.server} -d ${db.name} -i update_locker_version.sql"/>
<delete file="update_locker_version.sql" failonerror="false"/>
<!-- Data source file -->
<property name="oscc.module.ds" value="src\Client\Modules\oscc_module\Properties\DataSources"/>
<foreach item="File" in="${oscc.module.ds}" property="ds">
<property name="dir" value="${path::get-directory-name(ds)}\"/>
<property name="dsfile" value="${string::replace(ds, dir, '')}"/>
<property name="typename" value="${string::replace(dsfile, '.datasource', '')}"/>
<xmlpoke file="${ds}" xpath="/ms:GenericObjectDataSource/ms:TypeInfo" value="${typename}, Bespoke.X2ed.Services.Core.BusinessActions, Version=${version.number}, Culture=neutral, PublicKeyToken=8aded27eed9259ed">
<namespaces>
<namespace prefix="ms" uri="urn:schemas-microsoft-com:xml-msdatasource"/>
</namespaces>
</xmlpoke>
</foreach>
</target>
<!-- **********************************************************************
DATABASE
***************************************************************************-->
<target name="create.db" depends="load.db.props">
<echo message="database server : ${db.server}"/>
<exec program="sqlcmd" commandline="-E -S ${db.server} -d master -i ${create.db.sql}" failonerror="true"/>
<!--
Read all the files in the database folders
Starts with
- default
- Tables
- rules
- Alter Tables
- views
- sproc
the order must be followed by the list in "order.txt"
-->
<call target="db.schema"/>
<call target="db.default"/>
<call target="db.table"/>
<call target="db.code"/>
<call target="db.data"/>
<call target="db.membership"/>
</target>
<target name="db.code" description="re-create the database codes such as sproc view etc on x2 database" depends="load.db.props">
<echo message="database server : ${db.server}"/>
<!--
Read all the files in the database folders
Starts with
- default
- rules
- Alter Tables
- views
- sproc
the order must be followed by the list in "order.txt"
-->
<call target="db.rule"/>
<call target="db.view"/>
<call target="db.function"/>
<call target="db.sproc"/>
<call target="db.version"/>
<exec program="cmdcolor" commandline='-c Red "Inspect the build file log for any errors and warnings"'/>
</target>
<target name="rename.db.file" description="just a little utils">
<foreach item="File" in="database\table" property="file">
<copy file="${file}" tofile="${string::replace(file, 'dbo.', '')}"/>
</foreach>
</target>
<target name="db.schema" depends="load.db.props">
<foreach item="File" in ="database\schemas" property="schema">
<exec
program="sqlcmd"
unless="${string::starts-with(schema,'#')}"
commandline='-E -S ${db.server} -d ${db.name} -i "${schema}"'
failonerror="true"
append="false"/>
</foreach>
<foreach item="File" in ="database\xml.schema" property="xmlschema">
<exec
program="sqlcmd"
unless="${string::starts-with(xmlschema,'#')}"
commandline='-E -S ${db.server} -d ${db.name} -i "${xmlschema}"'
failonerror="true"
append="false"/>
</foreach>
</target>
<target name="db.default" depends="load.db.props">
<foreach item="File" in ="database\default" property="default">
<exec
program="sqlcmd"
unless="${string::starts-with(default,'#')}"
commandline='-E -S ${db.server} -d ${db.name} -i "${default}"' failonerror="true" append="false"/>
</foreach>
</target>
<target name="db.function" depends="load.db.props">
<foreach item="File" in ="database\function" property="function">
<exec
program="sqlcmd"
unless="${string::starts-with(function,'#')}"
commandline='-E -S ${db.server} -d ${db.name} -i "${function}"'
failonerror="true"
append="false"/>
</foreach>
</target>
<target name="db.version" depends="create.version, load.db.props">
<!-- update the database version according to the working copy revision -->
<exec
program="sqlcmd"
if="${file::exists('database\update_version.sql')}"
commandline="-E -S ${db.server} -d ${db.name} -i database\update_version.sql"
failonerror="true"
append="true"/>
</target>
<target name="db.view" depends="load.db.props">
<foreach item="File" in ="database\view" property="view">
<exec
program="sqlcmd"
unless="${string::starts-with(view,'#')}"
commandline='-E -S ${db.server} -d ${db.name} -i "${view}"'
failonerror="true" append="false"/>
</foreach>
</target>
<target name="db.rule" depends="load.db.props">
<foreach item="File" in ="database\rule" property="rule">
<exec
program="sqlcmd"
commandline='-E -S ${db.server} -d ${db.name} -i "${rule}"'
failonerror="true"
append="false"/>
</foreach>
</target>
<target name="db.table" depends="load.db.props">
<foreach item="Line" in ="database\table.txt" property ="table">
<exec
program="sqlcmd"
unless="${string::starts-with(table,'#')}"
commandline="-E -S ${db.server} -d ${db.name} -i database\table\${table}.sql"
failonerror="true" append="false"/>
</foreach>
</target>
<target name="db.sproc" depends="load.db.props">
<!-- hand crafted sproc -->
<foreach item="File" in ="database\sproc" property="sproc">
<echo message="executing ${sproc}"/>
<exec
program="sqlcmd"
unless="${string::starts-with(sproc,'#')}"
commandline='-E -S ${db.server} -d ${db.name} -i "${sproc}"'
failonerror="true"
/>
</foreach>
</target>
<target name="load.db.props">
<xmlpeek file="property.xml" property="db.server" xpath="/property/dbServer" verbose="false" />
<xmlpeek file="property.xml" property="db.name" xpath="/property/dbName" verbose="false" />
</target>
<target name="db.data" depends="load.db.props">
<foreach item="Line" in ="database\table.txt" property ="table">
<if test="${not string::starts-with(table,'#')}" >
<property name="insertfile" value="database\data\${table}.sql"/>
<exec if="${file::exists(insertfile)}" program="sqlcmd" commandline="-E -S ${db.server} -d ${db.name} -i ${insertfile}" failonerror="true" append="false"/>
</if>
</foreach>
</target>
<target name="db.membership" depends="load.db.props">
<echo message="membership -S ${db.server} -d ${db.name}"/>
<exec program="aspnet_regsql" commandline="-E -S ${db.server} -d ${db.name} -A m -A r -A p" failonerror="true" append="false"/>
<if test="${qa.build}">
<exec program="mru" commandline="-u user1001 -p 123456 -e user1001@bespoke.com.my -r Administrator -r MO -r MA -c src\Client\Application\OsccClient\app.config"/>
</if>
<if test=" ${not qa.build}">
<exec program="mru" commandline="-u user1 -p 123456 -e user1@bespoke.com.my -r Administrator -r MO -r MA -c src\Client\Application\OsccClient\app.config"/>
<exec program="mru" commandline="-u user2 -p 123456 -e user2@bespoke.com.my -r Administrator -r MO -r MA -c src\Client\Application\OsccClient\app.config"/>
<exec program="mru" commandline="-u usermo -p 123456 -e userMO@bespoke.com.my -r MO -c src\Client\Application\OsccClient\app.config"/>
<exec program="mru" commandline="-u userma -p 123456 -e userMA@bespoke.com.my -r MA -c src\Client\Application\OsccClient\app.config"/>
</if>
</target>
<target name="test.mru">
<exec program="mru" commandline="-u user002 -p 123456 -e user002@bespoke.com.my -r Administrator -r MO -r MA -c src\Client\Application\OsccClient\app.config"/>
</target>
<!-- *****************************************************************************
DISPLAY HELPS
*****************************************************************************-->
<target name="help" description="display the contents of the help file">
<if test="${file::exists('Solution Items\build help.txt')}" >
<exec program="n" commandline="Solution Items\build help.txt"/>
</if>
</target>
<target name="h" depends="help"/>
<!-- **********************************************************************
Code analisys
***************************************************************************-->
<target name="code.stat">
<codestats output="test.xml" verbose="true" summarize="true">
<counts>
<count label="C#">
<fileset>
<include name="**\*.cs" />
</fileset>
</count>
</counts>
</codestats>
</target>
<!-- *************************************************************************
QA Build
******************************************************************************-->
<target name="qa" description="qa build">
<property name="qa.build" value="true"/>
<exec program="svn" commandline="log http://svn.bespoke.com.my:8080/svn/x2.ed/ --xml --revision HEAD" output="svnlog.xml"/>
<xmlpeek file="svnlog.xml" property="revision" xpath="/log/logentry/@revision" />
<delete file="svnlog.xml" failonerror="false"/>
<script language="C#" prefix="tick" >
<code>
<![CDATA[
[Function("get-ticks")]
public static int GetTicks( )
{
return (DateTime.Today - new DateTime(2000, 1, 1)).Days;
}
]]>
</code>
</script>
<property name="version" value="${base.version}.${tick::get-ticks()}.${revision}"/>
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\bin"/>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\bin">
<fileset basedir="output\bin">
<include name="*.dll"/>
<include name="*.exe"/>
<include name="*.config"/>
<!-- we need the debug information for QA -->
<include name="*.pdb"/>
<exclude name="*.xml"/>
<include name="HelpProviderList.xml"/>
</fileset>
</copy>
<copy file="src\Client\Application\oscc_application_helper\HelpProviderList.xml" todir="${qa.build.dir}\${revision}\bin" overwrite="true"/>
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\bin\${version}"/>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\bin\${version}">
<fileset basedir="src\Client\Reports\xslt">
<include name="*.xslt"/>
</fileset>
</copy>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\sdm">
<fileset basedir="output\sdm">
<include name="*.*"/>
</fileset>
</copy>
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\sdm\images"/>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\sdm\images">
<fileset basedir="output\sdm\images">
<include name="*.*"/>
</fileset>
</copy>
<!-- COPY ALL HELP FILES -->
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\sdm\help_file"/>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\sdm\help_file">
<fileset basedir="output\sdm\help_file">
<include name="*.*"/>
</fileset>
</copy>
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\sdm\help_file\pix"/>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\sdm\help_file\pix">
<fileset basedir="output\sdm\help_file\pix">
<include name="*.*"/>
</fileset>
</copy>
<foreach item="Folder" in="output\sdm\help_file\pix" property="pixfolder">
<property name="rootdir" value="${path::get-directory-name(pixfolder)}\"/>
<property name="pixfolder" value="${string::replace(pixfolder, rootdir, '')}"/>
<if test="${not string::ends-with(pixfolder,'.svn')}">
<!---->
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\sdm\help_file\pix\${pixfolder}"/>
<copy includeemptydirs="true" todir="${qa.build.dir}\${revision}\sdm\help_file\pix\${pixfolder}">
<fileset basedir="output\sdm\help_file\pix\${pixfolder}">
<include name="*.*"/>
</fileset>
</copy>
</if>
</foreach>
<!-- database -->
<mkdir failonerror="true" dir="${qa.build.dir}\${revision}\data"/>
<delete dir="${qa.build.dir}\data" failonerror="false"/>
<mkdir failonerror="true" dir="${qa.build.dir}\data"/>
<property name="create.db.sql" value="database\create_database_qa.sql"/>
<call target="create.db"/>
<exec program="sqlcmd" commandline="-E -S (local)\YUKON -d master -i database/detach_db.sql"/>
<move file="${qa.build.dir}\data\x2o.mdf" overwrite="true" todir="${qa.build.dir}\${revision}\data"/>
</target>
</project>