Einrichten der Paketwiederherstellung mit Team Foundation Build

Im folgenden Artikel wird ausführlich beschrieben, wie Sie Pakete sowohl für Git als auch jeweils für Git und die Team Services-Versionskontrolle im Rahmen von Team Services Build wiederherstellen.

Obwohl sich die Beschreibungen auf Visual Studio Team Services-Szenarios beziehen, gelten die Konzepte auch für andere Build- und Versionskontrollsysteme.

Gilt für:

  • Benutzerdefinierte MSBuild-Projekte in einer beliebigen Version von TFS
  • Team Foundation Server 2012 oder früher
  • Benutzerdefinierte TFS-Buildprozessvorlagen, die zu TFS 2013 oder höher migriert wurden
  • Buildprozessvorlagen ohne Funktionen zur NuGet-Wiederherstellung

Wenn Sie Visual Studio Team Services oder Team Foundation Server 2013 mit Buildprozessvorlagen verwenden, erfolgt die automatische Paketwiederherstellung im Zuge des Buildprozesses.

Allgemeine Vorgehensweise

Ein Vorteil beim Verwenden von NuGet besteht darin, dass Sie Binärdateien nicht im Versionskontrollsystem einchecken müssen.

Dies ist besonders dann von Interesse, wenn Sie ein System für die verteilte Versionskontrolle wie z.B. Git verwenden, da Entwickler das gesamte Repository klonen müssen, der gesamte Verlauf inbegriffen, bevor sie lokal daran arbeiten können. Das Einchecken von Binärdateien kann zu erheblicher Repositoryüberfrachtung führen, da Binärdateien normalerweise ohne Deltakompression gespeichert werden.

NuGet unterstützt das Wiederherstellen von Paketen im Rahmen eines Builds mittlerweile schon sehr lange. Bei der vorherigen Implementierung bestand ein Henne-Ei-Problem bei Paketen, die den Buildprozess erweitern wollten, da NuGet Pakete während der Erstellung des Projekts wiederhergestellt hat. MSBuild erlaubt jedoch das Erweitern des Builds während des Buildvorgangs nicht. Hier kann man nun sagen, dass es sich um ein Problem in MSBuild handelt, ich bin jedoch der Meinung, dass dies ein inhärentes Problem ist. Je nachdem welchen Aspekt sie erweitern müssen, kann es unter Umständen für die Registrierung zu spät sein, wenn Ihr Paket wiederhergestellt wurde.

Stellen Sie sicher, dass Pakete als allererstes im Buildprozess wiederhergestellt werden, um dieses Problem zu umgehen:

nuget restore path\to\solution.sln

Wenn Ihr Buildprozess Pakete wiederherstellt, bevor der Code erstellt wird, müssen Sie keine .targets-Dateien einchecken.

Hinweis

Pakete müssen erstellt werden, um ein Laden in Visual Studio zu ermöglichen. Andernfalls sollten Sie .targets-Dateien weiterhin einchecken, damit andere Entwickler die Projektmappe problemlos öffnen können, ohne die Pakete zuerst wiederherstellen zu müssen.

In folgendem Beispielprojekt wird gezeigt, wie Sie den Build so einrichten, dass die Ordner packages und die Dateien .targets nicht eingecheckt werden müssen. Zudem wird veranschaulicht, wie Sie einen automatisierten Build in Team Foundation Service für dieses Beispielprojekt einrichten.

Repositorystruktur

Das Beispielprojekt ist ein einfaches Befehlszeilentool, in dem Befehlszeilenargumente verwendet werden, um Abfragen in Bing durchzuführen. .NET Framework 4 wird als Ziel verwendet. Darüber hinaus werden BCL-Pakete (Microsoft.Net.Http, Microsoft.Bcl, Microsoft.Bcl.Async und Microsoft.Bcl.Build) eingesetzt.

Die Struktur des Repositorys sieht folgendermaßen aus:

<Project>
    │   .gitignore
    │   .tfignore
    │   build.proj
    │
    ├───src
    │   │   BingSearcher.sln
    │   │
    │   └───BingSearcher
    │       │   App.config
    │       │   BingSearcher.csproj
    │       │   packages.config
    │       │   Program.cs
    │       │
    │       └───Properties
    │               AssemblyInfo.cs
    │
    └───tools
        └───NuGet
                nuget.exe

Weder die packages-Ordner noch die .targets-Dateien wurden eingecheckt.

Allerdings wurde die Datei nuget.exe eingecheckt, da sie während des Builds benötigt wird. Wir befolgen gebräuchliche Konventionen und haben sie unter einem freigegebenen tools-Ordner eingecheckt.

Der Quellcode befindet sich im Ordner src. Obwohl in unserem Beispiel nur eine Projektmappe verwendet wird, kann dieser Ordner selbstverständlich mehr als eine Projektmappe beinhalten.

Dateien ignorieren

Hinweis

Derzeit gibt es einen bekannten [known bug in the NuGet client](https://nuget.codeplex.com/workitem/4072) im NuGet-Client, der dazu führt, dass der Client den packages-Ordner trotzdem zur Versionskontrolle hinzufügt. Deaktivieren Sie die Integration der Quellcodeverwaltung, um dieses Problem zu umgehen. Dafür benötigen Sie eine Nuget.Config -Datei in dem Ordner .nuget, der sich auf derselben Ebene wie Ihre Projektmappe befindet. Wenn dieser Ordner noch nicht vorhanden ist, müssen Sie ihn erstellen. Fügen Sie in Nuget.Config Folgendes hinzu:

<configuration>
    <solution>
        <add key="disableSourceControlIntegration" value="true" />
    </solution>
</configuration>

Es wurden auch IGNORE-Dateien für Git (.gitignore) und Team Foundation-Versionskontrolle (.tfignore) hinzugefügt, um der Versionskontrolle mitzuteilen, dass der packages-Ordner nicht eingecheckt werden sollen. Diese Dateien beschreiben Dateimuster, die Sie nicht einchecken möchten.

Die .gitignore-Datei sieht folgendermaßen aus:

syntax: glob
*.user
*.suo
bin
obj
packages
*.nupkg
project.lock.json
project.assets.json

Die .gitignore-Datei ist leistungsstark. Wenn Sie z.B. prinzipiell keine Inhalte des packages-Ordners einchecken, aber das vorherige Eincheckverhalten von .targets-Dateien beibehalten möchten, können Sie stattdessen folgende Regel verwenden:

packages
!packages/**/*.targets

Dadurch werden alle packages-Ordner ausgeschlossen, aber alle beinhalteten .targets-Dateien eingeschlossen. Eine Vorlage für .gitignore-Dateien, die speziell auf die Bedürfnisse von Visual Studio-Entwicklern zugeschnitten ist, finden Sie hier.

Team Foundation-Versionskontrolle unterstützt mit der TFIGNORE-Datei einen ähnlichen Mechanismus. Die Syntax ist praktisch die gleiche:

*.user
*.suo
bin
obj
packages
*.nupkg
project.lock.json
project.assets.json

build.proj

In unserem Beispiel wird der Buildvorgang recht einfach gehalten. Es wird ein MSBuild-Projekt erstellt, in dem alle Projektmappen erstellt werden, während gleichzeitig sichergestellt wird, dass Pakete vor dem Erstellen der Projektmappe wiederhergestellt werden.

Dieses Projekt weist drei konventionelle Ziele auf (Clean, Build und Rebuild) sowie ein neues (RestorePackages).

  • Die Ziele Build und Rebuild sind von RestorePackages abhängig. Dadurch wird sichergestellt, dass Sie Build und Rebuild ausführen können, während Pakete wiederhergestellt werden.
  • Clean, Build und Rebuild rufen das entsprechende MSBuild-Ziel für alle Projektmappendateien auf.
  • Das RestorePackages-Ziel ruft nuget.exe für jede Projektmappendatei auf. Dies erfolgt durch die Batchverarbeitungsfunktion von MSBuild.

Daraus ergibt sich folgendes Ergebnis:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0"
            DefaultTargets="Build"
            xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
    <OutDir Condition=" '$(OutDir)'=='' ">$(MSBuildThisFileDirectory)bin\</OutDir>
    <Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
    <SourceHome Condition=" '$(SourceHome)'=='' ">$(MSBuildThisFileDirectory)src\</SourceHome>
    <ToolsHome Condition=" '$(ToolsHome)'=='' ">$(MSBuildThisFileDirectory)tools\</ToolsHome>
    </PropertyGroup>

    <ItemGroup>
    <Solution Include="$(SourceHome)*.sln">
        <AdditionalProperties>OutDir=$(OutDir);Configuration=$(Configuration)</AdditionalProperties>
    </Solution>
    </ItemGroup>

    <Target Name="RestorePackages">
    <Exec Command="&quot;$(ToolsHome)NuGet\nuget.exe&quot; restore &quot;%(Solution.Identity)&quot;" />
    </Target>

    <Target Name="Clean">
    <MSBuild Targets="Clean"
                Projects="@(Solution)" />
    </Target>

    <Target Name="Build" DependsOnTargets="RestorePackages">
    <MSBuild Targets="Build"
                Projects="@(Solution)" />
    </Target>

    <Target Name="Rebuild" DependsOnTargets="RestorePackages">
    <MSBuild Targets="Rebuild"
                Projects="@(Solution)" />
    </Target>
</Project>

Konfigurieren von Team Build

Team Build stellt verschiedene Prozessvorlagen bereit. In diesem Beispiel wird Team Foundation Service verwendet. Lokale Installationen von TFS unterscheiden sich nur geringfügig.

Git und Team Foundation-Versionskontrolle verfügen über unterschiedliche Team Build-Vorlagen. Die folgenden Schritte unterscheiden sich je nach verwendetem Versionskontrollsystem. In beiden Fällen müssen Sie nur „build.proj“ als zu erstellendes Projekt auswählen.

Sehen wir uns zunächst die Prozessvorlage für Git an. In der gitbasierten Vorlage wird der Build über die Eigenschaft Solution to build ausgewählt:

Build Process for git

Beachten Sie, dass diese Eigenschaft sich auf eine Stelle in Ihrem Repository bezieht. Da sich build.proj im Stamm befindet, haben wir build.proj verwendet. Wenn Sie die Builddatei in einem tools-Ordner befindet, ist der Wert tools\build.proj.

In der Team Foundation-Versionskontrollvorlage wird das Projekt mit der Eigenschaft Projects ausgewählt:

Build Process for TFVC

Im Gegensatz zur gitbasierten Vorlage unterstützt Team Foundation-Versionskontrolle Auswahlen (die Schaltfläche rechts mit den drei Punkten). Es wird empfohlen, diese für die Projektauswahl zu verwenden, um Tippfehler zu vermeiden.