12

TFS2010 – Numéro de build dans les assemblies

Dans cet article, nous allons voir comment créer et utiliser une Custom Activity pour personnaliser notre build TFS. Pour cela, j’utilise un cas concret de projet dans lequel nous affichons pour les différentes applications le numéro de version de celle-ci. Cela nous permet de savoir à quel build correspond telle ou telle version … :

clip_image001

Actuellement ce numéro de version, est ni plus ni moins qu’une clé de configuration que l’on gère manuellement à chaque version. Nous avons également gérés le numéro de version au niveau du build via la propriété Build Number Format :

clip_image002

L’idéal serai donc d’associer ces deux mécanismes pour ne plus avoir à gérer manuellement ce numéro de version. Depuis que nous avons mis en place TFS et les build, je souhaitais donc automatiser la gestion des numéros de versions en le faisant correspondre au numéro de build. Le but étant, que lors d’un build, j’applique le numéro du build dans les fichier AssemblyInfo.cs pour les valeurs AssemblyVersion et AssemblyFileVersion :

clip_image003

A chaque build, je veux donc récupérer le Build Number et l’affecté à ces deux propriétés. Ce sont ensuite ces valeurs qui seront affichées dans le différentes applications. Pour cela nous allons devoir créer une Custom Activity pour notre template de build.

Ouvrez Visual Studio 2010 et créez un nouveau projet de type Class Library, nommez le par exemple BuildActivities. Ajoutez à ce projet les références suivantes :

  • System.Activities
  • Microsoft.TeamFoundation.Build.Client.dll (c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0)

Ensuite, ajoutez un fichier de type Code Activity. Pour cela, faire un clic droit sur le projet BuildActivities, sélectionnez Add, New Item… Puis dans la catégorie Workfflow sélectionnez Code Activity. Nommez votre classe AssemblyVersionNumber par exemple et cliquez sur Add :

clip_image004

Une fois votre Code Activity créée, on remarque qu’il s’agit simplement d’une classe qui hérite de CodeActivity.

Copier-coller le code suivant dans la classe :

[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class AssemblyVersionNumber : CodeActivity
{
    // The file mask of all files for which the buildnumber of the 
    // AssemblyVersion must be increased
    [RequiredArgument]
    public InArgument<string> AssemblyInfoFileMask { get; set; }

    // The SourcesDirectory as initialized in the Build Process Template
    [RequiredArgument]
    public InArgument<string> SourcesDirectory { get; set; }

    [RequiredArgument]
    public InArgument<IBuildDetail> CurrentBuild { get; set; }

protected override void Execute(CodeActivityContext context)
{
    // Obtain the runtime value of the input arguments
    string sourcesDirectory = context.GetValue(this.SourcesDirectory);
    string assemblyInfoFileMask = context.GetValue(this.AssemblyInfoFileMask);
    string buildNumber = this.CurrentBuild.Get(context).BuildNumber;

    // Enumerate over all version attributes
    foreach (string attribute in new string[] { "AssemblyVersion", "AssemblyFileVersion" })
    {
        // Define the regular expression to find (which is for example 'AssemblyVersion("1.0.0.0")' )
        Regex regex = new Regex(attribute + @"\(""\d+\.\d+\.\d+\.\d+""\)");
        // Get all AssemblyInfo files
        foreach (string file in Directory.EnumerateFiles(sourcesDirectory, assemblyInfoFileMask, SearchOption.AllDirectories))
        {
            // Remove readonly attribute to the file
            FileInfo myFile = new FileInfo(file);
            myFile.Attributes -= FileAttributes.ReadOnly;
            // Read the text from the AssemblyInfo file
            string text = File.ReadAllText(file);
            // Search for the first occurance of the version attribute
            Match match = regex.Match(text);
            // When found
            if (match.Success)
            {
                Version newVersion = new Version(buildNumber);
                // Replace the version number
                string newText = regex.Replace(text, attribute + "(\"" + newVersion.ToString() + "\")");
                // Write the new text in the AssemblyInfo file
                File.WriteAllText(file, newText);
            }
        }
    }
}
}

Ce code permet de récupérer tous les fichiers AssemblyInfo.cs spécifié via un paramètre en entrée, donc modifiable, puis grâce à une expression régulière récupère les informations de version pour les écraser par le numéro du build en cours.

Ensuite, il nous faut modifier notre template de build. Pour cela, créez un nouveau projet de type Class Library (nommé Template dans mon exemple) et ajoutez à ce projet le fichier XAML correspondant au template que vous utilisez. Ajoutez également une référence au projet précédent BuildActivities ainsi que les références suivantes :

  • Microsoft.TeamFoundation.Build.Client.dll (c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0)
  • Microsoft.TeamFoundation.VersionControl.Client.dll (c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0)
  • Microsoft.TeamFoundation.WorkItemTracking.Client.dll (c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0)
  • Microsoft.TeamFoundation.Build.Workflow.dll (C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies)
  • Microsoft.TeamFoundation.TestImpact.BuildIntegration.dll (C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies)
  • Microsoft.TeamFoundation.TestImpact.Client.dll (C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.TestImpact.Client\10.0.0.0__b03f5f7f11d50a3a)
  • System.Activities
  • System.Drawing
  • System.ServiceModel
  • System.ServiceModel.Activities
  • System.Xaml

clip_image005

Il faut également définir la propriété BuildAction du fichier XAML correspondant à votre template à XamlAppDef. Si vous ne voyez pas cette valeur dans la liste proposé, ajouter une nouvelle Activity au projet Template pour la faire apparaître.

Faire ensuite un build de la solution, puis ouvrez le fichier XAML. Dans le workflow, naviguez jusqu’à l’activité Get Workspace. Ouvrez la boîte à outil, vous voyez apparaitre dans la liste l’activité AssemblyVersionNumber précédemment créée :

clip_image006

Faites un glisser-déposer de celle-ci sous l’activité Get Workspace, pour obtenir ceci :

clip_image007

Remarque : Dans mon exemple, j’ai ajouter en premier une séquence dans laquelle j’ai ajouté mon activité. Mais ceci n’est pas obligatoire.

Il reste ensuite à configurer les paramètres de notre activité. Sélectionnez l’activité AssemblyVersionNumber et dans les Properties, entrez les valeurs suivantes :

  • AssemblyInfoFileMask : « AssemblyInfo.cs »
  • CurrentBuild : BuildDetail
  • SourcesDirectory : SourcesDirectory

clip_image008

Nous avons désormais notre Custom Activity ansi que notre template prêt. Archiver l’ensemble dans TFS. Vous devez également archiver la DLL contenant votre Custom Activity, c’est-à-dire dans notre exemple : BuildActivities.dll.

Ensuite vous devez spécifier à votre Controller le chemin vers votre Custom Activity. Pour cela, faire un clic droit sur Builds dans l’un de vos projets dans Team Explorer :

clip_image009

Sélectionnez le Controller et cliquez sur Properties :

clip_image010

Dans les propriétés, indiquer le chemin vers BuildActivities.dll : par exemple : $/Development/BuildActivities

clip_image011

Il faut également modifier le chemin vers le template XAML dans la définition de build de votre projet. Pour cela, faire un clic droit sur le build correspondant et sélectionnez Edit Build Definition… Dans la section Process, modifier le Build process template pour pointer vers celui que vous avez modifié :

clip_image012

Il ne reste plus qu’à lancer un nouveau build, clic droit, Queue New Build… pour vérifier le fonctionnement de notre Custom Activity :

clip_image013

Pour ceux qui sont intéressés par la personnalisation du build et les Custom Activity je vous conseil le vivement la série d’articles de Ewald Hofman :

http://www.ewaldhofman.nl/post/2010/04/20/Customize-Team-Build-2010-e28093-Part-1-Introduction.aspx

Vous pouvez également télécharger la solution utilisée comme exemple dans cet article ici : BuildActivitiesDemos.zip

gbrout

Architecte, formateur MCT et expert sur la gamme Visual Studio ALM qu'il met en œuvre sur l'ensemble des projets. Il travaille pour la société Itelios, spécialisée dans les technologies Microsoft et le commerce connecté. Il accompagne quotidiennement de nombreuses équipes et projets dans différents domaines et technologies : Windows 8, Windows Phone, ASP.NET MVC, Dynamics CRM... Passionné par le développement, ses domaines de prédilections sont avant tout l'expertise technique, l'industrialisation des développements avec la gamme Visual Studio ALM, l'analyse des performances, les tests et tout ce qui a trait à la qualité. Son expertise sur les  technologies Microsoft sa passion pour les nouvelles technologies et les développements novateurs l'a conduit à l'écriture d'un livre accessible et opérationnel sur le développement pour Windows 8 à l'aide d'HTML5 et JavaScript. Il anime également des conférences et sessions techniques telles que des live meeting en ligne ou lors d’événements comme les Techdays.

12 Commentaires

  1. Bonjour,

    Très intéressant comme poste, mais j’éprouve un problème d’intégration de mon defaultTemplate .xaml dans le projet.
    Serais t-il possible d’avoir accès à un exemple de code source complet (style format Zip) pour voir ce qui cloche. Mon erreur actuel est la suivante lors de la compilation du projet BuildActivities :

    Error 1 Unknown build error,  »clr-namespace:TfsBuild;’ mapping URI is not valid. Line 1 Position 1611.’ C:\test\Visual Studio 2010\Projects\BuildActivities\Template\DefaultTemplate.xaml 1 1611 Template

    Pour l’entête est bon, deplus ce template est actuellement utilisé sans modification.
    Merci pour l’aide.

    • This review is from: This was the second pair of these I’ve bought and I’ll keep buying them as long as Fox makes them. I go through at least two pairs of gloves a year and these provide great grip, thy8;#e217&re comfortable even after two hours of riding, and they breathe well too. Summer rides in the Mojave are rough, but these gloves make it bearable.

  2. Bonjour,

    J’ai ajouté à la fin de l’article un lien vers une archive .zip contenant les sources de l’exemple, vous pouvez également le récupérer ici : BuildActivitiesDemos.zip.

    Avez-vous bien définit le BuildAction à la valeur XamlAppDef sur votre fichier XAML correspondant à votre template ?

    Si vous rencontrez encore des soucis, n’hésitez pas à me contacter.

  3. Bonjour,
    en suivant votre post pas à pas je n’ai aucun pb pour créer mon activité, l’intégrée à mon template, etc

    Par contre, à l’exécution de mon build j’ai le problème suivant :
    Access to the path ‘C:\Builds\10\DemoTFS2010\monBuild\Sources\monPath\Properties\AssemblyInfo.cs’ is denied.

    Que je lance sur un agent dont le user est ‘network service’ ou sur un agent dont le user est un admin ne change rien.

    Une idée ?

  4. Re bonjour,

    j’ai résolu mon problème en modifiant un peu le code de AssemblyVersionNumber.cs :
    remplacement de

    // Remove readonly attribute to the file
    FileInfo myFile = new FileInfo(file);
    myFile.Attributes -= FileAttributes.ReadOnly;

    Par

    var fileAttributes = File.GetAttributes(solutionVersionFile);
    File.SetAttributes(solutionVersionFile, fileAttributes & ~FileAttributes.ReadOnly);

    et a la fin, restauration des attributs originaux
    File.SetAttributes(solutionVersionFile, fileAttributes);

  5. great put up, very informative. I wonder why the other experts of this
    sector do not notice this. You must proceed your writing.

    I’m sure, you have a huge readers’ base already!

  6. Posted on December 18, 2012 at 6:40 amWhen I pay a visit to this internet site there’s new things and enhanced might be capable to study from. Haha I’ve seasoned your supply code too many occasions to master how you’re performing factors so we could wear them my internet site. Thanks! I can teach you about strategies to simple.

  7. Ha, yes, we have had LOTS of rain here in Scotland! I’m glad you had enough for a bit of a swim. Over here, I would just like a teensy bit of sun – not too much though – cos I get too hot and then it’s no fun!

  8. Great post, Scott – and what wonderful comments you’ve inspired! They further the learning from your ideas about leading – and living – with soul.I am totally with you on this critical opportunity for us as players and leaders/coaches. Bringing one’s heart to work – and to interactions with co-workers and customers – is NOT the norm. However, we are immensely loyal to those organizations that allow their leaders and staff to do exactly that! (See Southwest Airlines, Ritz Carlton Hotels, 37signals, etc.)I can’t wait to see the next post -Cheers!C.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *