André Krämers Blog

Lösungen für Ihre Probleme

Von Administratoren geliebt, von Entwicklern verflucht: Das Transportsystem von SAP. Prinzipiell kann man sich das so vorstellen, dass dieses System vorsieht, dass der Quellcode nur an einer Stelle, nämlich im SAP Entwicklungssystem erstellt und modifiziert wird.

Anschließend wird ein sogenannter Transport (so was ähnliches wie ein Setuppaket) erstellt. Dieses kann dann je Konfiguration erst mal nur in das Testsystem eingespielt werden. Dort wird das Paket auf seine Funktionstüchtigkeit getestet. Wurden diese Tests bestanden, wird es in das Integrationssystem “transportiert”. Dort wird das Zusammenspiel mit anderen Anpassungen getestet, es wird also geprüft, ob das Paket nichts anderes kaputt macht ;-)

War auch dieser Test erfolgreich, wird der Transport aus dem Integrationssystem in das Produktionssystem transportiert. Ein direktes Einspielen von Transporten in das Produktionssystem beziehungsweise sogar ein direktes Ändern der Quellcodes ist nicht vorgesehen.

Auch wenn diese Vorgehensweise zunächst recht streng, bürokratisch und viel zu aufwändig wirkt, hat sie durchaus ihren Sinn. Dieser zugegeben etwas starre Prozess sorgt dafür, dass SAP Produktionssysteme normalerweise immer stabil und möglichst fehlerfrei sein sollten. Er trägt also Maßgeblich zu SAPs gutem Ruf bei!

Warum erzähle ich das eigentlich?

Ok, nette Einführung, aber ist das hier nicht eigentlich ein auf .NET fokussierter Blog? Ja :-) Also keine Sorge, ich bin nicht ins Lager der SAP Consultants gewechselt ;-) Allerdings habe ich von ungefähr 2005 bis 2008 die SAP Schnittstelle meines ehemaligen Arbeitgebers gemeinsam mit einem Kollegen weiterentwickelt. Da blieb der ein oder andere Blick unter die Haube diverser SAP Systeme nicht aus.

Nun aber zurück zum Thema:

In meiner beruflichen Laufbahn war ich an einigen (ASP).NET Projekte beteiligt, die von einem SAP transportähnlichen System sehr profitiert hätten. Überspitzt gesagt sah es dort nämlich häufig so aus, dass ein Entwickler nach einer Quellcodeänderung Visual Studio genutzt hat um einen neuen Releasestand zu erstellen und diesen dann schnell auf den produktiven Webserver gepackt hat. Selbstverständlich wurde das ganze vorher nicht in einem Test- oder Integrationssystem installiert und unter Umständen wusste der Kunde und/oder Projektleiter sogar nichts von dem adhoc Update.

Agil != Chaos !!!

Der Entwickler handelte unter dem Deckmantel der agilen Entwicklung nach dem Prinzip “nach mir die Sinnflut”, einfach drauf damit, wird schon klappen. In diesem Zusammenhang finde ich es übrigens immer wieder äußerst verwunderlich, wie viele Entwickler unkoordiniertes und schlampiges Vorgehen einfach als agil bezeichnen, um ihr Chaos damit zu entschuldigen. Agil ist allerdings alles andere als chaotisch, unprofessionell, unkoordiniert oder schlampig. Aber gut, dass ist ein anderes Thema - ich schweife schon wieder aus ;-)

In einem meiner aktuellen Projekte wollte ich einer solchen Vorgehensweise direkt einen Riegel vorschieben. Nicht dass die Entwickler dieses Projekts chaotisch wären, das ist ganz und gar nicht der Fall, aber wir wollen ja auch niemanden in Versuchung führen ;-)

Ich hatte einen Traum …

Meine Ziele lautete also wie folgt:

  1. Releasestände einer Software sollen automatisch auf einem dedizierten Buildrechner und nicht auf einem Entwickler-PC erstellt werden.
  2. Jedes Release hat eine eindeutige Versionsnummer. Kompilate auf dem Entwicklerrechner haben jedoch immer die Nummer 1.0.0.0 (dazu später mehr)
  3. Jedes Release soll ein Set an Unit Tests durchlaufen haben.
  4. Jedes Release soll mit einer bestimmten Qualität als Metadatum versehen werden.
  5. In Abhängigkeit von dieser Qualität und der vorherigen Qualität soll die Software bei bestimmten Statusübergängen automatisch auf bestimmte Systeme verteilt werden.
  6. Das Qualitätsmetadatum wird durch einen dedizierten Personenkreis gesetzt (zum Beispiel QM-Manager oder Projektmanager, Softwarearchitekt oder Chefentwickler)

Realisiert werden sollte das ganze mit Visual Studio 2008 und dem Team Foundation Server. Die Punkte 1 - 3 stellen in einer solchen Umgebung kein Problem dar.

Punkt Nr. 1 erledigen wir durch Teambuild. Hier läuft ein Buildagent auf einem dedizierten Rechner. Durchgeführt werden sowohl Continuous Integration Builds, als auch Nightly Builds.

Punkt Nr. 2 haben wir durch ein einfaches Build Target in unserem Buildscript erledigt. Die Versionsnummer haben wir wie folgt aufgebaut:

  • Major: Fixer Wert
  • Minor: Fixer Wert
  • Build: Aktueller Changeset des Teamprojekts im TFS
  • Revision: Fortlaufende Nummer

Diese Nummer wird nur während des Builds durch Teambuild erzeugt. Entwicklerbuilds haben immer die Version 1.0.0.0. So fange ich ab, dass ein Entwickler doch einfach mal auf seinem Rechner eine Version baut und versucht zu deployen. Natürlich ist dies nur ein weicher Schutz. Mit ein wenig Aufwand lässt sich das System natürlich leicht umgehen indem ein Entwickler eine korrekte Versionsnummer erzeugt. Allerdings ist der Aufwand schon wieder so hoch, dass sich dann doch lohnt, den vorgesehenen Prozess einzuhalten ;-)

Sollte jemand Interesse an diesem Teil des Buildscripts haben: Einfach einen Kommentar posten.

Punkt Nr. 3 ist natürlich auch kein Problem. Aufgrund der guten VS Integration haben wir uns für MS Test für dieses Projekt entschieden. Diese Tests als Bestandteil des Buildprozess laufen zu lassen war demnach kein Problem.

Punkt Nr. 4 ist auch bereits von Haus aus mit dem TFS möglich. Jeder Build der durch Teambuild durchgeführt wird hat ein Metadatum Buildqualität. Die möglichen Werte der Buildqualität lassen sich frei definieren. Auch lässt sich über entsprechende Rechte einschränken, wer diese Qualität setzen darf. Wir haben bei uns die Werte “Entwicklung”, “Test”, “Integration”, “Produktion” und “Abgelehnt” definiert.

Punkt Nr. 5 kann mit TFS Bordmitteln erst mal nicht realisiert werden. Hier kommt nun das Open Source Projekt TFS Deployer ins Spiel. TFS Deployer installiert man als Windowsdienst. Nach entsprechender Konfiguration lauscht er nun auf eine Änderung der Buildqualität. Dazu muss der Benutzer unter dem der Dienst läuft allerdings in der TFS Gruppe Valid Users sein und für das entsprechende Temaprojekt zumindest Leserechte haben. Bemerkt TFS Deployer nun einen Statusübergang, für den er ein Deploymentscript hat, führ er dieses automatisch aus.

Angelehnt an die Einführung von Dave Comfort und Scott Colestock kann man sich das ganze nun wie folgt vorstellen:

tfsdeployer

Konkret sieht dies so aus, dass innerhalb der TFS Quellcodeverwaltung unterhalb des Verzeichnisses der Builddefinition ein Verzeichnis Deployment angelegt wird, also zum Beispiel $/TeamProjekt/TeamBuildTypes/MeinProjektNightlyBuild/Deployment. In diesem Verzeichnis wird nun die Datei DeploymentMappings.xml angelegt. In dieser Datei wird für jeden gewünschten Statusübergang festgelegt, welches Powershellscript auf welchem Computer ablaufen soll. Die Datei DeploymentMappings kann zum Beispiel wie folgt aussehen:

In diesem Script werden vier Statusübergänge definiert. Erst vom leeren Zustand nach Entwicklung, dann weiter nach Test, Integration und Produktion. Jeder dieser Status entspricht einem Build-Quality Eintrag im TFS. Diese sind wie angemerkt frei definierbar. Über die Eigenschaft Script wird nun definiert, welches Powershellscript ausgeführt werden soll. Diese Powershellscripte müssen übrigens im selben Ordner liegen, wie die Datei DeploymentMappings.xml.

Tritt nun einer der definierten Statusübergänge auf, ruft TFS Deployer das gewünschte Script im Kontext des Service Users auf und übergibt ein BuildData Objekt. Die verschiedenen des Eigenschaften BulidData Objekts können dann über die Variable $TfsDeployerBuildData zugegriffen werden.

In unserer Umgebung nutzen wir übrigens eine modifzierte Variante des Beispiels der Seite Team Foundation Server Build Recipes.

  function publish-site( [string] $sourcepath, [string] $destinationpath, [bool] $renameconfig, [bool] $deleteexisting) {
    $droplocation = $TfsDeployerBuildData.DropLocation

    $websourcepath = $droplocation + $sourcepath
    $webdestinationpath = $destinationpath

    new-item -force -path $webdestinationpath -itemtype "directory"
    if ($deleteexisting) {
        get-childitem $webdestinationpath | remove-item -force -recurse
    }
    get-childitem $websourcepath | copy-item -force -recurse -destination $webdestinationpath

    if ($renameconfig) {
        $configFile = $webdestinationpath + "web.production.config"
        remove-item $configFile -force
        $configFile = $webdestinationpath + "web.development.config"
        remove-item $configFile -force
        $configFile = $webdestinationpath + integration.config"
        remove-item $configFile -force


        $configFile = $webdestinationpath + "web.test.config"
        $configFileDest = $webdestinationpath + "web.config"
        move-item $configFile $configFileDest -force
    }
}
publish-site "\Release\_PublishedWebsites\MyWebApplication\" "\\MeinWebServer\MeineFreigabe\" 1 1

Dies funktioniert in unserer Umgebung recht gut, da wir vom Build Server direkten Zugriff auf die verschiedenen Web Server (Entwicklung, Test, Integration, Produktion) haben. Für jede Webapplikation besteht auf den Servern eine Windows Freigabe, die direkt auf das Wurzelverzeichnis der Applikation zeigt. Zugriffsrechte hat hier nun der Benutzer, unter der TFS Deployer Dienst läuft. So stellen wir sicher, dass keiner der Entwickler “mal schnell” etwas patcht ;-) Noch sicherer wäre es natürlich gewesen, den TFS Deployer Dienst direkt auf dem Web Server laufen zu lassen, und ihm lesenden Zugriff auf die erstellen Binaries des Buildprozesses zu geben.

Als Erweiterung zum Standardscript wärmen wir nach dem Deployment Vorgang die Applikation noch auf, indem wir einige Seiten ansurfen. Somit ist sichergestellt, dass der Workerprozess beim ersten Zugriff durch einen Benutzer schon da ist und die entsprechenden Seiten auch schon kompiliert wurden.

Den Übergang von “Nichts” zu “Entwicklung” machen wir übrigens automatisch als letzten Schritt unseres Buildscripts. Somit wird der Nightly Build Automatisch in die Entwicklungsumgebung gejagt.

Und was hat man nun davon?

Mit dem TFS Deployer haben Nutzer des TFS eine einfache Möglichkeit, benannte Softwarestände automatisch in verschiedene Umgebungen zu verteilen. Die dadurch entstehende Nachvollziehbarkeit lässt aus meiner Erfahrung Kunden und somit auch die Projektverantwortlichen im internen Team besser schlafen.

Ein wenig schade ist, dass man innerhalb des TFS zwar verschiedene Buildqualitäten, jedoch keine Regeln für gültige Übergänge anlegen kann. Da unsere Scripte jedoch auf festen Übergängen definieren bedeutet dies, dass derjenige, der die Buildqualität setzt, genau wissen muss welche Übergänge gültig sind. Schaltet er nämlich zum Beispiel von Test direkt auf Produktion passiert nämlich nichts.

Angeregt zu diesem Blog Post hat mich übrigens Robert Mühsigs Posts Build / Deployment / WTF.

Es gibt 5 Kommentare

Comment by Robert Mühsig
Von | 29.10.2011 21:11
Hallo André,das klingt jedenfalls recht interessant. Ich hab mir seitdem ich den Blogpost geschrieben hab noch ein paar Gedanken zum Thema gemacht und da hätte ich gleich ein paar Fragen ;)Habt ihr auch automatische UI-Tests, welche die Webseite mal "durchklicken" oder wie laufen bei euch Integrationstests?Der TFSDeployer hat für mich ein wenig nach MSDeploy geklungen. Hast du dich schon mal mit MSDeploy beschäftigt? Der TFSDeployer macht ja zum Teil ähnliche Sachen, nur das man eigene PS-Scripte hat und das er direkt auf TFSBuild Qualitätssachen achtet. Wie "deployed" ihr Datenbankänderungen? Wir das auch automatisch gemacht?Werden bei euch Releasenotes per Hand geschrieben oder zeugt ihr die automatisch im Build Prozess? Es gibt wohl ein paar Ansätze wie man das machen könnte, aber so ein richtig funktionierendes Beispiel hab ich nicht gefunden.Viele Grüße,Robert
Comment by Christian Pappert
Von | 29.10.2011 21:11
Hallo André,vielen Dank für diesen Artikel. Ich bin bisher nicht weiter gekommen als den Build-Server mit Deployment und Testläufen aufzusetzen. Kannst Du mir das Buildscript zu kommen lassen?Sonnige Grüße,Christian
Comment by André Krämer
Von | 29.10.2011 21:11
@Robert, in diesem Projekt nutzen wir manuelle Integrationstests, sprich wir haben einen QM Verantwortlichen der alles durchklickt. In anderen Projekten haben wir sehr gute Erfahrungen mit QuickTest Pro von HP für automatische UI Tests gemacht.Mit MSDeploy habe ich bisher noch nichts gemacht. Nachdem ich auf die Homepage geschaut habe denke ich jedoch, dass ich es gut in Kombination mit dem TFS Deployer einsetzen könnte. Innerhalb des Powershell Scripts kann ich ja problemlos die MSDeploy.exe aufrufen.Datenbankänderungen deployen wir im aktuellen Projekt nicht automatisch. Das liegt aber auch daran, dass die DB in diesem Projekt recht statisch ist. Die Änderungen waren bisher so selten, dass sich ein automatischer Prozess noch nicht rentiert hätte. Wären die Änderungen häufiger, würde ich hier jedoch versuchen einen automatischen Weg zu wählen.Releasenotes schreiben wir im aktuellen Projekt von Hand. Habe noch gar nicht über einen automatischen Weg nachgedacht. Würde dies über die Checkin Kommentare funktionieren???@Christian,kommt bald hier im Blog :-)Viele GrüßeAndré
Comment by André Krämer
Von | 29.10.2011 21:11
WorkItem Hierarchie ist eine gute Idee. Haben wir bei uns auch eingeführt. Die ersten beiden Ebenen haben wir als Requirements angelegt. Die Texte stammen aus dem Anforderungsdokument des Kundens. Darunter wie du auch vorgeschlagen hast Entwickler Tasks. Besonders empfehlen kann ich in diesem Zusammenhang den Artiso Work Item Manager. Damit wurde die hierarchische Anlage der Workitems zum Kinderspiel! Die paar Euro für das Tool sind auf jeden Fall gut investiert.Zu den Check-In Kommentaren. Da hast du wohl recht. Je nach Frust-Level des Entwicklers sollte man die nicht öffentlich machen ;-)
Comment by Daniel Schilling
Von | 29.10.2011 21:11
Als WorkItem-Manager für TFS sollte man sich mal bei Telerik umschauen, eventuell kann das auch als Alternative für Artiso dienen: www.telerik.com/...Deren beide TFS-Tools sind kostenlos!