Best Practices / Anleitungen zur Pflege der Versionsnummern von Baugruppen

154

Ich suche nach Hinweisen, Vorschlägen und sogar Diktaten zum Verwalten der drei verschiedenen Assemblyversionsnummern für eine .NET-Assembly. Die Produktversion ist die einfachste, da dies normalerweise vom Unternehmen vorgegeben wird. Dann scheint die Dateiversion für die Versionierung zwischen Bereitstellungen vorgesehen zu sein, wobei die tatsächliche Assemblyversion nur beim Versand verwendet wird.

Im Moment suche ich nur nach einer einfachen Möglichkeit, Test- und Wartungsversionen einer Baugruppe zu kennzeichnen, von der keine abhängt. Daher suche ich nach automatisch inkrementierenden Build- und Revisionsnummern für die Dateiversion und nach einer endgültigen Version, bei der die aktuelle Version kopiert wird Dateiversion zur Assemblyversion. Das Produkt wird in der Produktion eingesetzt, befindet sich aber noch in der Entwicklung - Sie wissen, eines dieser kleinen Unternehmen, das keine Infrastruktur für die Änderungskontrolle hat.

ProfK
quelle
1
Überprüfen Sie dies heraus ... codinghorror.com/blog/2007/02/…
Rahul Soni

Antworten:

211

Die Versionierung ist etwas, das mich sehr begeistert und ich habe lange versucht, ein einfach zu verwendendes Versionierungssystem zu entwickeln. Aus dem, was Sie bereits in Ihrer Frage gesagt haben, geht hervor, dass Sie einen wichtigen Punkt verstanden haben: Die Versionsnummern der Baugruppe sind nicht gleichbedeutend mit der Produktversion. Einer ist technisch und der andere vom Geschäft bestimmt.

Im Folgenden wird davon ausgegangen, dass Sie eine Form der Quellcodeverwaltung und einen Build-Server verwenden. Für den Kontext verwenden wir TeamCity und Subversion / Git. TeamCity ist für eine kleine (10) Anzahl von Projekten kostenlos und ein sehr guter Build-Server, aber es gibt andere, von denen einige völlig kostenlos sind.

Was eine Versionsnummer bedeutet

Was eine Version für eine Person bedeutet, kann für eine andere Person etwas anderes bedeuten. Die allgemeine Struktur ist Dur, Moll, Makro, Mikro. Ich betrachte eine Versionsnummer so, dass sie in zwei Teile zerlegt wird. In der ersten Hälfte werden die Hauptversion (Major) und alle wichtigen Aktualisierungen (Minor) beschrieben. Die zweite Hälfte zeigt an, wann es erstellt wurde und wie die Quellcodeversion war. Versionsnummern bedeuten je nach Kontext auch unterschiedliche Dinge, sei es eine API, eine Web-App usw.

Major. Minor. Build.Revision

  • Revision Dies ist die Nummer, die der Quellcodeverwaltung entnommen wurde, um zu identifizieren, was tatsächlich erstellt wurde.
  • BuildDies ist eine ständig wachsende Zahl, mit der ein bestimmter Build auf dem Build-Server gefunden werden kann. Dies ist eine wichtige Zahl, da der Build-Server möglicherweise dieselbe Quelle zweimal mit einem anderen Parametersatz erstellt hat. Durch die Verwendung der Build-Nummer in Verbindung mit der Quellennummer können Sie identifizieren, was und wie erstellt wurde.
  • MinorDies sollte sich nur ändern, wenn die öffentliche Schnittstelle erheblich geändert wurde. Wenn es sich beispielsweise um eine API handelt, kann der konsumierende Code dennoch kompiliert werden? Diese Nummer sollte auf Null zurückgesetzt werden, wenn sich die Hauptnummer ändert.
  • MajorGibt an, auf welcher Version des Produkts Sie sich befinden. Beispielsweise ist der Major aller VisualStudio 2008-Assemblys 9 und VisualStudio 2010 10.

Die Ausnahme von der Regel

Es gibt immer Ausnahmen von der Regel und Sie müssen sich anpassen, wenn Sie auf sie stoßen. Mein ursprünglicher Ansatz basierte auf der Verwendung von Subversion, aber kürzlich bin ich zu Git gewechselt. Quellcodeverwaltung wie Subversion und Source Safe, die ein zentrales Repository verwenden, verfügen über eine Nummer, mit der ein bestimmter Satz von Quellen aus einer bestimmten Zeit identifiziert werden kann. Dies ist bei einer verteilten Quellcodeverwaltung wie Git nicht der Fall. Da Git verteilte Repositorys verwendet, die sich auf jedem Entwicklungscomputer befinden, gibt es keine automatisch inkrementierende Nummer, die Sie verwenden können. Es gibt einen Hack, der die Anzahl der Check-Ins verwendet, aber hässlich ist. Aus diesem Grund musste ich meinen Ansatz weiterentwickeln.

Major. Minor. Macro.Build

Die Versionsnummer ist jetzt weg, der Build wurde an die Stelle verschoben, an der sich die Revision befand, und das Makro wurde eingefügt. Sie können das Makro so verwenden, wie Sie es für richtig halten, aber die meiste Zeit lasse ich es in Ruhe. Da wir TeamCity verwenden, können die aus der Versionsnummer verlorenen Informationen im Build gefunden werden. Dies bedeutet, dass es sich um einen zweistufigen Prozess handelt, aber wir haben nichts verloren und sind ein akzeptabler Kompromiss.

Was einstellen

Das erste, was zu verstehen ist, ist, dass die Assembly-Version, die Dateiversion und die Produktversion nicht übereinstimmen müssen. Ich befürworte nicht, unterschiedliche Zahlengruppen zu haben, aber es erleichtert das Leben erheblich, wenn kleine Änderungen an einer Assembly vorgenommen werden, die keine öffentlichen Schnittstellen betreffen, die Sie nicht gezwungen sind, abhängige Assemblys neu zu kompilieren. Ich gehe damit um, indem ich nur die Haupt- und Nebenzahlen in der Assembly-Version, aber alle Werte in der Dateiversion festlege. Beispielsweise:

  • 1.2.0.0 (AssemblyVersion)
  • 1.2.3.4 (FileVersion)

Auf diese Weise können Sie Hotfixes bereitstellen, die den vorhandenen Code nicht beschädigen, da die Assemblyversionen nicht übereinstimmen. Sie können jedoch die Revision / den Build einer Assembly anhand der Versionsnummer der Datei anzeigen. Dies ist ein gängiger Ansatz, der bei einigen Open Source-Assemblys zu sehen ist, wenn Sie sich die Assemblydetails ansehen.

Sie als Teamleiter müssten dafür verantwortlich sein, die untergeordnete Zahl zu erhöhen, wenn jemals eine Änderung erforderlich ist. Eine Lösung, um eine erforderliche Änderung an einer Schnittstelle einzuführen, ohne den vorherigen Code zu beschädigen, besteht darin, die aktuelle als veraltet zu markieren und eine neue Schnittstelle zu erstellen. Dies bedeutet, dass vorhandener Code gewarnt wird, dass die Methode veraltet ist und jederzeit entfernt werden kann, Sie jedoch nicht sofort alles beschädigen müssen. Sie können dann die veraltete Methode entfernen, wenn alles migriert wurde.

Wie man es zusammen verdrahtet

Sie können alle oben genannten Schritte manuell ausführen, dies wäre jedoch sehr zeitaufwändig. Im Folgenden wird der Prozess automatisiert. Jeder Schritt ist ausführbar.

  • Entfernen Sie die Attribute AssemblyVersionund AssemblyFileVersionaus allen AssemblyInfo.cs-Projektdateien.
  • Erstellen Sie eine allgemeine Assembly-Info-Datei (nennen Sie sie VersionInfo.cs) und fügen Sie sie allen Ihren Projekten als verknüpftes Element hinzu.
  • Hinzufügen AssemblyVersionund AssemblyFileVersionAttribute zur Version mit den Werten "0.0.0.0".
  • Erstellen Sie ein MsBuild-Projekt, das Ihre Lösungsdatei erstellt.
  • Fügen Sie vor dem Build eine Aufgabe hinzu, die die VersionInfo.cs aktualisiert. Es gibt eine Reihe von Open Source-MsBuild-Bibliotheken, die eine AssemblyInfo-Task enthalten, mit der die Versionsnummer festgelegt werden kann. Stellen Sie es einfach auf eine beliebige Zahl ein und testen Sie es.
  • Fügen Sie eine Eigenschaftsgruppe hinzu, die eine Eigenschaft für jedes der Segmente der Build-Nummer enthält. Hier stellen Sie Dur und Moll ein. Die Build- und Revisionsnummer sollte als Argument übergeben werden.

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

Hoffentlich war mir klar, aber es geht um viel. Bitte stellen Sie Fragen. Ich werde jedes Feedback nutzen, um einen prägnanteren Blog-Beitrag zusammenzustellen.

Bronumski
quelle
Haben Sie darüber nachgedacht, Versions-Tags von GitHub zu verwenden? Ich bin sehr gespannt, wie das in das Puzzle passen würde.
RaRaRa
1
@raRaRa - Dies ist ein ziemlich alter Beitrag. Während das meiste davon immer noch zu mir steht, gibt es einige Dinge, die ich anders machen würde. Die NuGet-Versionierung hat meine Arbeitsweise geändert und ich verwende Git-Tags für erfolgreiche Builds, aber am Ende des Tages sollte die Versionsnummer auf der Assembly mit der Build-Version auf dem Build-Server und der Tag-Version in der Quellcodeverwaltung verknüpft sein.
Bronumski
57

Die [AssemblyVersion] ist eine sehr große Sache in .NET. Eine von Microsoft empfohlene Philosophie ist, dass Sie die automatische Inkrementierung zulassen und alle Projekte, die von der Assembly abhängen, neu kompilieren müssen. Funktioniert einwandfrei, wenn Sie einen Build-Server verwenden. Es ist nie das Falsche , sich vor Menschen zu hüten, die Schwerter tragen.

Die andere, die enger mit ihrer tatsächlichen Bedeutung verbunden ist, ist, dass die Nummer für die Versionierung der öffentlichen Schnittstelle der Assembly repräsentativ ist. Mit anderen Worten, Sie ändern es nur, wenn Sie eine öffentliche Schnittstelle oder Klasse ändern. Da nur für eine solche Änderung Clients der Assembly neu kompiliert werden müssen. Dies muss jedoch manuell erfolgen. Das Build-System ist nicht intelligent genug, um eine solche Änderung automatisch zu erkennen.

Sie können diesen Ansatz weiter ausbauen, indem Sie die Version nur erhöhen, wenn die Assembly auf Computern außerhalb Ihrer Reichweite bereitgestellt wurde. Dies ist der Ansatz, den Microsoft verwendet. Die Versionsnummern der .NET-Assemblys ändern sich sehr selten. Vor allem wegen der sehr erheblichen Schmerzen, die es bei ihren Kunden verursacht.

Was Microsoft predigt, ist also nicht das, was es praktiziert. Der Erstellungsprozess und die Versionskontrolle sind jedoch beispiellos. Sie verfügen sogar über einen dedizierten Softwareentwickler, der den Prozess überwacht. Es hat nicht ganz so gut geklappt, insbesondere die Überlastung von WaitHandle.WaitOne (int) verursachte eine Menge Schmerzen . In .NET 4.0 mit einem ganz anderen Ansatz behoben, aber das geht etwas über den Rahmen hinaus.

Es liegt eher an Ihnen und Ihrem Vertrauen, wie gut Sie den Build-Prozess und die Release-Zyklen steuern können, um Ihre eigene Wahl zu treffen. Abgesehen davon ist es sehr angebracht, die [AssemblyFileVersion] automatisch zu erhöhen. Mit der Unannehmlichkeit, dass dies nicht unterstützt wird.

Hans Passant
quelle
11

Sie können den Build-Teil der Versionsnummer zum automatischen Inkrementieren verwenden.

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

In Ihrer Umgebung ist eine Testversion eine Version mit einer Build-Version! = 0. Bei der Freigabe erhöhen Sie den untergeordneten Teil und setzen den Build-Teil auf 0. Auf diese Weise würden Sie freigegebene Assemblys identifizieren.

Wenn Sie Ihre Baugruppen im GAC installieren, wird Ihr GAC im Laufe der Zeit mit vielen verschiedenen Versionen überflutet. Denken Sie also daran. Wenn Sie die DLLs jedoch nur lokal verwenden, ist dies meiner Meinung nach eine gute Vorgehensweise.

Testalino
quelle
Ich mag die 0 Build Nummer für Release-Versionen.
ProfK
1
Dies bedeutet natürlich, dass sich der starke Name Ihrer Assembly mit jedem Build ändert, unabhängig davon, ob Sie dies möchten oder nicht.
Richard
9

Hinzufügen zu Bronumskis Antwort , möchte ich darauf hinweisen , dass nach dem Semantic Versioning - 2.0 - Standard bei semver.org , Major.Minor.Build.Revisionwürde aufgrund der Regel illegal sein , dass nach einer bestimmten Anzahl zu erhöhen, alle regulären Werte auf der rechten Seite auf Null zurückgesetzt sein müsste.

Ein besserer Weg, dem Standard zu folgen, wäre die Verwendung Major.Minor+Build.Revision. Dies ist offensichtlich nicht für die Verwendung in vorgesehen AssemblyVersionAttribute, es kann jedoch stattdessen ein benutzerdefiniertes Attribut oder eine statische Klasse verwendet werden.

Semver in TeamCity sollte mit dem Meta-Runner Power Pack verfügbar sein. Für Git mit Git-Flow (insbesondere in der .NET-Welt) fand ich GitVersion hilfreich.

Sonnenseite
quelle
2
Interessant, ich werde das überprüfen. Das von Ihnen erwähnte Versionsnummernformat kann im AssemblyInformationalVersion-Attribut verwendet werden.
Bronumski
1

Es gibt keine feste Regel, wenn es um die Versionsverwaltung von Baugruppen geht. Probieren Sie also einfach aus, welche für Sie geeignet ist. Ich würde Ihnen jedoch empfehlen, den 4-Teile-Ansatz zu verwenden, da Sie die Flexibilität haben, falls Sie einige Änderungen vornehmen möchten in der Zukunft.

... zum Beispiel: 1.0.0. *

Reserviert - Dies erhöht die Flexibilität, falls Sie in Zukunft Änderungen vornehmen möchten. Behalten Sie es jedoch standardmäßig als 0 bei.

Ziehen Sie auch in Betracht, die Assembly mit einem starken Schlüssel zu signieren. Dies löst das Problem mit Baugruppenkonflikten, wenn Sie mehrere Versionen der Baugruppe im GAC registriert haben. MSDN Link

Karthik Mahalingam
quelle