Projektaufbau und Konfiguration
Der Build Server
Sie sollten wenn irgendwie möglich einen dedizierten Rechner als Build Server vorsehen, und ihn nicht auf einer Entwicklerstation betreiben.Gründe dafür sind unter anderem das zuverlässigere Setup, die bessere Verfügbarbarkeit und Stabilität und eine wohl definierte Umgebung. Vor allem der letzte Punkt ist auf einem Entwickler PC nicht gegeben.
Das Ziel Setup für den Build Server sieht vor, dass eine neue Umgebung mit minimalem Aufwand eingerichtet werden kann. Die Build Konfiguration jedes einzelnen Projektes ist deshalb komplett im Repository abgelegt. Sie wird nun im Detail besprochen.
Ein neuer Build Server kann ganz einfach in Betrieb genommen werden, indem lediglich CruiseControl.Net und Subversion installiert und die Konfiguration aus dem Repository aufgerufen wird. Die detaillierte Anleitung für die Konfiguration finden sie in der CruiseControl.NET Konfiguration.
Der Entwickler PC
Nebst Visual Studio 2005 oder 2008 und einem Subversion Client oder Visual SourceSafe werden keine weiteren Tools benötigt, um die Build Umgebung bedienen zu können.Die Installation von Subversion und entsprechenden Clients wird im Artikel Source Code Verwaltung mit Subversion ausführlich besprochen.
Das Repository und Projekt Layout
Einer der wichtigsten CI Aspekte ist es, alle benötigten Projektelemente im Repository aufzunehmen. Dies erlaubt es jedem Entwickler, durch ein simples Abrufen der letzen Version aus dem Repository eine lokale Umgebung zu erhalten, in welcher sofort gearbeitet werden kann. Weil auch alle Werkzeuge im Repository vorhanden sind, erhält der Entwickler ohne weitere Installation und Konfiguration von Komponenten die neuesten Versionen mit den korrekten Abhängigkeiten.Um dies zu ermöglichen, wird die folgende Verzeichnisstruktur für ein Projekt verwendet:
Builds
CruiseControl.NET
server
ccnet.config
webdashboard
Deploy
Install
Src
Tools
build.csproj
BuildNumber.txt
In Deploy befinden sich die vom ReleasseBuild erstellten Lieferobjekte. Pro Release wird automatisch ein Verzeichnis erstellt.
In Install befinden sich alle Setup Projekte. Diese können entweder mit dem in Visual Studio integrierten Projekt Assistenten angelegt werden, oder sie können auf der frei verfügbaren Microsoft Technologie WiX basieren. Beide Varianten werden vom Build Prozess unterstützt und automatisch mit dem Build kompiliert.
Wenn Sie die in Visual Studio integrierte Projektvorlage für ein MSI basiertes Setup Projekt verwenden, müssen Sie Visual Studio auf dem Build Server installieren. Ein solches Setup Projekt kann nicht einfach via MSBuild kompiliert werden, sondern benötigt das entsprechende Visual Studio Addin.
Im Ordner src befinden sich alle Visual Studio Solutions und Projekte. Diese können wiederum innerhalb Verzeichnissen gegliedert sein, der Build Prozess unterstützt auch hierarchisch aufgebaute Projekt Strukturen in Visual Studio. Dies kann bei einer Solution mit vielen Projekten die Übersicht und Navigation im Code erleichtern.
Im Verzeichnis Tools befinden sich alle vom Build verwendeten Werkzeuge und Utilities. Um Copyright Probleme zu umgehen, und um sicherzustellen, dass sie mit den aktuellen Versionen arbeiten, sind die Tools nicht in der Build Vorlage enthalten, sondern müssen von ihnen von der jeweiligen Website runtergeladen werden. Je nach ihren Anforderungen und Anpassungen des Build Prozesses benötigen sie auch nicht alle Tools. Die Installation wird weiter unten detailliert erklärt.
Es ist empfehlenswert, eine Projekt Struktur aufzubauen, in welcher die Test Projekte klar vom "produktiven" Code getrennt abgelegt sind. Der Build Prozess unterscheidet Test Projekte von produktivem Code anhand des Projektnamens. Dieser muss für ein Testprojekt "UnitTest" im Namen enthalten.
Beispielsweise heisst ein Testprojekt also ACME.BusinessLogic.UnitTest.
Die Datei build.csproj enthält schliesslich die ganze MSBuild Konfiguration mit allen Build Targets und Tasks. Ein Entwickler kann den Build über diese Datei auch lokal starten, in diesem Fall wird die ganze Solution mit allen Projekten erstellt.
Die Datei BuildNumber.txt enthält die fortlaufend nummerierte Build Nummer, welche Bestandteil der Versionsinformation der Assemblies ist. Wie diese Nummer und die Versionsinformationen erstellt werden, wird im ContinuousBuild erklärt.
Tools
Wie oben erwähnt, benötigt das Build Skript einige Tools um gewisse Aufgaben im Build Prozess erledigen zu können. Alle diese Tools werden im Tools Ordner abgelegt und mit dem Projekt im Repository versioniert.MSBuild Community Tasks
MSBuild bringt von Haus aus bereits einiges an Funktionalität mit. Wenn jedoch Funktionalität wie das Senden eines Emails, der Zugriff auf Source Code Repositories oder anspruchsvollere Dateioperationen gefragt sind, muss MSBuild passen. Eine Möglichkeit wäre, über den Exec Task externe Programme aufzurufen, dies geht jedoch auch nicht in jedem Fall.Die MSBuild Community Tasks bieten diverse nützliche Tasks an welche MSBuild ideal ergänzen. Der Build Prozess benötigt diese Tasks unter anderem, um auf Subversion zuzugreifen, um die Unit Tests auszuführen und um Vorlagen basiert Dateien zu erzeugen.
Kopieren sie den neuesten verfügbaren Nightly Build und kopieren sie den Inhalt des Build Verzeichnisses in das Tools\MSBuild.Community.Tasks Verzeichnis der Projektvorlage.
Download: http://msbuildtasks.tigris.org/MSBuild.Community.Tasks.Nightly.zip
NUnit
Wenn sie bereits Unit Tests einsetzen, müssen nicht viele Worte über NUnit verloren werden. Installieren sie NUnit und kopieren sie den gesamten Inhalt von c:\ProgramFiles\NUnit 2.4.6 ins Verzeichnis Tools\NUnit der Projektvorlage. Danach können sie NUnit wieder deinstallieren, wenn sie es sonst nicht benötigen.Download: http://www.nunit.org/index.php?p=download
WiX
Das Windows Installer XML (WiX) Projekt war das erste Projekte von Microsoft das unter einer Open Source Lizenz (CPL) Lizenz veröffentlicht wurde.Sie können WiX verwenden, um Windows Installer Programme zu erstellen. Die Installer werden über eine XML Datei programmiert, und werden dann von WiX in eine MSI Datei kompiliert.
Für Visual Studio wird eine Projektvorlage mitgeliefert, welche das Editieren und Kompilieren der .wxs Dateien ermöglicht.
Installieren sie WiX und kopieren sie den gesamten Inhalt von c:\ProgramFiles\Windows Installer XML v3 ins Verzeichnis Tools\WiX der Projektvorlage.
Download: ProjectAggregator2-3.0.2925.0.msi, Wix-3.0.2925.0.msi
Build Prozess und MSBuild Targets
Der Build Prozess, oder genauer CruiseControl.NET wird während des Ablaufs einige MSBuild Targets aufrufen. Solche Targets können voneinander abhängig gemacht werden. Wenn also Target C von B, und dieses wiederum von Target A abhängig ist, wird beim Aufruf zuerst A, dann B, und dann erst C ausgeführt.Das Build Skript beinhaltet einige Definitionslisten und Targets, welche von mehreren anderen Targets genutzt werden. Vor den eigentlichen Targets, welche die Aufgaben unseres Build Ablaufs erledigen, werden nun diese allgemeinen Blöcke beschrieben.
Allgemeine PropertyGroup und ItemGroup Blöcke
PropertyGroup und ItemGroup Blöcke in einem MSBuild Skript dienen dazu, benutzerdefinierte Property oder Item Elemente zu definieren. Diese können danach über ihren Namen im Skript angesprochen und verwendet werden.Zu Beginn des Build Skriptes werden nun einige solcher Blöcke definiert.
<!-- ASCII constants -->
<PropertyGroup>
<NEW_LINE>%0D%0A</NEW_LINE>
<TAB>%09</TAB>
<DOUBLE_QUOTES>%22</DOUBLE_QUOTES>
<SPACE>%20</SPACE>
</PropertyGroup>
<!-- Version settings -->
<PropertyGroup>
<Major>0</Major>
<Minor>1</Minor>
<Company>CompanyName</Company>
<!-- The project name must not contain spaces and illegal path chars -->
<ProjectName>CITemplate.VS2005.SVN</ProjectName>
</PropertyGroup>
<!-- The developers email addresses -->
<ItemGroup>
<Developers Include="developer1@company.com;
developer2@company.com" />
</ItemGroup>
<!-- Solution folders -->
<PropertyGroup>
<CodeFolder>$(MSBuildProjectDirectory)\src</CodeFolder>
<BuildsFolder>$(MSBuildProjectDirectory)\Builds</BuildsFolder>
<DeployFolder>$(MSBuildProjectDirectory)\Deploy</DeployFolder>
<InstallFolder>$(MSBuildProjectDirectory)\Install</InstallFolder>
<ToolsFolder>$(MSBuildProjectDirectory)\Tools</ToolsFolder>
<UseCommonBinFolder>1</UseCommonBinFolder>
<BinFolder>bin\$(Configuration)</BinFolder>
<BinFolder Condition=" '$(UseCommonBinFolder)' == '1' ">$(CodeFolder)\bin</BinFolder>
</PropertyGroup>
<!-- Solution files -->
<PropertyGroup>
<SolutionFileName>CITemplate.sln</SolutionFileName>
<SolutionFile>$(CodeFolder)\$(SolutionFileName)</SolutionFile>
<BuildNumberFile>$(MSBuildProjectDirectory)\BuildNumber.txt</BuildNumberFile>
<KeyFile>$(CodeFolder)\$(ProjectName)-Key.snk</KeyFile>
<TestResultFileAppendix>-results.xml</TestResultFileAppendix>
<AssemblyInfoFile>$(CodeFolder)\AssemblyInfoCommon.cs</AssemblyInfoFile>
<AssemblyInfoTemplate>$(CodeFolder)\AssemblyInfoCommon.Template.cs</AssemblyInfoTemplate>
<InstallBuildEmailFile>$(TEMP)\BuildEmailFile.htm</InstallBuildEmailFile>
<InstallBuildEmailTemplate>$(InstallFolder)\BuildEmail.Template.htm</InstallBuildEmailTemplate>
<WixSolutionFileName>$(InstallFolder)\CITemplateAppSetup.sln</WixSolutionFileName>
</PropertyGroup>
<!-- Environment settings -->
<PropertyGroup>
<SmtpServer>mail.company.com</SmtpServer>
<BuildServer>build.company.com</BuildServer>
<BuildMasterMail>buildmaster@company.com</BuildMasterMail>
<CCNetInstallPath Condition=" '$(CCNetInstallPath)' == '' ">$(ProgramFiles)\CruiseControl.NET</CCNetInstallPath>
<DeployShare>\\$(BuildServer)\ProjectDeployShare</DeployShare>
</PropertyGroup>
<!-- Tools settings -->
<PropertyGroup>
<SubversionPath>C:\Program Files\Subversion\bin</SubversionPath>
<SubversionCmd>$(SubversionPath)\svn.exe</SubversionCmd>
<NUnitPath>$(ToolsFolder)\NUnit\bin\</NUnitPath>
<NUnitCmd>$(NUnitPath)nunit-console.exe</NUnitCmd>
<MSBuildCommunityTasksPath>$(ToolsFolder)\MSBuild.Community.Tasks</MSBuildCommunityTasksPath>
<WixPath>$(ToolsFolder)\WiX\bin\</WixPath>
<WixTargetsPath>$(WixPath)Wix.targets</WixTargetsPath>
<WixTasksPath>$(WixPath)WixTasks.dll</WixTasksPath>
<WixToolPath>$(WixPath)</WixToolPath>
</PropertyGroup>
<!-- Subversion settings -->
<PropertyGroup>
<SvnServer>localhost</SvnServer>
<SvnProjectPath>CITemplate.VS2005.SVN</SvnProjectPath>
<SvnServerPath>svn://$(SvnServer)/$(SvnProjectPath)</SvnServerPath>
<SvnTrunkFolder>$(SvnServerPath)/trunk</SvnTrunkFolder>
<SvnTagsFolder>$(SvnServerPath)/tags</SvnTagsFolder>
</PropertyGroup>
<!-- Setting *.csproj project settings, when none are specified -->
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputPath Condition=" '$(OutputPath)' == '' ">$(BinFolder)</OutputPath>
<WixOutputPath Condition=" '$(WixOutputPath)' == '' ">$(InstallFolder)\bin</WixOutputPath>
</PropertyGroup>
Im Block <-- Version settings... --> werden die Informationen zur Assembly Versionierung definiert. Eine .NET Assembly Versionsnummer wird nach dem Muster Major.Minor.Build.Revision angegeben.
Setzen sie Versionsnummern für den Major und Minor Teil im Build Skript. Im Feld CompanyName können sie ihren Firmennamen eintragen, er wird ins Assembly Attribut [assembly: AssemblyCompany("CompanyName") eingetragen.
Der Inhalt des Properties ProductName wird ins Assembly Attribut [assembly: AssemblyProduct("ProductName") eingetragen.
Sie können alle diese Assembly Metadaten anschauen, indem sie die Dateieigenschaften einer DLL anzeigen.
Der Abschnitt <-- The developers email addresses --> enthält alle Email Adressen der beteiligten Entwickler. An diese Adressen wird später ein Email mit dem Build Status geschickt.
Im Block <-- Solution folders --> werden die Pfade zu den vorher erläuterten Ordnern unserer Build Vorlage definiert. Wenn ihr Build Ablauf weitere Verzeichnisse benötigt, sollten sie sie hier definieren.
Erwähnenswert ist das hier verwendete Property $(MSBuildProjectDirectory). Der Wert dieses Properties ist immer auf den Ordnerpfad des Build Skriptes gesetzt. Dieses Property ist eines der vordefinierten Properties von MSBuild, welche sie in ihren Skripten ganz einfach mit dem Syntax $(PropertyName) verwenden können.
Wenn sie alle Assemblies zentral in den Ordner src\bin kopiert haben wollen, setzen sie das Property $(UseCommonBinFolder) auf 1. Wenn der Wert auf 0 gesetzt wird, befinden sich alle Assemblies in den jeweiligen Projektverzeichnissen (bin\Debug oder bin\Release).
Der Abschnitt <-- Solution files --> setzt die Pfade zu allen im Build Ablauf verwendeten Dateien. Hier müssen sie den Namen der Visual Studio Solution und ggf. das Key File an ihr Projekt anpassen.
Der Abschnitt <-- Environment settings --> definiert Properties wie den Build Server Namen, den SMTP Server und ein paar andere verwendete Bezeichner. Passen sie diese Werte gemäss ihrer Umgebung an.
Im Block <-- Tools settings --> werden die Pfade zu den Utilities im Tools Ordner gesetzt. Hier brauchen sie nichts zu verändern, eigene Tools, welche sie im Build vewenden wollen, können sie hier referenzieren.
Der Abschnitt <-- Subversion settings --> definiert Properties, mit welchen auf das Source Code Repository zugegriffen wird. Definieren sie hier den Hostnamen ihres Subversion Servers, und den Pfad zu ihrem Projekt im Repository.
Die Definitionsliste <-- Setting *.csproj project... --> setzt einige Standard Properties für das Kompilieren, falls sie noch nicht definiert sind. Diese Properties werden im Aufruf von CruiseControl.NET gesetzt.
<!-- Imports -->
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets"/>
<!-- Add the CleanSolution task to the general MSBuild Clean target -->
<PropertyGroup>
<CleanDependsOn>$(CleanDependsOn);CleanSolution</CleanDependsOn>
</PropertyGroup>
Die letzte PropertyGroup überschreibt das Property $(CleanDependsOn). Das Clean Target in Microsoft.CSharp.targets ist abhängig von den Targets, welche in diesem Property eingetragen sind. Wir fügen unser eigenes Target "CleanSolution" hinzu, es wird im ContinuousBuild erklärt.