Meilleures pratiques / conseils pour la maintenance des numéros de version d’assemblage

Je recherche des pointeurs, des suggestions et même des dictées sur la façon de gérer les trois numéros de version d’assemblage différents pour un assembly .NET. La version du produit est la plus simple, car cela semble normalement être dicté par les entresockets. Ensuite, la version du fichier semble être destinée au contrôle de version entre les déploiements, où la version d’assemblage réelle est utilisée uniquement lors de l’expédition.

En ce moment, je cherche simplement un moyen simple d’étiqueter les versions de test et de maintenance d’un assemblage dont aucun ne dépend, donc je regarde les numéros de révision et de construction auto-incrémentés sur la version du fichier et la version finale, en copiant le courant. version du fichier à la version d’assemblage. Le produit est utilisé en production, mais est toujours en développement – vous savez – une de ces petites entresockets, aucune situation d’infrastructure de contrôle des changements.

Le contrôle de version est quelque chose qui me passionne énormément et qui a longtemps essayé de concevoir un système de gestion des versions facile à utiliser. D’après ce que vous avez déjà dit dans votre question, il est clair que vous avez compris un point important, les numéros de version d’assemblage ne sont pas synonymes de la version du produit. L’un est piloté techniquement et l’autre par l’entreprise.

Ce qui suit suppose que vous utilisez une forme de contrôle de code source et un serveur de génération. Pour le contexte, nous utilisons TeamCity et Subversion / Git. TeamCity est gratuit pour un petit nombre de projets (10) et est un très bon serveur de compilation, mais il y en a d’autres, dont certains sont entièrement gratuits.

Qu’est-ce qu’un numéro de version signifie

Qu’est-ce qu’une version signifie pour une personne peut signifier quelque chose de différent à une autre, la structure générale est majeure, mineure, macro, micro. La façon dont je regarde un numéro de version est de le décomposer en deux parties. Le premier semestre décrit la version principale (Major) et les principales mises à jour (Minor). La seconde moitié indique quand elle a été construite et quelle était la version du code source. Les numéros de version signifient également des choses différentes selon le contexte, est-ce une API, une application Web, etc.

Major . Minor Build . Revision

  • Revision C’est le nombre pris du contrôle de la source pour identifier ce qui a été réellement construit.
  • Build C’est un nombre toujours croissant qui peut être utilisé pour trouver une version particulière sur le serveur de génération. C’est un nombre important car le serveur de génération peut avoir créé la même source deux fois avec un ensemble de parameters différent. L’utilisation du numéro de build avec le numéro source vous permet d’identifier ce qui a été construit et comment.
  • Minor Cela ne devrait changer que lorsqu’il y a un changement significatif de l’interface publique. Par exemple, s’il s’agit d’une API, la consommation de code pourrait-elle encore être compilée? Ce nombre doit être remis à zéro lorsque le nombre majeur change.
  • Major indique quelle version du produit vous utilisez. Par exemple, le majeur de tous les assemblys VisualStudio 2008 est 9 et VisualStudio 2010 est 10.

L’exception à la règle

Il y a toujours des exceptions à la règle et vous devrez vous adapter lorsque vous les rencontrerez. Mon approche originale était basée sur l’utilisation de subversion mais récemment je suis passé à Git. Les contrôles de source tels que subversion et source safe qui utilisent un référentiel central ont un numéro qui peut être utilisé pour identifier un ensemble particulier de sources à un moment donné. Ce n’est pas le cas pour un contrôle de source dissortingbué tel que Git. Comme Git utilise des référentiels dissortingbués qui se trouvent sur chaque machine de développement, il n’y a pas de numéro auto-incrémenté que vous pouvez utiliser, il y a un hack qui utilise le nombre de check-ins mais c’est laid. Pour cette raison, j’ai dû faire évoluer mon approche.

Major Minor Macro Build

Le numéro de révision a maintenant disparu, la construction a été déplacée vers la version de la révision et la macro a été insérée. Vous pouvez utiliser la macro comme bon vous semble, mais la plupart du temps, je la laisse seule. Parce que nous utilisons TeamCity, les informations perdues à partir du numéro de révision peuvent être trouvées dans la version, cela signifie qu’il y a un processus en deux étapes mais nous n’avons rien perdu et c’est un compromis acceptable.

Que définir

La première chose à comprendre est que la version de l’assemblage, la version du fichier et la version du produit ne doivent pas nécessairement correspondre. Je ne préconise pas d’avoir différents ensembles de nombres, mais cela simplifie beaucoup la vie lorsque vous apportez de petits changements à un assemblage qui n’affecte pas les interfaces publiques que vous n’êtes pas obligé de recomstackr des assemblys dépendants. La manière dont je traite cela consiste à définir uniquement les numéros majeur et mineur dans la version d’assemblage, mais à définir toutes les valeurs dans la version du fichier. Par exemple:

  • 1.2.0.0 (AssemblyVersion)
  • 1.2.3.4 (FileVersion)

Cela vous permet de déployer des correctifs à chaud qui ne rompent pas le code existant car les versions d’assembly ne correspondent pas, mais vous permettent de voir la révision / génération d’un assembly en consultant son numéro de version de fichier. Ceci est une approche commune et peut être vu sur certains assemblages open source lorsque vous regardez les détails de l’assemblage.

En tant que responsable de l’équipe, vous devrez être responsable de l’augmentation du nombre mineur lorsqu’un changement est requirejs. Une solution pour déployer un changement requirejs dans une interface mais ne pas rompre le code précédent consiste à marquer le changement actuel comme obsolète et à créer une nouvelle interface. Cela signifie que le code existant est averti que la méthode est obsolète et peut être supprimée à tout moment, mais ne vous oblige pas à tout casser immédiatement. Vous pouvez ensuite supprimer la méthode obsolète lorsque tout a été migré.

Comment le câbler ensemble

Vous pouvez faire tout ce qui précède manuellement, mais cela prendrait beaucoup de temps. Voici comment nous automatisons le processus. Chaque étape est exécutable.

  • Supprimez les atsortingbuts AssemblyVersion et AssemblyFileVersion de tous les fichiers AssemblyInfo.cs du projet.
  • Créez un fichier d’informations d’assembly commun (appelez-le VersionInfo.cs) et ajoutez-le en tant qu’élément lié à tous vos projets.
  • Ajoutez les atsortingbuts AssemblyVersion et AssemblyFileVersion à la version avec les valeurs “0.0.0.0”.
  • Créez un projet MsBuild qui génère votre fichier de solution.
  • Ajoutez une tâche avant la génération qui met à jour le fichier VersionInfo.cs. Il existe un certain nombre de bibliothèques MsBuild open source qui incluent une tâche AssemblyInfo pouvant définir le numéro de version. Il suffit de définir un nombre et un test arbitraires.
  • Ajoutez un groupe de propriétés contenant une propriété pour chacun des segments du numéro de build. C’est là que vous définissez le majeur et le mineur. Le numéro de compilation et de révision doit être passé en argument.

Avec subversion:

  0 0 0 $(build_number) 0 $(revision_number)  

J’espère que j’ai été clair, mais il y a beaucoup de choses à faire. S’il vous plaît poser des questions. Je vais utiliser tous les commentaires pour mettre un blog plus concis ensemble.

  • Numéros de version dans un assembly compilé
  • Pack d’extension MSBuild
  • TeamCity

Le [AssemblyVersion] est un très gros problème dans .NET. Une philosophie encouragée par Microsoft est que vous le laissez auto-incrémenter, obligeant tous les projets qui dépendent de l’assemblage à être recompilés. Fonctionne okayish si vous utilisez un serveur de compilation. Ce n’est jamais la mauvaise chose à faire, mais méfiez-vous des gens qui portent des épées.

L’autre, plus étroitement associé à son sens réel, est que le numéro est représentatif du versionnage de l’interface publique de l’assemblage. En d’autres termes, vous ne le modifiez que lorsque vous modifiez une interface ou une classe publique. Étant donné que seul un tel changement nécessite la recompilation des clients de l’assemblée. Cela doit être fait manuellement, cependant, le système de construction n’est pas assez intelligent pour détecter automatiquement un tel changement.

Vous pouvez étendre cette approche en incrémentant uniquement la version lorsque l’assemblage a été déployé sur des machines hors de votre scope. C’est l’approche que Microsoft utilise, les numéros de version de leurs assemblys .NET changent très rarement. Principalement en raison de la très grande douleur qu’il cause à leurs clients.

Donc, ce que Microsoft prêche n’est pas ce qu’il pratique. Son processus de génération et son contrôle des versions sont toutefois incomparables. Ils disposent même d’un ingénieur logiciel dédié qui surveille le processus. Cela n’a pas très bien fonctionné, la surcharge WaitHandle.WaitOne (int) en particulier a causé beaucoup de douleur . Corrigé dans .NET 4.0 avec une approche très différente, mais cela dépasse un peu la scope.

C’est à vous et à votre confiance dans la manière dont vous pouvez contrôler le processus de construction et les cycles de publication de faire votre propre choix. Sinon, l’incrémentation automatique de [AssemblyFileVersion] est très appropriée. Avec toutefois l’inconvénient que cela n’est pas pris en charge.

Vous pouvez utiliser la partie Construire du numéro de version pour l’incrémentation automatique.

[assembly: AssemblyVersion("1.0.*")]

Dans votre environnement, une version de test est une version avec une version de version! = 0. À la sortie, vous incrémentez la partie mineure et définissez la partie build sur 0, vous identifiez ainsi les assemblys publiés.

Si vous installez vos assemblages dans le GAC, votre GAC sera inondé de nombreuses versions différentes au fil du temps, gardez donc cela à l’esprit. Mais si vous utilisez les dll uniquement localement, je pense que c’est une bonne pratique.

En ajoutant à la réponse à Bronumskis , je voudrais souligner qu’après le standard Semantic Versioning 2.0 sur semver.org , Major.Minor.Build.Revision serait illégal en raison de la règle selon laquelle après avoir augmenté un nombre, toutes les valeurs régulières à droite auraient à remettre à zéro.

Une meilleure façon de suivre la norme serait d’utiliser Major.Minor+Build.Revision . Ceci n’est évidemment pas à utiliser dans AssemblyVersionAtsortingbute , mais un atsortingbut personnalisé ou une classe statique peut être utilisé à la place.

Semver dans TeamCity devrait être disponible en utilisant le pack d’alimentation Meta-runner. Pour git avec git-flow (en particulier dans le monde .NET), j’ai trouvé GitVersion utile.

Il n’y a pas de règle absolue en matière de versioning, alors n’hésitez pas à essayer ce qui pourrait vous convenir, mais je vous suggère d’utiliser une approche en 4 parties car vous aurez la flexibilité nécessaire pour apporter quelques modifications. A l’avenir.

… par exemple: 1.0.0. *

Réservé – Cela ajoute de la flexibilité supplémentaire, si vous souhaitez apporter des modifications à l’avenir. Mais par défaut, conservez-le comme 0.

En outre, envisagez de signer l’assembly avec la clé forte. Cela permettra de résoudre le problème de conflit d’assemblage, même si vous avez plusieurs versions d’assembly enregistrées dans le GAC. Lien MSDN