wake-up-neo.net

Wie kann ich die C # -Assembly-Version über unsere CI-Plattform (Hudson) automatisch inkrementieren?

Ich und meine Gruppe sind entsetzlich, wenn es darum geht, die Assembly-Versionsnummern zu erhöhen, und wir versenden häufig Assemblys mit 1.0.0.0-Versionen. Offensichtlich verursacht dies viele Kopfschmerzen.

Über unsere CI -Plattform werden wir mit unseren Übungen viel besser, und ich würde es gerne so einstellen, dass die Werte innerhalb der assemblyinfo.cs -Datei, damit die Versionen unserer Assemblys automatisch mit den Codeänderungen in dieser Assembly aktualisiert werden.

Ich hatte zuvor (bevor wir Hudson ) eine Möglichkeit eingerichtet, den Wert entweder über msbuild oder über die Befehlszeile (kann mich nicht erinnern) zu erhöhen, aber mit Hudson wird das aktualisiert SVN-Repository und einen weiteren Build auslösen. Dies würde zu einer langsamen Endlosschleife führen, da Hudson jede Stunde SVN abfragt.

Ist es eine schlechte Idee, Hudson die Versionsnummer erhöhen zu lassen? Was wäre eine Alternative dazu?

Im Idealfall wäre mein Kriterium für eine Lösung eines der folgenden:

  • Erhöht die Build-Nummer in assemblyinfo.cs vor einem Build
  • Erhöht die Build-Nummer nur in Baugruppen, die geändert wurden. Dies ist möglicherweise nicht möglich, da Hudson den Projektordner bei jedem Build löscht
  • Übernimmt die geänderte assemblyinfo.cs in das Code-Repository (derzeit VisualSVN )
  • Verursacht nicht, dass Hudson beim nächsten Scannen nach Änderungen einen neuen Build auslöst

Wenn ich das im Kopf habe, könnte ich leicht eine Lösung für das meiste durch Batch-Dateien/-Befehle finden, aber all meine Ideen würden dazu führen, dass Hudson beim nächsten Scannen einen neuen Build auslöst. Ich suche nicht jemanden, der alles für mich tut, sondern weise mich in die richtige Richtung, vielleicht eine Technik, um Hudson dazu zu bringen, bestimmte SVN-Commits zu ignorieren usw.

Alles, was ich bisher gefunden habe, ist nur ein Artikel, in dem erklärt wird, wie die Versionsnummer automatisch erhöht wird. Dabei wird eine CI-Plattform, die in eine Endlosschleife umgewandelt werden könnte, nicht berücksichtigt.

110
Allen Rice

Eine einfache Alternative besteht darin, die Assembly-Version von der C # -Umgebung erhöhen zu lassen, indem Sie das Versionsattribut auf major.minor.* Setzen (wie in der AssemblyInfo-Dateivorlage beschrieben).

Möglicherweise suchen Sie jedoch nach einer umfassenderen Lösung.

EDIT (Antwort auf die Frage in einem Kommentar):

Von 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.*")]
62
Greg D

Folgendes habe ich getan, um das AssemblyFileVersion-Attribut zu stempeln.

AssemblyFileVersion aus AssemblyInfo.cs entfernt

Fügen Sie dem Projekt eine neue, leere Datei mit dem Namen AssemblyFileInfo.cs hinzu.

Installieren Sie das Toolset MSBuild-Community-Aufgaben auf dem Hudson-Build-Computer oder als NuGet-Abhängigkeit in Ihrem Projekt.

Bearbeiten Sie die Projektdatei (csproj), es handelt sich lediglich um eine msbuild-Datei, und fügen Sie Folgendes hinzu.

Irgendwo wird es einen <PropertyGroup> Geben, der die Version angibt. Ändern Sie das so, dass es z.

 <Major>1</Major>
 <Minor>0</Minor>
 <!--Hudson sets BUILD_NUMBER and SVN_REVISION -->
 <Build>$(BUILD_NUMBER)</Build>
 <Revision>$(SVN_REVISION)</Revision>

Hudson stellt diese Umgebungsvariablen bereit, die Sie dort sehen, wenn das Projekt auf Hudson basiert (vorausgesetzt, es wird von Subversion abgerufen).

Fügen Sie am Ende der Projektdatei hinzu

 <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')" />
  <Target Name="BeforeBuild" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')">
    <Message Text="Version: $(Major).$(Minor).$(Build).$(Revision)" />
    <AssemblyInfo CodeLanguage="CS" OutputFile="AssemblyFileInfo.cs" AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)" AssemblyConfiguration="$(Configuration)" Condition="$(Revision) != '' " />
  </Target>

Hierbei wird mithilfe von MSBuildCommunityTasks die Datei AssemblyFileVersion.cs generiert, um ein AssemblyFileVersion-Attribut einzuschließen, bevor das Projekt erstellt wird. Sie können dies für alle Versionsattribute tun, wenn Sie möchten.

Wenn Sie einen Hudson-Build ausgeben, erhält die resultierende Assembly eine AssemblyFileVersion von 1.0.HUDSON_BUILD_NR.SVN_REVISION, z. 1.0.6.2632, das heißt die 6. Build-Nr. In Hudson, stammt aus der Subversion-Revision 2632.

64
nos

Hier ist eine elegante Lösung, die vor dem Hinzufügen eines neuen Projekts ein wenig Arbeit erfordert, aber den Prozess sehr einfach handhabt.

Die Idee ist, dass jedes Projekt auf eine Lösungsdatei verweist, die nur die Assembly-Versionsinformationen enthält. Ihr Erstellungsprozess muss also nur eine einzelne Datei aktualisieren und alle Assembly-Versionen werden beim Kompilieren aus der einen Datei gezogen.

Schritte:

  1. Fügen Sie Ihrer Lösungsdatei * .cs eine Klasse mit dem Namen min SharedAssemblyProperties.cs hinzu
  2. Entfernen Sie alle cs-Informationen aus dieser neuen Datei
  3. Schneiden Sie die Assembly-Informationen aus einer AssemblyInfo-Datei aus: [Assembly: AssemblyVersion ("1.0.0.0")] [Assembly: AssemblyFileVersion ("1.0.0.0")]
  4. Fügen Sie die Anweisung "using System.Reflection;" in die Datei und fügen Sie dann Daten in Ihre neue cs-Datei ein (ex SharedAssemblyProperties.cs)
  5. Fügen Sie Ihrem Projekt ein vorhandenes Objekt hinzu (warten Sie ... lesen Sie weiter, bevor Sie die Datei hinzufügen)
  6. Wählen Sie die Datei aus, und klicken Sie auf die Dropdown-Liste neben der Schaltfläche "Hinzufügen", bevor Sie auf "Hinzufügen" klicken.
  7. Wiederholen Sie die Schritte 5 und 6 für alle vorhandenen und neuen Projekte in der Lösung

Wenn Sie die Datei als Link hinzufügen, werden die Daten in der Projektdatei gespeichert und beim Kompilieren werden die Assembly-Versionsinformationen aus dieser einen Datei abgerufen.

In Ihrer Quellcodeverwaltung fügen Sie eine Fledermausdatei oder eine Skriptdatei hinzu, die einfach die SharedAssemblyProperties.cs-Datei inkrementiert, und alle Ihre Projekte aktualisieren ihre Assemblyinformationen aus dieser Datei.

42
sondlerd

Hudson kann so konfiguriert werden, dass Änderungen an bestimmten Pfaden und Dateien ignoriert werden, sodass kein neuer Build angefordert wird.

Klicken Sie auf der Seite für die Auftragskonfiguration unter Quellcodeverwaltung auf die Schaltfläche Erweitert. In das Feld Ausgeschlossene Bereiche geben Sie einen oder mehrere reguläre Ausdrücke ein, die mit Ausschlüssen übereinstimmen.

Um beispielsweise Änderungen an der Datei version.properties zu ignorieren, können Sie Folgendes verwenden:

/MyProject/trunk/version.properties

Dies funktioniert für andere Sprachen als C # und ermöglicht es Ihnen, Ihre Versionsinformationen in Subversion zu speichern.

11

.NET erledigt das für Sie. Setzen Sie in Ihrer AssemblyInfo.cs-Datei Ihre Assembly-Version auf major.minor. * (Beispiel: 1.0. *).

Wenn Sie Ihr Projekt erstellen, wird die Version automatisch generiert.

Die Build- und Revisionsnummern werden, glaube ich, basierend auf dem Datum unter Verwendung der Unix-Epoche generiert. Die Erstellung basiert auf dem aktuellen Tag und die Überarbeitung basiert auf der Anzahl der Sekunden seit Mitternacht.

9
Kyle Trauberman

Ich habe diese 1.0. * -Funktion noch nie in VS2005 oder VS2008 gesehen. Muss etwas getan werden, um VS so einzustellen, dass die Werte inkrementiert werden?

Wenn AssemblyInfo.cs mit 1.0. * Fest codiert ist, wo werden dann die tatsächlichen Builds/Revisionen gespeichert?

Nach dem Einfügen von 1.0. * In AssemblyInfo können wir die folgende Anweisung nicht verwenden, da ProductVersion jetzt einen ungültigen Wert hat - es wird 1.0. * Und nicht der von VS zugewiesene Wert verwendet:

Version version = new Version(Application.ProductVersion);

Seufz - das scheint eines der Dinge zu sein, nach denen jeder fragt, aber irgendwie gibt es nie eine sichere Antwort. Vor Jahren sah ich Lösungen, um eine Revisionsnummer zu generieren und als Teil eines Postbuild-Prozesses in AssemblyInfo zu speichern. Ich hoffte, dass VS2008 keinen Tanz erfordert. Vielleicht VS2010?

8
TonyG

Ich gehe davon aus, dass dies auch mit einem Textvorlage möglich ist, bei dem Sie die fraglichen Assembly-Attribute im Handumdrehen aus der Umgebung erstellen, wie dies AssemblyVersion.tt unten tut.

<#@ 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#>")]
5
MikeS

Als Fortsetzung der Antwort von MikeS wollte ich hinzufügen, dass das VS + Visual Studio-Visualisierungs- und Modellierungs-SDK installiert sein muss, damit dies funktioniert, und dass Sie auch die Projektdatei ändern müssen. Zu erwähnen ist auch, dass ich Jenkins als Build-Server verwende, der auf einer Windows 2008 R2-Server-Box mit Versionsmodul ausgeführt wird. Dort erhalte ich die BUILD_NUMBER.

Meine Textvorlagendatei version.tt sieht so aus

<#@ 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#>")]

Ich habe die folgenden in den Eigenschaftsgruppen

<PropertyGroup>
    <TransformOnBuild>true</TransformOnBuild>
    <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>

nach dem Import von Microsoft.CSharp.targets habe ich dies (abhängig davon, wo Sie VS installieren)

<Import Project="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\TextTemplating\v10.0\Microsoft.TextTemplating.targets" />

Auf meinem Build-Server habe ich dann das folgende Skript, um die Texttransformation vor dem eigentlichen Build auszuführen und die letzte Änderungssatznummer in TFS abzurufen

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 
...
<rest of bld script>

Auf diese Weise kann ich Builds UND Changesets nachverfolgen. Wenn ich also seit dem letzten Build nichts eingecheckt habe, sollte sich die letzte Ziffer nicht ändern. Möglicherweise habe ich jedoch Änderungen am Build-Prozess vorgenommen, sodass die vorletzte Nummer erforderlich ist . Wenn Sie vor einem Build mehrere Eincheckvorgänge durchführen, wird nur die letzte Änderung in der Version berücksichtigt. Ich vermute, Sie könnten verketten, dass dies erforderlich ist.

Ich bin sicher, Sie können etwas ausgefalleneres tun und TFS direkt aus der tt-Vorlage aufrufen, aber das funktioniert für mich.

Ich kann dann meine Version zur Laufzeit so bekommen

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

Für meine Lösung müssen keine externen Tools oder Skriptsprachen hinzugefügt werden. Es ist so gut wie garantiert, dass sie auf Ihrem Build-Computer funktionieren. Ich löse dieses Problem in mehreren Teilen. Zuerst habe ich eine BUILD.BAT-Datei erstellt, die den Parameter Jenkins BUILD_NUMBER in eine Umgebungsvariable konvertiert. Ich verwende die Jenkins-Funktion "Windows-Batch-Befehl ausführen", um die Build-Batch-Datei auszuführen, indem ich die folgenden Informationen für den Jenkins-Build eingebe:

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

In der Build-Umgebung habe ich eine build.bat-Datei, die wie folgt beginnt:

     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

Danach habe ich mit der rechten Maustaste auf das zu erstellende Projekt im Bereich des Projektmappen-Explorers von Visual Studio geklickt und Eigenschaften ausgewählt, Ereignisse erstellen ausgewählt und die folgenden Informationen als Befehlszeile für die Ereigniserstellung eingegeben, die automatisch eine CS-Datei erstellt Enthält Informationen zur Build-Nummer basierend auf den aktuellen Einstellungen der Umgebungsvariablen:

     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.CompilerServices; >> %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%

Möglicherweise müssen Sie sich an Ihren Geschmack anpassen. Ich habe das Projekt einmal manuell erstellt, um eine erste Version.cs-Datei im Eigenschaftenverzeichnis des Hauptprojekts zu generieren. Zuletzt binde ich die Datei Version.cs manuell in die Visual Studio-Projektmappe ein, indem ich sie in den Projektmappen-Explorer unterhalb der Registerkarte Eigenschaften für dieses Projekt ziehe. In zukünftigen Builds liest Visual Studio dann die .cs-Datei zur Jenkins-Build-Zeit und erhält die richtigen Build-Nummer-Informationen daraus.

1
johnwbyrd

Wir haben also ein Projekt mit einer Lösung, die mehrere Projekte mit Assemblys mit unterschiedlichen Versionsnummern enthält.

Nachdem ich einige der oben genannten Methoden untersucht hatte, implementierte ich gerade einen Erstellungsschritt, um ein Powershell-Skript auszuführen, das die Datei AssemblyInfo.cs sucht und ersetzt. Ich verwende immer noch die Versionsnummer 1.0. * In der Versionsverwaltung, und Jenkins aktualisiert die Versionsnummer nur manuell, bevor msbuild ausgeführt wird.

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" }

Ich habe die Option -Encoding "UTF8" hinzugefügt, da git anfing, die .cs-Datei als Binärdateien zu behandeln, wenn ich dies nicht tat. Zugegeben, das spielte keine Rolle, da ich das Ergebnis nie wirklich begangen habe. es ist gerade beim Testen aufgetaucht.

Unsere CI-Umgebung verfügt bereits über eine Funktion, mit der Sie den Jenkins-Build mit dem jeweiligen git-Commit verknüpfen können (dank Stash-Plugin!).

1
jonnybot

Ich habe mich für ein paar Methoden entschieden, die ein vorab erstelltes Powershell-Skript ( https://Gist.github.com/bradjolicoeur/e77c508089aea6614af ) verwenden, um bei jedem erfolgreichen Build eine Erhöhung in Global.asax vorzunehmen etwas wie das:

  // We are using debug configuration, so increment our builds.
  if (System.Diagnostics.Debugger.IsAttached)
  {
      string version = System.Reflection.Assembly.GetExecutingAssembly()
                                                       .GetName()
                                                       .Version
                                                       .ToString();

      var psi = new ProcessStartInfo(@"svn", "commit -m \"Version: " + version + "\n \"");
      psi.WorkingDirectory = @"C:\CI\Projects\myproject";
      Process.Start(psi); 
  }

Ich denke immer noch, dass der gesamte Prozess zu kompliziert ist und ich werde nach einer effizienteren Methode suchen, um das gleiche Ergebnis zu erzielen. Ich wollte dies hauptsächlich, um die Version in SVN und dann in Jenkin ohne zu viele zusätzliche Tools zu übergeben.

0
Netferret

Dies ist ein einfacherer Mechanismus. Vor dem MSBuild-Schritt muss lediglich ein Windows Batch Command Task Build-Schritt hinzugefügt und ein einfaches Programm zum Suchen und Ersetzen (FART) verwendet werden.

Der Batch-Schritt

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

Wenn Sie eine andere Quellcodeverwaltung als svn verwenden, ändern Sie die Option --svn für die entsprechende Option für Ihre SCM-Umgebung.

Download Furz

0
sweetfa