Meilleures pratiques / conseils pour gérer les numéros de version d'assembly

154

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'assembly différents pour un assembly .NET. La version du produit est la plus simple, car cela semble normalement être dicté par les entreprises. Ensuite, la version du fichier semble être destinée au contrôle de version entre les déploiements, où la version réelle de l'assembly n'est utilisée que lors de l'expédition.

Pour le moment, je cherche simplement un moyen simple d'étiqueter les versions de test et de maintenance d'un assemblage dont aucune ne dépend, donc je cherche à incrémenter automatiquement les numéros de version et de révision sur la version du fichier, et pour la version finale, copier la version actuelle version du fichier à la version de l'assembly. Le produit est utilisé en production, mais toujours en développement - vous savez - une de ces petites entreprises, aucune situation d'infrastructure de contrôle des changements.

ProfK
la source
1
Vérifiez ceci ... codinghorror.com/blog/2007/02/…
Rahul Soni

Réponses:

211

La gestion des versions est quelque chose qui me passionne beaucoup et j'ai passé beaucoup de temps à essayer de créer 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 version du produit. L'un est motivé par la technique et l'autre est motivé 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 (10) nombre de projets et est un très bon serveur de build, mais il y en a d'autres, dont certains sont totalement gratuits.

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

Ce qu'une version signifie pour une personne peut signifier quelque chose de différent pour 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. La première moitié décrit la version principale (majeure) et les mises à jour clés (mineures). La seconde moitié indique quand il a été construit et quelle était la version du code source. Les numéros de version signifient également des choses différentes selon le contexte, s'agit-il d'une API, d'une application Web, etc.

Major. Minor. Build.Revision

  • Revision Il s'agit du nombre extrait du contrôle de code source pour identifier ce qui a été réellement construit.
  • BuildIl s'agit d'un nombre toujours croissant qui peut être utilisé pour trouver une version particulière sur le serveur de construction. C'est un nombre important car le serveur de build peut avoir construit deux fois la même source avec un ensemble de paramètres différent. L'utilisation du numéro de build en conjonction avec le numéro de source vous permet d'identifier ce qui a été construit et comment.
  • MinorCela ne devrait changer qu'en cas de modification significative de l'interface publique. Par exemple, s'il s'agit d'une API, le code consommant serait-il toujours en mesure de compiler? Ce nombre doit être remis à zéro lorsque le nombre majeur change.
  • Majorindique la version du produit que vous utilisez. Par exemple, le Major 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 au fur et à mesure que vous les rencontrerez. Mon approche originale était basée sur l'utilisation de la subversion, mais récemment, je suis passé à Git. Le contrôle de source comme la subversion et le coffre-fort de source 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 distribué tel que Git. Étant donné que Git utilise des référentiels distribués qui se trouvent sur chaque machine de développement, il n'y a pas de numéro à incrémentation automatique que vous pouvez utiliser, il existe un hack qui utilise le nombre d'archives mais c'est moche. Pour cette raison, j'ai dû faire évoluer mon approche.

Major. Minor.Macro.Build

Le numéro de révision a maintenant disparu, la version est déplacée là où se trouvait 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 tranquille. 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'assembly, 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 rend la vie beaucoup plus facile lorsque vous apportez de petites modifications à un assembly qui n'affecte aucune interface publique que vous n'êtes pas obligé de recompiler les assemblys dépendants. La façon dont je gère cela est de définir uniquement les nombres majeurs et mineurs dans la version d'assemblage, mais de définir toutes les valeurs dans la version de fichier. Par exemple:

  • 1.2.0.0 (AssemblyVersion)
  • 1.2.3.4 (FileVersion)

Cela vous donne la possibilité de déployer des correctifs qui ne briseront pas le code existant car les versions d'assembly ne correspondent pas, mais vous permettent de voir la révision / build d'un assembly en regardant son numéro de version de fichier. Il s'agit d'une approche courante et peut être vue sur certains assemblys open source lorsque vous regardez les détails de l'assemblage.

En tant que chef d'équipe, vous devez être responsable de l'incrémentation du nombre mineur chaque fois qu'un changement de rupture est nécessaire. Une solution pour déployer une modification requise sur une interface sans casser le code précédent consiste à marquer l'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 attributs AssemblyVersionet AssemblyFileVersionde tous les fichiers AssemblyInfo.cs du projet.
  • Créez un fichier d'informations d'assemblage commun (appelez-le VersionInfo.cs) et ajoutez-le en tant qu'élément lié à tous vos projets.
  • Ajoutez AssemblyVersionet AssemblyFileVersionattribuez à la version avec des valeurs de "0.0.0.0".
  • Créez un projet MsBuild qui génère votre fichier de solution.
  • Ajoutez une tâche avant la compilation qui met à jour VersionInfo.cs. Il existe un certain nombre de bibliothèques MsBuild open source qui incluent une tâche AssemblyInfo qui peut définir le numéro de version. Réglez-le simplement sur un nombre arbitraire et testez.
  • 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 version et de révision doit être transmis en tant qu'arguments.

Avec subversion:

<PropertyGroup>
    <Version-Major>0</Version-Major>
    <Version-Minor>0</Version-Minor>
    <Version-Build Condition=" '$(build_number)' == '' ">0</Version-Build>
    <Version-Build Condition=" '$(build_number)' != '' ">$(build_number)</Version-Build>
    <Version-Revision Condition=" '$(revision_number)' == '' ">0</Version-Revision>
    <Version-Revision Condition=" '$(revision_number)' != '' ">$(revision_number)</Version-Revision>
</PropertyGroup>

J'espère avoir été clair, mais il y a beaucoup à faire. Veuillez poser des questions. J'utiliserai vos commentaires pour rédiger un article de blog plus concis.

Bronumski
la source
Avez-vous envisagé d'utiliser les balises de version de GitHub? Je suis très curieux de savoir comment cela s'intégrerait dans le puzzle.
raRaRa
1
@raRaRa - C'est un message assez ancien. Bien que la plupart d'entre eux restent fidèles, il y a des choses que je ferais différemment. La gestion des versions de NuGet a changé ma façon de faire et j'utilise les balises Git pour les compilations réussies, mais à la fin de la journée, le numéro de version de l'assembly doit être lié à la version de compilation sur le serveur de compilation et à la version de balise dans le contrôle de code source.
Bronumski
57

[AssemblyVersion] est un très gros problème dans .NET. Une philosophie, encouragée par Microsoft, est que vous laissez l'incrémentation automatique, forçant tous les projets qui dépendent de l'assembly à être recompilés. Fonctionne bien si vous utilisez un serveur de build. Ce n'est jamais le mal chose à faire, mais méfiez-vous des personnes portant des épées.

L'autre, plus étroitement associé à sa signification réelle, est que le numéro est représentatif du versionnage de l'interface publique de l'assembly. En d'autres termes, vous ne le modifiez que lorsque vous modifiez une interface ou une classe publique. Étant donné que seule une telle modification nécessite que les clients de l'assembly soient recompilés. Cela doit être fait manuellement, le système de construction n'est pas assez intelligent pour détecter automatiquement un tel changement.

Vous pouvez étendre davantage cette approche en incrémentant uniquement la version lorsque l'assembly a été déployé sur des machines hors de votre portée. 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 douleur très considérable que cela cause à leurs clients.

Ce que Microsoft prêche n'est donc pas ce qu'il pratique. Son processus de construction et son contrôle de version sont cependant inégalés, ils ont même 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 portée.

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

Hans Passant
la source
11

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

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

Dans votre environnement, une version de test est une version qui a une version de construction! = 0. Lors de la publication, vous incrémentez la partie mineure et définissez la partie de construction sur 0, c'est ainsi que vous identifierez les assemblys publiés.

Si vous installez vos assemblys dans le GAC, votre GAC est inondé de nombreuses versions différentes au fil du temps, alors gardez cela à l'esprit. Mais si vous n'utilisez les DLL que localement, je pense que c'est une bonne pratique.

testalino
la source
J'aime le numéro de build 0 pour les versions.
ProfK
1
Bien sûr, cela signifie que le nom fort de votre assembly changera à chaque build, que vous le vouliez ou non.
Richard
9

En plus de la réponse de Bronumskis , je tiens à 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 devraient être réinitialisées à zéro.

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

Semver dans TeamCity devrait être disponible à l'aide du Power Pack Meta-runner. Pour git avec git-flow (en particulier dans le monde .NET), j'ai trouvé que GitVersion était utile.

côté soleil
la source
2
Intéressant, je vais vérifier cela. Le format de numéro de version que vous avez mentionné peut être utilisé dans l'attribut AssemblyInformationalVersion.
Bronumski
1

Il n'y a pas de règle absolue en ce qui concerne les assemblages de version, alors n'hésitez pas à essayer ce qui fonctionnera pour vous, mais je vous suggère d'utiliser une approche en 4 parties car vous aurez la flexibilité dans le cas où vous souhaitez apporter des modifications. A l'avenir.

... par exemple: 1.0.0. *

Réservé - Cela ajoute une flexibilité supplémentaire, au cas où vous souhaiteriez apporter des modifications à l'avenir. Mais par défaut, gardez-le à 0.

Pensez également à signer l'assemblage avec une clé forte. Cela résoudra le problème de conflit d'assembly dans le cas où vous avez plusieurs versions d'assembly enregistrées dans le GAC. Lien MSDN

Karthik Mahalingam
la source