Domanda

Stiamo utilizzando un file T4 per gestire la nostra versione di assemblaggio; Fondamentalmente stiamo seguendo queste procedure Per rigenerare i nostri versioni assembly su ogni build. Questo viene fatto facendo usare il .csproj Modeling SDK per VS 2013 in modo da Personalizza la configurazione di rigenerazione T4 con MSBuild.

Funziona alla grande! Sfortunatamente il team-build per il servizio di Fondazione Team non sembra supportare la generazione di codice T4 al momento della build poiché le istanze di VS 12 sul server build non dispongono di texttemplating.targets nella posizione di installazione predefinita; presumibilmente gli SDK di modellazione/VS non sono installati sul server build (dai registri di errore di build TFService):

Il progetto importato "C: Programmi (x86) msBuild 12.0 Microsoft VisualStudio V12.0 TextTemplating Microsoft.TextTemplating.Targets" non è stato trovato. Conferma che il percorso nella dichiarazione è corretto e che il file esiste sul disco.

Ci sono piani per installare i componenti aggiuntivi VS 2013 pubblicati Microsoft (VS SDK, Modeling SDK, ecc.) Sull'immagine del server Build?

C'è un lavoro in giro che posso implementare in modo che quando commetto il mio codice nel servizio di Fondazione Team tramite Git, la build non si romperà?

Come posso configurare il controller di build ospitato di TFService per trasformare i miei file T4 durante le sue build?

È stato utile?

Soluzione

Ho finito per creare una soluzione diversa al compito di avere la conversazione automatica del server build i nostri assembly. Invece di utilizzare T4 per creare dinamicamente un file AssemblyInfo.cs da condividere tramite il collegamento dell'oggetto ad altri progetti all'interno della soluzione (e quindi devi affrontare il fastidio di capire come mantenere la rigenerazione della corrente del file per questo scopo), i Evitato del tutto T4. È stato troppo lavoro integrato con la macchina per la costruzione remota di terze parti, gestendo i componenti aggiuntivi e gli SDK che consentono la manipolazione T4 ecc. Esiste una soluzione molto più semplice che coinvolge Attività della comunità MSBuild che ho trovato da Questo è così domanda. La soluzione è elegantemente semplice rispetto a T4! Ecco come si scuote:

Ogni volta che questo progetto, Application.versioning.csproj, viene costruito, le attività MSBuild definite nella libreria "MsBuildCommUnity Tasks" installate da Nuget, installate in modo dinamico, generano dinamicamente Assemblyfileversion, AssemblyInformationalversion, Assemblyversion In base all'ora della data di UTC corrente e inseriscili in un nuovo file, Autoversion.cs, che risiede nella directory "Proprietà" di questo progetto (insieme al file AssemblyInfo.cs). AssemblyInfo.CS ha questi attributi di assemblaggio per sempre per evitare errori di build degli attributi di assemblaggio definiti multiplica). Dopo la generazione di AutoVersion.cs (che si verifica appena prima della build), il compilatore integra gli attributi di versioning dell'assemblaggio di cui sopra nell'assemblaggio costruito. Questa versione di versione riflette il tempo UTC in cui sono stati costruiti (vedi sotto).

Ogni altra .csproj nel .sln si iscrive a questa dinamica assemblaggio di build-time con la creazione di un collegamento al file al file AutoVersion.cs generato. Questi assembly devono anche essere potati da AssemblyInfo.cs. La versione assemblying per tutte le iscrizioni .csprojs nel .sln viene eseguita ogni volta che myapplication.versioning.csproj è costruito (o ricostruito). Ecco il .csproj per il progetto di versione:

  <!-- START DYNAMIC ASSEMBLY VERSIONING WORK-->
  <!--MSBuild Community Tasks path as installed via the nuget package 'Install-Package MSBuildTasks'-->

 <PropertyGroup>
    <MSBuildCommunityTasksPath>$(MSBuildThisFileDirectory)..\.build</MSBuildCommunityTasksPath>
    <My-PropertiesDir>Properties</My-PropertiesDir>
  </PropertyGroup>
  <PropertyGroup>

   <!--this should only be incremented (starting at zero) for MAJOR application releases this should never be reset only incremented!--> 
    <ManualMajorVersion>0</ManualMajorVersion>

   <!--3 digits maximum should only be manually incremented (starting at zero) for feature releases-->
   <!--!this should be reset to '0' at the start of each caldenar Year-->  
    <ManualMinorVersion>0</ManualMinorVersion>
  </PropertyGroup>

   <!--Import MSBuild Community Tasks library installed from Nuget -->
   <!--This library contains defined MSBUILD tasks useful for dynamically generating Assembly information via MSBUILD https://github.com/loresoft/msbuildtasks--> 
  <Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets" />
  <Target Name="BeforeBuild">
    <Time Format="yy.MM.dd.HHmm" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="My-VersionNumber" />
    </Time>
    <Message Text="Auto versioning from UTC time: $(My-VersionNumber) ...">
    </Message>
    <Time Format="yy" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Year" />
    </Time>
    <Time Format="MM" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Month" />
    </Time>
    <Time Format="dd" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Day" />
    </Time>
    <Time Format="HH" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Hour" />
    </Time>
    <Time Format="mm" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Minute" />
    </Time>
    <ItemGroup>
      <My-AssemblyInfo Include="$(My-PropertiesDir)\AutoVersion.cs" />
      <Compile Include="@(My-AssemblyInfo)" />
    </ItemGroup>
    <MakeDir Directories="$(My-PropertiesDir)" />
    <PropertyGroup>
      <GeneratedAssemblyVersion>$(ManualMajorVersion).$(Year)$(ManualMinorVersion).$(Month)$(Day).$(Hour)$(Minute)</GeneratedAssemblyVersion>
    </PropertyGroup>
    <AssemblyInfo OutputFile="@(My-AssemblyInfo)" CodeLanguage="CS" AssemblyFileVersion="$(GeneratedAssemblyVersion)" AssemblyInformationalVersion="$(GeneratedAssemblyVersion)" AssemblyVersion="$(GeneratedAssemblyVersion)" Condition="$(GeneratedAssemblyVersion) != '' " />
  </Target>
  <!-- END DYNAMIC ASSEMBLY VERSIONING WORK-->

così come il test unitario per verificare da soli:

/// <summary> A test to validate the configured, auto-generated assembly versioning is working as expected </summary>
[Test]
public void AssemblyVersioningTest()
{
    DirectoryInfo currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
    DirectoryInfo versioningDir = new DirectoryInfo(currentDirectory.FullName + "\\" + VERSIONING_DYNAMIC_FILE_DIRECTORY);

    // verify versioning directory located/loaded/exists
    Assert.IsTrue(versioningDir.Exists);

    // locate the VERSIONING_DYNAMIC_FILE file within the VERSIONING_DYNAMIC_FILE_DIRECTORY directory
    string dynamicFilePath = versioningDir.FullName + "\\" + VERSIONING_DYNAMIC_FILE;

    // get the FileInfo for the file that is used to dynamically generate assembly versioning
    FileInfo dynamicVersioningFileInfo = new FileInfo(dynamicFilePath);
    Assert.IsTrue(dynamicVersioningFileInfo.Exists);

    // get the two digit creation Dates/Times for the assembly's file as strings
    // since that's what the versioning reflects
    DateTime dynamicVersioningFileLastWriteTime = dynamicVersioningFileInfo.LastWriteTime;

    #region    Created VERSIONING_DYNAMIC_FILE
    string dynamicVersioningFileLastWriteTimeYear = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("yy");

    string dynamicVersioningFileLastWriteTimeMonth = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("MM");
    string dynamicVersioningFileLastWriteTimeDay = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("dd");

    string dynamicVersioningFileLastWriteTimeHour = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("HH");
    string dynamicVersioningFileLastWriteTimeMinute = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("mm");
    #endregion Created VERSIONING_DYNAMIC_FILE

    // get *this* assembly from the .sln using reflection since this assembly consumes/is dependent upon the versioning functionality we
    // are testing
    Assembly theAssemblyExecutingThisTest = Assembly.GetExecutingAssembly();

    // get this assembly's version
    // we will investigate this to compare it to a reverse-engineering of what we would
    // expect it to be based 
    AssemblyName testingAssemblyName = theAssemblyExecutingThisTest.GetName();
    Version testingAssemblyVersion = testingAssemblyName.Version;

    #region    Generated Assembly Versioning
    // get the first two digits of the assemblyVersion.MinorVersion - these represent the year
    string testingAssemblyVersionMinorYear = testingAssemblyVersion.Minor.ToString().Substring(0, 2);
    // the rest of the digits represent the manually-configured version and can be 1-3 chars long
    string testingAssemblyVersionMinorManual = GetMinorManualFromVersionString(testingAssemblyVersion.Minor.ToString());

    string testingAssemblyVersionBuildMonth = testingAssemblyVersion.Build.ToString("D4").Substring(0, 2);
    string testingAssemblyVersionBuildDay = testingAssemblyVersion.Build.ToString("D4").Substring(2, 2);

    string testingAssemblyVersionRevisionHour = testingAssemblyVersion.Revision.ToString("D4").Substring(0, 2);
    string testingAssemblyVersionRevisionMinute = testingAssemblyVersion.Revision.ToString("D4").Substring(2, 2);
    #endregion Generated Assembly Versioning

    // verify the assembly's minor version: last two digits match of assembly file creation year
    // (pad minorversion 4 spaces in case released minor version is empty)
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeYear,
        testingAssemblyVersionMinorYear,
        "Assembly's minor version: last two digits do not match assembly file last write time year");

    // verify the assembly's minor version is comprised of two digit 'released minor version' + two digit year of assembly file creation date
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeYear + testingAssemblyVersionMinorManual,
        testingAssemblyVersionMinorYear + testingAssemblyVersionMinorManual,
        "Assembly's minor version: not comprised of two digit year of assembly file last write time date + dynamically-sized 'minor manual version' + ");

    // verify the Assembly's build version is comprised of two digit month + two digit day of assembly file creation date
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeMonth + dynamicVersioningFileLastWriteTimeDay,
        testingAssemblyVersionBuildMonth + testingAssemblyVersionBuildDay,
        "Assembly's build version: not comprised of two digit month + two digit day of assembly file last write time date");

    // verify the Assembly's revision version is comprised two digit hour + two digit minute of assembly file creation date
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeHour + dynamicVersioningFileLastWriteTimeMinute,
        testingAssemblyVersionRevisionHour + testingAssemblyVersionRevisionMinute,
        "Assembly's revision version: comprised two digit hour + two digit minute of assembly file last write time date");
}

Altri suggerimenti

Abbiamo risolto un problema simile includendo i file SDK V&M (Microsoft.TextTemplating.Build.Tasks.dll, Microsoft.TextTemplating.Targets, Microsoft.VisualStudio.TextTemplating.sdk.host.1x.0.dll) in un cartellone esterno_librarie controllo.

IMO Questo è l'unico modo vero per gestire gli SDK di terze parti in grandi progetti: l'installazione su ogni singola macchina per lo sviluppo e il server Build è troppo fragile per essere pratico.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top