Comment puis-je incrémenter automatiquement la version d’assemblage C # via notre plateforme CI (Hudson)?

Mon groupe et moi-même sums horribles à incrémenter les numéros de version d’assemblage et nous expédions fréquemment des assemblages avec des versions 1.0.0.0. De toute évidence, cela provoque beaucoup de maux de tête.

Nous améliorons considérablement nos pratiques via notre plate-forme CI et j’aimerais vraiment l’installer pour incrémenter automatiquement les valeurs du fichier assemblyinfo.cs afin que les versions de nos assemblys soient automatiquement mises à jour avec les modifications du code dans cette assemblée.

J’avais auparavant configuré (avant de trouver Hudson ) un moyen d’incrémenter la valeur soit par msbuild soit par la ligne de commande ( msbuild ne me souviens plus), mais avec Hudson, cela msbuild jour le repository SVN et déclencherait une autre construction. Cela entraînerait une boucle infinie lente, car Hudson interroge SVN toutes les heures.

Avoir Hudson incrémenter le numéro de version est-il une mauvaise idée? Quelle serait une alternative pour le faire?

Idéalement, mes critères pour une solution seraient ceux qui:

  • Incrémente le numéro de build dans assemblyinfo.cs avant une construction
  • Incrémente uniquement le numéro de build dans les assemblys qui ont changé. Cela peut ne pas être possible car Hudson efface le dossier du projet à chaque fois qu’il fait une compilation
  • Valide l’assemblyinfo.cs modifié dans le référentiel de code (actuellement VisualSVN )
  • Ne provoque pas Hudson pour déclencher une nouvelle génération lors de la prochaine parsing des modifications

En travaillant cela dans ma tête, je pourrais facilement trouver une solution à la plupart de ces problèmes par le biais de fichiers de commandes / commandes, mais toutes mes idées amèneraient Hudson à déclencher une nouvelle version lors de la prochaine parsing. Je ne cherche pas quelqu’un pour tout faire pour moi, il suffit de me diriger dans la bonne direction, peut-être une technique pour amener Hudson à ignorer certains commits SVN, etc.

Tout ce que j’ai trouvé jusqu’à présent est juste un article expliquant comment obtenir le numéro de version automatiquement incrémenté, rien ne prend en compte une plateforme CI qui pourrait être transformée en une boucle infinie.

Une alternative simple consiste à laisser l’environnement C # incrémenter la version de l’assembly pour vous en définissant l’atsortingbut version sur major.minor.* (Comme décrit dans le modèle de fichier AssemblyInfo.)

Vous recherchez peut-être une solution plus complète.

EDIT (Réponse à la question dans un commentaire):

De AssemblyInfo.cs :

 // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] 

Voici ce que j’ai fait pour estampiller l’atsortingbut AssemblyFileVersion.

Suppression de AssemblyFileVersion de AssemblyInfo.cs

Ajoutez un nouveau fichier vide appelé AssemblyFileInfo.cs au projet.

Installez le jeu d’outils des tâches de la communauté MSBuild sur la machine de compilation hudson ou en tant que dépendance NuGet dans votre projet.

Editez le fichier de projet (csproj), c’est juste un fichier msbuild et ajoutez les éléments suivants.

Quelque part, il y aura un indiquant la version. Changer cela pour qu’il se lise par exemple

  1 0  $(BUILD_NUMBER) $(SVN_REVISION) 

Hudson fournit les variables env que vous voyez là quand le projet est construit sur hudson (en supposant qu’il soit extrait de subversion).

Au bas du fichier de projet, ajoutez

       

Cela utilise les MSBuildCommunityTasks pour générer le AssemblyFileVersion.cs pour inclure un atsortingbut AssemblyFileVersion avant la construction du projet. Vous pouvez le faire pour tous les atsortingbuts de version si vous le souhaitez.

Le résultat est que, chaque fois que vous émettez une version hudson, l’assembly obtenu reçoit un fichier AssemblyFileVersion de 1.0.HUDSON_BUILD_NR.SVN_REVISION, par exemple 1.0.6.2632, ce qui signifie que le 6ème build # dans hudson provient de la révision subversion 2632.

Voici une solution élégante qui nécessite un peu de travail lors de l’ajout d’un nouveau projet, mais qui traite le processus très facilement.

L’idée est que chaque projet est lié à un fichier Solution qui contient uniquement les informations de version de l’assembly. Ainsi, votre processus de compilation ne doit mettre à jour qu’un seul fichier et toutes les versions d’assemblage sont extraites d’un fichier lors de la compilation.

Pas:

  1. Ajouter une classe à votre fichier de solution * fichier .cs, j’ai nommé min SharedAssemblyProperties.cs
  2. Supprimer toutes les informations cs de ce nouveau fichier
  3. Coupez les informations d’assembly à partir d’un fichier AssemblyInfo: [assembly: AssemblyVersion (“1.0.0.0”)] [assembly: AssemblyFileVersion (“1.0.0.0”)]
  4. Ajoutez l’instruction “using System.Reflection;” dans le fichier, puis collez les données dans votre nouveau fichier cs (ex SharedAssemblyProperties.cs)
  5. Ajouter un élément existant à votre projet (patientez … lisez avant d’append le fichier)
  6. Sélectionnez le fichier et avant de cliquer sur Ajouter, cliquez sur le menu déroulant en regard du bouton Ajouter et sélectionnez “Ajouter en tant que lien”.
  7. Répétez les étapes 5 et 6 pour tous les projets existants et nouveaux dans la solution.

Lorsque vous ajoutez le fichier en tant que lien, il stocke les données dans le fichier de projet et, à la compilation, extrait les informations de la version de l’assembly de ce fichier.

Dans votre contrôle de source, vous ajoutez un fichier de chauve-souris ou un fichier de script qui incrémente simplement le fichier SharedAssemblyProperties.cs et tous vos projets mettront à jour leurs informations d’assemblage à partir de ce fichier.

Hudson peut être configuré pour ignorer les modifications apscopes à certains chemins et fichiers afin d’éviter toute nouvelle génération.

Sur la page de configuration du travail, sous Gestion du code source , cliquez sur le bouton Avancé . Dans la zone Régions exclues , vous entrez une ou plusieurs expressions régulières correspondant aux exclusions.

Par exemple, pour ignorer les modifications apscopes au fichier version.properties , vous pouvez utiliser:

 /MyProject/trunk/version.properties 

Cela fonctionnera pour les langues autres que C # et vous permettra de stocker vos informations de version dans Subversion.

.NET le fait pour vous. Dans votre fichier AssemblyInfo.cs, définissez votre version d’assembly sur major.minor. * (Par exemple: 1.0. *).

Lorsque vous créez votre projet, la version est générée automatiquement.

Les numéros de compilation et de révision sont générés en fonction de la date, en utilisant l’époque Unix, je crois. La version est basée sur le jour actuel et la révision est basée sur le nombre de secondes écastings depuis minuit.

Je n’ai jamais vu cette fonctionnalité 1.0. * Fonctionner dans VS2005 ou VS2008. Y a-t-il quelque chose à faire pour définir VS pour augmenter les valeurs?

Si AssemblyInfo.cs est codé en dur avec la version 1.0. *, Alors où sont stockés la version réelle / révision?

Après avoir mis 1.0. * Dans AssemblyInfo, nous ne pouvons pas utiliser l’instruction suivante car ProductVersion a désormais une valeur non valide – il utilise la version 1.0. * Et non la valeur atsortingbuée par VS:

 Version version = new Version(Application.ProductVersion); 

Soupir – cela semble être une de ces questions sur lesquelles tout le monde s’interroge, mais il n’ya jamais de réponse solide. Il y a des années, j’ai vu des solutions pour générer un numéro de révision et l’enregistrer dans AssemblyInfo dans le cadre d’un processus de post-construction. J’espérais que ce genre de danse ne serait pas nécessaire pour VS2008. Peut-être VS2010?

Je suppose que l’on pourrait également faire cela avec un modèle de texte où vous créez les atsortingbuts d’assemblage en question à la volée, comme le fait AssemblyVersion.tt ci-dessous.

 <#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".cs" #> <# var build = Environment.GetEnvironmentVariable("BUILD_NUMBER"); build = build == null ? "0" : int.Parse(build).ToString(); var revision = Environment.GetEnvironmentVariable("SVN_REVISION"); revision = revision == null ? "0" : int.Parse(revision).ToString(); #> using System.Reflection; [assembly: AssemblyVersion("1.0.<#=build#>.<#=revision#>")] [assembly: AssemblyFileVersion("1.0.<#=build#>.<#=revision#>")] 

Dans le prolongement de la réponse de MikeS, je voulais append que le SDK Visualization and Modeling de VS + Visual Studio doit être installé pour que cela fonctionne, et vous devez également modifier le fichier de projet. Doit également être mentionné, j’utilise Jenkins comme serveur de compilation fonctionnant sur une boîte de serveur Windows 2008 R2 avec le module de version, où je reçois le BUILD_NUMBER.

Mon fichier texte modèle version.tt ressemble à ceci

 <#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".cs" #> <# var build = Environment.GetEnvironmentVariable("BUILD_NUMBER"); build = build == null ? "0" : int.Parse(build).ToString(); var revision = Environment.GetEnvironmentVariable("_BuildVersion"); revision = revision == null ? "5.0.0.0" : revision; #> using System.Reflection; [assembly: AssemblyVersion("<#=revision#>")] [assembly: AssemblyFileVersion("<#=revision#>")] 

J’ai les éléments suivants dans les groupes de propriétés

  true true false  

après l’importation de Microsoft.CSharp.targets, j’ai ceci (dépendant de l’endroit où vous installez VS

  

Sur mon serveur de génération, j’ai le script suivant pour exécuter la transformation de texte avant la génération proprement dite, afin d’obtenir le dernier numéro de modifications sur TFS.

 set _Path="C:\Build_Source\foo" pushd %_Path% "%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe" history . /r /noprompt /stopafter:1 /Version:W > bar FOR /f "tokens=1" %%foo in ('findstr /R "^[0-9][0-9]*" bar') do set _BuildVersion=5.0.%BUILD_NUMBER%.%%foo del bar popd echo %BUILD_NUMBER% echo %_BuildVersion% cd C:\Program Files (x86)\Jenkins\jobs\MyJob\workspace\MyProject MSBuild MyProject.csproj /t:TransformAll ...  

De cette façon, je peux garder une trace des builds AND changesets, donc si je n’ai rien vérifié depuis la dernière version, le dernier chiffre ne devrait pas changer, cependant j’ai peut-être apporté des modifications au processus de compilation. . Bien sûr, si vous effectuez plusieurs archivages avant une construction, vous ne recevez que la dernière modification dans la version. Je suppose que vous pourriez concaténer cela est nécessaire.

Je suis sûr que vous pouvez faire quelque chose de plus sophistiqué et appeler TFS directement depuis le modèle tt, mais cela fonctionne pour moi.

Je peux alors obtenir ma version à l’exécution comme ceci

 Assembly assembly = Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); return fvi.FileVersion; 

Ma solution ne nécessite pas l’ajout d’outils externes ou de langages de script – c’est pratiquement garanti de fonctionner sur votre machine de génération. Je résous ce problème en plusieurs parties. Tout d’abord, j’ai créé un fichier BUILD.BAT qui convertit le paramètre Jenkins BUILD_NUMBER en une variable d’environnement. J’utilise la fonction “Execute Windows batch command” de Jenkins pour exécuter le fichier batch de compilation en entrant les informations suivantes pour la version Jenkins:

  ./build.bat --build_id %BUILD_ID% -build_number %BUILD_NUMBER% 

Dans l’environnement de génération, j’ai un fichier build.bat qui démarre comme suit:

  rem build.bat set BUILD_ID=Unknown set BUILD_NUMBER=0 :parse_command_line IF NOT "%1"=="" ( IF "%1"=="-build_id" ( SET BUILD_ID=%2 SHIFT ) IF "%1"=="-build_number" ( SET BUILD_NUMBER=%2 SHIFT ) SHIFT GOTO :parse_command_line ) REM your build continues with the environmental variables set MSBUILD.EXE YourProject.sln 

Une fois cela fait, j’ai cliqué avec le bouton droit sur le projet à construire dans le volet Explorateur de solutions de Visual Studio et sélectionné Propriétés, sélectionnez Générer des événements et entrez les informations suivantes en tant que ligne de commande d’événement de pré-génération. contenant des informations sur les numéros de build en fonction des parameters de variables d’environnement actuels:

  set VERSION_FILE=$(ProjectDir)\Properties\VersionInfo.cs if !%BUILD_NUMBER%==! goto no_buildnumber_set goto buildnumber_set :no_buildnumber_set set BUILD_NUMBER=0 :buildnumber_set if not exist %VERSION_FILE% goto no_version_file del /q %VERSION_FILE% :no_version_file echo using System.Reflection; >> %VERSION_FILE% echo using System.Runtime.ComstackrServices; >> %VERSION_FILE% echo using System.Runtime.InteropServices; >> %VERSION_FILE% echo [assembly: AssemblyVersion("0.0.%BUILD_NUMBER%.1")] >> %VERSION_FILE% echo [assembly: AssemblyFileVersion("0.0.%BUILD_NUMBER%.1")] >> %VERSION_FILE% 

Vous devrez peut-être vous adapter à votre goût de construction. Je construis le projet manuellement une fois pour générer un fichier Version.cs initial dans le répertoire Properties du projet principal. Enfin, j’inclus manuellement le fichier Version.cs dans la solution Visual Studio en le faisant glisser dans le volet Explorateur de solutions, sous l’onglet Propriétés de ce projet. Dans les versions futures, Visual Studio lit alors ce fichier .cs au moment de la génération Jenkins et obtient les informations de numéro de build correctes.

Nous avons donc un projet avec une solution qui contient plusieurs projets qui ont des assemblys avec des numéros de version différents.

Après avoir étudié plusieurs des méthodes ci-dessus, je viens d’implémenter une étape de génération pour exécuter un script Powershell qui effectue une recherche et remplacement sur le fichier AssemblyInfo.cs. J’utilise toujours le numéro de version 1.0. * Dans le contrôle de code source, et Jenkins met à jour manuellement le numéro de version avant que msbuild ne s’exécute.

 dir **/Properties/AssemblyInfo.cs | %{ (cat $_) | %{$_ -replace '^(\s*)\[assembly: AssemblyVersion\("(.*)\.\*"\)', "`$1[assembly: AssemblyVersion(`"`$2.$build`")"} | Out-File $_ -Encoding "UTF8" } dir **/Properties/AssemblyInfo.cs | %{ (cat $_) | %{$_ -replace '^(\s*)\[assembly: AssemblyFileVersion\("(.*)\.\*"\)', "`$1[assembly: AssemblyFileVersion(`"`$2.$build`")"} | Out-File $_ -Encoding "UTF8" } 

J’ai ajouté l’option -Encoding “UTF8” parce que git a commencé à traiter le fichier .cs comme un fichier binary si ce n’était pas le cas. Certes, cela n’a pas d’importance, puisque je ne commets jamais le résultat; il est juste venu comme je testais.

Notre environnement CI a déjà la possibilité d’associer la version de Jenkins au git commit (merci le plugin Stash!), Donc je ne m’inquiète pas du fait qu’il n’y ait pas de git commit avec le numéro de version qui lui est attaché.

C’est un mécanisme plus simple. Il implique simplement l’ajout d’une étape de génération de tâche de commande Windows Batch avant l’étape MSBuild et l’utilisation d’un simple programme de recherche et de remplacement (FART).

Le pas de lot

 fart --svn -r AssemblyInfo.cs "[assembly: AssemblyVersion(\"1.0.0.0\")]" "[assembly: AssemblyVersion(\"1.0.%BUILD_NUMBER%.%SVN_REVISION%\")]" if %ERRORLEVEL%==0 exit /b 1 fart --svn -r AssemblyInfo.cs "[assembly: AssemblyFileVersion(\"1.0.0.0\")]" "[assembly: AssemblyFileVersion(\"1.0.%BUILD_NUMBER%.%SVN_REVISION%\")]" if %ERRORLEVEL%==0 exit /b 1 exit /b 0 

Si vous utilisez un contrôle de source autre que svn, modifiez l’option –svn pour l’option appropriée pour votre environnement scm.

Télécharger Fart

J’ai décidé d’utiliser quelques méthodes en utilisant un script Powershell de pré-construction ( https://gist.github.com/bradjolicoeur/e77c508089aea6614af3 ) pour incrémenter à chaque génération réussie puis dans Global.asax.

  // We are using debug configuration, so increment our builds. if (System.Diagnostics.Debugger.IsAttached) { ssortingng version = System.Reflection.Assembly.GetExecutingAssembly() .GetName() .Version .ToSsortingng(); var psi = new ProcessStartInfo(@"svn", "commit -m \"Version: " + version + "\n \""); psi.WorkingDirectory = @"C:\CI\Projects\myproject"; Process.Start(psi); } 

Je pense toujours que tout le processus est trop compliqué et je vais chercher une méthode plus efficace pour obtenir le même résultat. Je voulais surtout que la version soit transmise à SVN, puis à Jenkin sans trop d’outils supplémentaires.