Configuration de la restauration de packages avec Team Foundation Build

Cet article explique pas à pas comment restaurer des packages dans Team Services Build pour la gestion de version Team Services et Git.

Cette procédure pas à pas est propre au scénario où Team Foundation Services est utilisé. Toutefois, les mêmes concepts s’appliquent aussi à d’autres systèmes de gestion de versions et de build.

S’applique à :

  • Projets MSBuild personnalisés exécutés sur n’importe quelle version de TFS
  • Team Foundation Server 2012 ou version antérieure
  • Modèles de processus Team Foundation Build personnalisés migrés vers TFS 2013 ou version ultérieure
  • Modèles de processus de génération sans la fonctionnalité de restauration Nuget

Si vous utilisez Visual Studio Team Services ou Team Foundation Server 2013 avec ses modèles de processus de génération, une restauration automatique des packages est effectuée dans le cadre du processus de génération.

Approche générale

L’utilisation de NuGet vous permet d’éviter l’archivage des fichiers binaires dans votre système de gestion de versions.

Ceci est particulièrement intéressant si vous utilisez un système de gestion de versions distribué tel que git, car les développeurs ont besoin de cloner l’intégralité du référentiel, y compris l’historique complet, avant de pouvoir travailler en local. L’archivage des fichiers binaires peut provoquer l’encombrement du référentiel, puisqu’ils sont généralement stockés sans compression delta.

NuGet prend en charge la restauration des packages dans le cadre de la génération depuis longtemps. L’implémentation précédente avait un problème du type « l’œuf ou la poule » pour les packages qui devaient étendre le processus de génération, car NuGet restaurait les packages lors de la génération du projet. Toutefois, MSBuild ne permet pas d’étendre la génération pendant la génération. Certains pourraient dire qu’il s’agit d’un problème MSBuild, mais je pense qu’il s’agit plutôt d’un problème inhérent. Selon ce que vous avez besoin d’étendre, vous ne pourrez plus inscrire votre package une fois la restauration effectuée.

Pour remédier à ce problème, la première étape du processus de génération est de vérifier que les packages sont restaurés :

nuget restore path\to\solution.sln

Lorsque votre processus de génération restaure des packages avant de générer le code, vous n’avez pas à archiver les fichiers .targets.

Remarque

Les packages doivent être associés à leur auteur afin de permettre leur chargement dans Visual Studio. Dans le cas contraire, vous pouvez toujours archiver les fichiers .targets pour que les autres développeurs puissent ouvrir la solution sans avoir à restaurer les packages.

Le projet de démonstration suivant montre comment configurer la génération de sorte que les dossiers packages et les fichiers .targets n’aient pas à être archivés. Il montre également comment configurer une génération automatique dans Team Foundation Service pour cet exemple de projet.

Structure des référentiels

Notre projet de démonstration est un outil en ligne de commande simple qui utilise l’argument de ligne de commande pour interroger Bing. Il cible .NET Framework 4 et utilise une grande partie des packages BCL (Microsoft.Net.Http, Microsoft.Bcl, Microsoft.Bcl.Async et Microsoft.Bcl.Build).

La structure du référentiel se présente ainsi :

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

Vous pouvez voir que nous n’avons pas archivé le dossier packages ni les fichiers .targets.

Nous avons, toutefois, archivé le fichier nuget.exe, car il est nécessaire pour le processus de génération. En suivant les conventions couramment utilisées, nous l’avons archivé dans un dossier tools partagé.

Le code source se trouve dans le dossier src. Notre démonstration utilise une seule solution. Toutefois, ce dossier pourrait tout à fait contenir plusieurs solutions.

Ignorer les fichiers

Remarque

Il existe actuellement un [known bug in the NuGet client](https://nuget.codeplex.com/workitem/4072) à cause duquel le client continue d’ajouter le dossierpackages à la gestion de version. Pour contourner ce problème, désactivez l’intégration du contrôle de code source. Vous aurez besoin pour cela d’un fichier Nuget.Config dans le dossier .nuget, parallèle à votre solution. Si ce dossier n’existe pas encore, créez-le. Dans Nuget.Config, ajoutez le contenu suivant :

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

Pour informer la gestion de version que notre intention n’est pas d’archiver les dossiers des packages, nous avons également ajouté une option « ignorer les fichiers » pour la gestion de version git (.gitignore) et Team Foundation (.tfignore). Ces fichiers décrivent les modèles des fichiers que vous ne souhaitez pas archiver.

Le fichier .gitignore se présente ainsi :

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

Le fichier .gitignore est très puissant. Par exemple, si vous ne souhaitez pas archiver le contenu du dossier packages, mais souhaitez archiver les fichiers .targets, vous pouvez utiliser la règle suivante :

packages
!packages/**/*.targets

Cela exclut tous les dossiers packages, mais inclut de nouveau tous les fichiers .targets contenus. Pour obtenir un modèle de fichier .gitignore conçu spécialement pour les besoins des développeurs Visual Studio, cliquez ici.

La gestion de versions Team Foundation prend en charge un mécanisme très similaire via le fichier .tfignore. La syntaxe est pratiquement la même :

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

build.proj

Pour notre démonstration, nous présentons un processus de génération relativement simple. Nous allons créer un projet MSBuild qui génère toutes les solutions en veillant à ce que les packages soient restaurés avant la génération des solutions.

Ce projet aura trois cibles conventionnelles (Clean, Build et Rebuild), ainsi qu’une nouvelle cible (RestorePackages).

  • Les cibles Build et Rebuild dépendent toutes les deux de RestorePackages. Vous avez ainsi la garantie de pouvoir exécuter Build et Rebuild, et de compter sur les packages en cours de restauration.
  • Clean, Build et Rebuild appellent la cible MSBuild correspondante dans tous les fichiers solution.
  • La cible RestorePackages appelle nuget.exe pour chaque fichier solution. Pour cela, utilisez la fonctionnalité de traitement par lots de MSBuild.

Le résultat ressemble à ce qui suit :

<?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>

Configuration de Team Build

Team Build propose divers modèles de processus. Pour cette démonstration, nous utilisons Team Foundation Service. Les installations locales de TFS sont cependant très similaires.

Les modèles Team Build sont différents pour Git et pour la gestion de versions Team Foundation. Par conséquent, les étapes suivantes vont varier selon le système de gestion de versions que vous utilisez. Dans les deux cas, vous avez seulement à sélectionner le fichier build.proj comme le projet que vous souhaitez générer.

Tout d’abord, examinons le modèle de processus pour git. Dans le modèle git, la génération est sélectionnée via la propriété Solution to build :

Build Process for git

Notez que cette propriété est un emplacement de votre référentiel. Étant donné que notre build.proj se trouve à la racine, nous avons simplement utilisé build.proj. Si vous placez le fichier de build dans un dossier appelé tools, la valeur sera tools\build.proj.

Dans le modèle de gestion de versions Team Foundation, le projet est sélectionné via la propriété Projects :

Build Process for TFVC

Contrairement au modèle git, le modèle de gestion de versions Team Foundation prend en charge les sélecteurs (le bouton situé à droite des trois points). Par conséquent, afin d’éviter les éventuelles erreurs de frappe, nous vous suggérons de les utiliser pour sélectionner le projet.