PowerShell-Build-Framework

Automatisiertes, lokales Erstellen von Visual-Studio-Projektmappen und Aufrufen externer Tools wie Unit-Tests, Quelltext-Commit, Obfuscation, digitale Signatur, Dateiveröffentlichung und -übertragung.

Bring bitte etwa 10 Minuten mit, um diese Seite in Ruhe zu lesen.

Dieses portable, anpassbare Build-Skript erstellt nicht nur eine Projektmappe. Es koordiniert vielmehr verschiedene Aufgaben, die bei einem Release-Build oder Commit oder zu anderen Anlässen durchzuführen sind. Das Framework besteht aus einigen Modulen, die bestimmte Themenbereiche abdecken, einer zentralen Funktionsbibliothek und einer projektspezifischen Steuerdatei (Beispiel unten). Um den Aufruf der einzelnen Szenarien zu vereinfachen, werden zusätzliche Windows-Batch-Dateien erstellt.

Ein paar beispielhafte Anwendungsfälle:

  • Einfache Erstellung eines Debug- oder Release-Builds (Alles neu erstellen)
  • Starten von Unit-Tests mit MSTest
  • Erstellung eines Setups mit Inno Setup
  • Digitales Signieren der erstellten Programmdateien sowie des Setups
  • Prüfen der Buildfähigkeit der Projektmappe vor einem Commit in Git oder Subversion (persönlicher gated check-in)
  • Zusammenstellen der letzten Änderungen aus Git oder Subversion in eine Changelog-Datei
  • Übertragen der erstellten Dateien in ein anderes Verzeichnis oder mit SFTP
  • Starten eines Code-Obfuscators

Diese Aufgaben werden einmal für das gesamte Projekt konfiguriert (siehe Beispiel unten) und können dann von jedem Entwickler auf dem lokalen Rechner ausgeführt werden, da die Build-Skripte als Teil des Projekts ins Code-Repository aufgenommen werden. Nicht benötigte Module können weggelassen werden (z. B. das svn-Modul in einem Git-Repository oder dotfuscator in einem Open-Source-Projekt).

  • Keine Installation (außer für aufzurufende Buildwerkzeuge)
  • Keine Umgebungskonfiguration
  • Keine Administratorberechtigung notwendig

Steuerung externer Werkzeuge

Die externen Programme, die für den jeweiligen Build-Schritt ausgeführt werden müssen, sucht dieses Skript selbstständig. MSBuild und MSTest werden je nach zu erstellender Plattformkonfiguration aus dem .NET-Verzeichnis gewählt. Das Installationsverzeichnis von Inno Setup und der Git-/Subversion-Tools wird aus der Registry ermittelt. Es genügt also, die erforderlichen Programme regulär zu installieren – danach stehen sie automatisch für Buildaufgaben zur Verfügung. Lediglich kleine, portable Tools werden direkt im Repository abgelegt. Dazu zählen insbesondere FlashConsoleWindow und NetRevisionTool, die besonders stark in das Skript integriert sind, oder PdbConvert von FieldLog.

Dazu gibt es eine Fortschrittsanzeige, die in der Taskleiste dargestellt wird. So ist bei vielen Vorgängen auch der ungefähre Fortschritt erkennbar. Damit das funktioniert, muss für jeden Schritt der Zeitbedarf in Sekunden angegeben werden. Je nach ausgewähltem Szenario wird dann die erwartete Builddauer summiert. Tritt bei einem Teilschritt ein Fehler auf, wird die rote Markierung angezeigt und das Skript abgebrochen. Das Konsolenfenster bleibt dann geöffnet, damit man die Fehlermeldung lesen kann. Hat alles funktioniert, bleibt die grüne Markierung sichtbar und das Fenster schließt sich nach einer Weile selbst, man muss also gar nicht ins Fenster schauen.

Module

Die folgenden Module sind derzeit enthalten:

  • dotfuscator: Startet Dotfuscator CLI (getestet mit Community Edition in VS 2010 mit CLI-Update)
  • file: Erstellt Archive (mit 7-Zip), kopiert und löscht Dateien, startet externe Programme
  • git: Commit, Export einer sauberen Kopie, fasst Commit-Messages zusammen (mit TortoiseGit)
  • innosetup: Startet Inno Setup und erstellt Installationspakete
  • msbuild: Startet MSBuild und erstellt Visual-Studio-Projektmappen
  • mstest: Startet MSTest und führt Unit-Tests aus
  • nuget: Erstellt und veröffentlicht NuGet-Pakete
  • pdbconvert: Konvertiert .pdb-Dateien mit FieldLog PdbConvert
  • seeunsharp: Startet SeeUnsharp .NET Obfuscator
  • sign: Digitale Signatur von Dateien
  • ssh: Überträgt Dateien über SFTP (mit PuTTY pscp)
  • svn: Commit, Export einer sauberen Kopie, fasst Commit-Messages zusammen (mit TortoiseSVN)

Eigene Module können problemlos nach Vorlage der bestehenden Dateien erstellt werden. Dateien im modules-Verzeichnis werden automatisch verwendet. Alle Commandlets, die in den verfügbaren Modulen definiert werden, können in der Steuerdatei aufgerufen werden. Eine spezielle Registrierung findet nicht statt.

Wenn du ein interessantes Modul geschrieben oder ein vorhandenes erweitert hast, würde ich mich über deine Rückmeldung freuen, um es vielleicht in dieser Distribution mit aufzunehmen. Es gibt noch viele zu unterstützende Tools: NUnit, Mercurial, TFS/TFVC, SHFB, NDoc, StyleCop, FxCop, InstallShield…

Kompatibilität: Windows 10 Windows 8 Windows 7 Windows XP 64 bit

Wann brauche ich dieses Framework?

Wenn deine Projektmappe nur ein oder wenige Projekte enthält und daneben keine weiteren Werkzeuge zum Einsatz kommen, kann dir dieses Framework kaum helfen. Sobald du aber außerhalb von Visual Studio ein Setup generierst, Unit-Tests durchführst oder mit anderen Entwicklern und einer Quelltextverwaltung arbeitest, automatisiert dieses Framework wiederkehrende Aufgaben. So werden Fehler frühzeitig erkannt, Release-Builds laufen vorhersagbar ab und kein Schritt wird in der Hektik vergessen.

Wenn Post-Build-Ereignisse in Visual Studio unübersichtlich und unhandlich werden, bringt das Build-Skript flexible Ordnung zurück. Das Zusammenfassen von Commit-Logs zu Change-Logs und das Einpacken bestimmter Dateien nach einem Build oder die Übertragung in lokale und entfernte Verzeichnisse („Continuous Delivery“) können ebenfalls automatisiert werden.

Außerdem funktioniert das Skript auch auf einem Buildserver gut, um alles in der richtigen Reihenfolge auszuführen, ohne es erneut zu konfigurieren. Änderungen an der Projektstruktur werden mit dem Einchecken des neuen Build-Skripts automatisch auf den Buildserver übernommen. Getestet wird es vorher, auf dem Entwickler-PC.

Installation

Die Einrichtung des Build-Frameworks in einem Projekt ist sehr einfach. Es werden nur Dateien entpackt und ausgewählt und die projektspezifische Steuerdatei angepasst.

  1. Die im Download enthaltenen Dateien müssen ins Projektmappenverzeichnis entpackt werden, am besten mit der enthaltenen Verzeichnisstruktur (unten abgebildet). Bei Abweichungen in Verzeichnisnamen oder -tiefe müssen Änderungen am Skript vorgenommen werden.
  2. Verwendete portable Tools können ins Verzeichnis _scripts\bin verschoben werden.
  3. Die Steuerdatei _scripts\buildscript\control.ps1 muss angepasst werden, so dass die erforderlichen Build-Schritte und -Konfigurationen ausgeführt werden. Als Vorlage kann die im Download enthaltene Datei verwendet werden.
  4. Für jede Konfiguration sollte eine Batch-Datei im Verzeichnis _scripts angelegt werden. Im Download sind bereits mehrere gebräuchliche Dateien enthalten.

Der automatisierte Softwarebuild ist jetzt eingerichtet und kann durch Starten der gewünschten Batch-Datei gestartet werden. Der folgende Verzeichnisbaum stellt die empfohlene Struktur dar:

  • Projektmappenverzeichnis
    • _scripts
      • bin
        • FlashConsoleWindow.exe
        • NetRevisionTool.exe
        • (weitere portable Tools)
      • buildscript
        • modules
          • git.ps1
          • msbuild.ps1
          • (weitere Framework-Module)
        • control.ps1
        • (private.ps1)
        • psbuild.ps1
      • build_debug.cmd
      • build_release_setup.cmd
      • commit.cmd
      • publish.cmd
      • (weitere Batch-Dateien)
    • Projekt 1
    • Projekt 2
    • Projektmappe.sln

Optional kann jetzt noch der Button in der Visual-Studio-Symbolleiste eingerichtet werden, wie im nächsten Absatz beschrieben. (Das wirkt sich auf die lokale Visual-Studio-Umgebung aus und gilt für alle Projekte. Der Button wird natürlich nur dort funktionieren, wo die angegebene Batch-Datei existiert.)

Build & Commit per Toolbar

Dadurch, dass bestimmte Buildvorgänge per Batchdatei von jedem Entwickler lokal durchgeführt werden können, lässt sich auch ein nützliches Skript zum Einchecken von Änderungen in der Versionsverwaltung umsetzen. Die Datei commit.cmd gibt es mittlerweile in all meinen Projekten, die dieses Framework einsetzen. Passend dazu habe ich dieses Skript in Visual Studio als externes Tool eingetragen und eine zusätzliche Symbolleiste mit einem Button „Build & Commit“ angelegt, der das Skript aufruft. Somit wird vor jedem Commit geprüft, ob auch die komplette Projektmappe (inkl. deaktivierter Projekte und Setup) übersetzbar ist und die Projektmappen- und Projektdateien gespeichert sind. Das ist auch ein guter Platz für schnelle Unit-Tests.

Nachdem ich eine Aufgabe fertig bearbeitet habe, kann ich einfach diesen Knopf drücken, um den Build geprüft und alle Änderungen angezeigt zu bekommen. Änderungen kurz durchschauen, Commit-Message schreiben, fertig.

Screenshot der Visual-Studio-Toolbar „Build & Commit“

Die Toolbar und das externe Tool können manuell eingerichtet werden, wie folgt beschrieben. Ich habe auch eine VSSettings-Datei vorbereitet, die diese Schritte fast vollständig automatisiert. Beim Import ist unbedingt darauf zu achten, dass alle Abschnitte importiert werden, auch die mit dem Warnsymbol. Anschließend muss der neue Befehl noch an den Anfang der Liste verschoben werden, da Schaltflächen für externe Tools leider nur nach Listenposition angelegt werden können und nicht nach Namen. Der Dialog befindet sich im Menü „Extras; Externe Tools…“.

psbuild-commit.vssettings2,6 KiBVisual-Studio-Toolbar mit dem „Build & Commit“-Befehl (VS 2010–2015)

Externes Tool, Titel: Build && Commit
Befehl: $(SolutionDir)_scripts\commit.cmd
Optionen: Ausgabefenster verwenden
Position: An die erste Stelle verschieben
Symbolleiste, Kategorie: Extras
Befehl: Externer Befehl 1

Der Commit wird für Git und SVN mit dem Tortoise-GUI durchgeführt, was insbesondere bei SVN das zurückgebliebene Ankh-GUI umgeht und auch Dateien außerhalb der Projektmappe erfasst. Um bei SVN-Arbeitsverzeichnissen inkonsistente Versionen zu verhindern, wird nach dem SVN-Commit gleich ein Update durchgeführt. (Bei Git ist dieser Hack nicht erforderlich.)

Beispiel

Die folgende Steuerdatei stammt aus dem FieldLog-Projekt und zeigt das Erstellen der Projektmappe und des Setups und das digitale Signieren sowie weitere Programmaufrufe. (Hier gekürzt, die vollständige Datei ist im Download enthalten.) Dafür werden die Module file, git, innosetup, msbuild, nuget und sign verwendet. Die Angaben zum Zertifikat und NuGet-Upload sind in einer privaten Datei gespeichert, das nicht im Repository eingecheckt ist. Hinweise zur Verwendung sind bei den betreffenden Funktionen dokumentiert.

Einstiegspunkt ist psbuild.ps1, diese Datei wird aus den Batch-Dateien gestartet. control.ps1 wird daraus eingebunden. Nach ein paar allgemeinen Metadaten wie dem Programmnamen und der Version werden direkt die Befehle der jeweiligen durchzuführenden Vorgänge aufgerufen. Diese können mit Bedingungen auf einzelne Konfigurationen eingeschränkt werden. Diese Einteilung ist per PowerShell-Code frei programmierbar. Befehle für mehrere Konfigurationen können durch passende Bedingungen gemeinsam genutzt werden. Die meisten Pfadangaben werden relativ zum Projektmappenverzeichnis ($rootDir) gemacht.

Die Befehle sammeln allerdings zunächst nur alle Parameter und speichern sie in einer Liste. Erst mit dem Aufruf von End-BuildScript wird diese Liste abgearbeitet. Dadurch steht die Gesamtzeit und der aktuelle Fortschritt zur Verfügung. Das bedeutet aber auch, dass nicht beliebige Befehle im Build-Ablauf aufgerufen werden können (die werden sofort ausgeführt), es müssen Funktionen aus einem der Module sein.

Ausführliche Beschreibungen der einzelnen Befehle sind in den Kommentaren der Moduldateien über jeder Funktion angegeben. Dort sind auch die Anforderungen dokumentiert, die zur Ausführung eines Befehls erfüllt sein müssen.

# PowerShell build framework
# Project-specific control file

Begin-BuildScript "FieldLog"

# Find revision format from the source code, require Git checkout
Set-VcsVersion "" "/require git"

# FieldLog.*NET* projects are overlapping, don't build them in parallel
Disable-ParallelBuild

# Debug builds
if (IsSelected "build-debug")
{
    Build-Solution "FieldLog.sln" "Debug" "Any CPU" 8
}

# Release builds
if ((IsSelected "build-release") -or (IsSelected "commit") -or (IsSelected "publish"))
{
    Build-Solution "FieldLog.sln" "Release" "Any CPU" 8
   
    if ((IsSelected "sign-app") -or (IsSelected "publish"))
    {
        Sign-File "...\bin\Release\FieldLogViewer.exe" "$signKeyFile" "$signPassword" 1
        Sign-File "PdbConvert\bin\Release\PdbConvert.exe" "$signKeyFile" "$signPassword" 1
    }

    Create-NuGet "FieldLog\Unclassified.FieldLog.nuspec" "FieldLog\bin" 2
}

# Release setups
if ((IsSelected "setup-release") -or (IsSelected "commit") -or (IsSelected "publish"))
{
    Create-Setup "Setup\FieldLog.iss" Release 1

    if ((IsSelected "sign-setup") -or (IsSelected "publish"))
    {
        Sign-File "Setup\bin\FieldLogSetup-$revId.exe" "$signKeyFile" "$signPassword" 1
    }
}

# Install release setup
if (IsSelected "install")
{
    Exec-File "Setup\bin\FieldLogSetup-$revId.exe" "/norestart /verysilent" 1
}

# Commit to repository
if (IsSelected "commit")
{
    # Clean up test build files
    Delete-File "Setup\bin\FieldLogSetup-$revId.exe" 0
    Delete-File ".local\FieldLog-$revId.pdbx" 0

    Git-Commit 5
}

# Prepare publishing a release
if (IsSelected "publish")
{
    Git-Log ".local\FieldLogChanges.txt" 1
}

# Upload to NuGet
if (IsSelected "transfer-nuget")
{
    Push-NuGet "FieldLog\bin\Unclassified.FieldLog" $nuGetApiKey 45
}

End-BuildScript

Download

master.zipAktueller Quelltext mit allen Modulen direkt von GitHub

Es gibt ein öffentliches Git-Repository von psbuild bei GitHub. Dort sind auch Änderungen am Code dokumentiert.

Warum PowerShell?

Dieses Skript ist in PowerShell geschrieben, weil es auf allen Windows-Systemen verfügbar ist und komplexere Aufgaben (Registry-Daten verarbeiten, XML-Programmausgaben parsen usw.) erheblich einfacher ermöglicht als Batch-Dateien. Gleichzeitig wollte ich das Skript offen und anpassbar halten, so dass man bei Bedarf schnell Änderungen vornehmen kann. Deshalb ist es kein geschlossenes Binary. Außerdem ist die Steuerdatei immer projektspezifisch, und da sie ebenfalls in PowerShell geschrieben ist, brauche ich keinen separaten Konfigurationsparser für all die benötigten Bedingungen.

Anfang 2013 hatte ich für ein Projekt ein einfaches Build-Skript als Batch-Datei aus Altbeständen eingerichtet, das bereits MSBuild, Inno Setup und Dotfuscator CLI gefunden und aufgerufen hat. Es sollte bei allen Entwicklern einfach und ohne weitere Einrichtung die erforderlichen Build- und Packaging-Schritte ausführen. Gerade der Registry-Zugriff war aber so unelegant, dass daraus bereits wenige Tage später ein PowerShell-Skript entstand, das besser wartbar war. Über das Jahr 2014 kamen etliche Erweiterungen dazu, die später in Module aufgeteilt wurden. Anfang 2015 wurde dieses Skript als eigenes Projekt aufbereitet, von überflüssigem Code befreit, vollständig dokumentiert und veröffentlicht. Das erleichtert auch die Aktualisierung in allen Projekten.

Lizenz und Nutzungsbedingungen

Vervielfältigung und Weiterverbreitung dieser Datei, verändert oder unverändert, sind gestattet, vorausgesetzt die Urheberrechtsangabe und dieser Hinweis bleiben erhalten. Diese Datei wird wie vorliegend ohne jegliche Garantie oder Gewährleistung angeboten. (GNU All-Permissive-Lizenz)

Statistische Daten

  • Erstellt am 2013-02-01, aktualisiert am 2016-01-28.
  • Ca. 1 300 Codezeilen, geschätzte Ent­wick­lungs­kos­ten: 1 300 - 5 200 €