0

我们正在使用 T4 文件来管理我们的程序集版本;基本上,我们遵循这些程序在每个构建上重新生成我们的程序集版本。这是通过让 .csproj 使用Modeling SDK for VS 2013使用 MSBUILD 自定义 T4 重新生成配置来完成的

这很好用!不幸的是,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 的托管构建控制器以在构建期间转换我的 T4 文件?

4

2 回答 2

0

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

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

于 2014-03-27T00:22:22.327 回答
0

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

每次构建此项目 Application.Versioning.csproj 时,在第 3 方、Nuget 安装的“MSBuildCommunity Tasks”库中定义的 MSBUILD 任务会动态生成[AssemblyFileVersion][AssemblyInformationalVersion][AssemblyVersion]基于当前的 UTC 日期时间,并将它们输入到一个新文件 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");
}
于 2013-11-08T05:37:34.207 回答