【问题标题】:TFService MSBUILD and T4 Code GenerationTFService MSBUILD 和 T4 代码生成
【发布时间】:2013-11-18 12:15:16
【问题描述】:

我们正在使用 T4 文件来管理我们的程序集版本; 基本上我们遵循these procedure 在每个构建上重新生成我们的程序集版本。 这是通过让 .csproj 使用 Modeling SDK for VS 2013 来实现 customize T4 regeneration configuration with MSBUILD。

这很好用!不幸的是,Team Foundation Service 的团队构建似乎不支持在构建时生成 T4 代码,因为构建服务器上的 VS 12 实例在默认安装位置没有 TextTemplating.targets;假设建模/VS SDK 没有安装在构建服务器上(来自 TFService 构建失败日志):

找不到导入的项目“C:\Program Files (x86)\MSBuild\12.0\Microsoft\VisualStudio\v12.0\TextTemplating\Microsoft.TextTemplating.targets”。确认声明中的路径正确,并且该文件存在于磁盘上。

是否有计划将 Microsoft 发布的 VS 2013 插件(VS SDK、Modeling SDK 等)安装到构建服务器映像中?

我是否可以实施一种变通方法,以便当我通过 Git 将代码提交到 Team Foundation Service 时,构建不会中断?

如何配置 TFService 的 Hosted Build Controller 以在其构建期间转换我的 T4 文件?

【问题讨论】:

    标签: code-generation t4 visual-studio-2013 tfsbuild azure-devops


    【解决方案1】:

    我最终创建了一个不同的解决方案来让构建服务器自动对我们的程序集进行版本控制。而不是使用 T4 动态创建一个 AssemblyInfo.cs 文件以通过项目链接共享到解决方案中的其他项目(因此必须处理为此目的而弄清楚如何使文件的重新生成保持最新的烦恼),我完全避免了T4。与第 3 方远程构建机器集成、管理允许 T4 操作等的插件和 SDK 等工作量太大。我从this SO question 找到了一个涉及MSBuild Community Tasks 的更简单的解决方案。与 T4 相比,该解决方案非常简单!以下是它的动摇方式:

    每次构建此项目 Application.Versioning.csproj 时,MSBUILD 任务都会在第 3 方、Nuget 安装的“MSBuildCommunity Tasks”库中定义 根据当前 UTC 日期时间动态生成 [AssemblyFileVersion]、[AssemblyInformationalVersion]、[AssemblyVersion] 并将它们输入到新文件中, AutoVersion.cs,位于该项目的“Properties”目录中(与 AssemblyInfo.cs 文件一起)。 AssemblyInfo.cs 具有这些程序集属性 永远剔除以避免多重定义的程序集属性的构建错误)。在生成 AutoVersion.cs 之后(发生在构建之前),编译器 将上述程序集版本控制属性集成到构建的程序集中。此版本反映了它们构建时的 UTC 时间(见下文)。

    .sln 中的每个其他 .csproj 都订阅此动态的构建时程序集版本控制,创建指向生成的 AutoVersion.cs 文件的文件链接。 这些程序集还必须对其 AssemblyInfo.cs 进行修剪。每次 MyApplication.Versioning.csproj 都会对 .sln 中的所有订阅 .csprojs 进行程序集版本控制 被建造(或重建)。这是版本控制项目的 .csproj:

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

    以及为自己验证的单元测试:

    /// <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");
    }
    

    【讨论】:

      【解决方案2】:

      我们通过在 external_libraries 中包含 V&M SDK 文件(Microsoft.TextTemplating.Build.Tasks.dll、Microsoft.TextTemplating.targets、Microsoft.VisualStudio.TextTemplating.Sdk.Host.1X.0.dll)解决了类似的问题源代码管理中的文件夹。

      IMO 这是在大型项目中管理 3rd 方 SDK 的一种真正方法:在每台单独的开发机器和构建服务器上安装太脆弱,不实用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-03
        • 2016-09-06
        • 2010-09-22
        • 1970-01-01
        • 2010-10-05
        • 2017-06-06
        • 2011-03-22
        相关资源
        最近更新 更多