12

我正在设置 TeamCity(从 CruiseControl.NET 迁移),我正在努力让它通过 MSBuild 执行增量构建。

我有一个小的 .proj 文件,其中包含一个基本构建脚本,用于调用我的解决方案的构建,其中包含从 TeamCity 提供的一些参数。当我手动调用脚本时,MSBuild 的增量构建功能会启动并在后续运行中完全跳过构建。

通过 Team City 调用此脚本时,构建日志每次都会显示干净编译的输出。我在构建过程中观察了工作目录,并且可以看到之前构建的输出并没有消失。

我还通过远程连接到服务器并从命令提示符运行 MSBuild,从该目录手动调用构建脚本。以这种方式运行它会在第一次调用后触发预期的增量构建。

即使从仪表板开始构建而没有进行任何更改,也会发生完整的重建。

我无法确定原因,但似乎有些东西给 MSBuild 一种印象,即它正在获得新的更改并导致它在每次运行时都执行重建。我在 TeamCity 文档中看不到太多可以解释这一点的内容——我的期望是,如果源代码控制系统没有更改,它就不会更新工作文件夹。

TeamCity 是否将一些参数传递给触发重建的构建过程?我可以查看这些参数吗?


在检查了详细的 MSBuild 日志(/v:d命令行开关)后,发生完全重建的原因是由于每次构建时目录.NETFramework,Version=v4.0.AssemblyAttributes.cs中的文件都会更新。<Agent>\temp\buildTmp

该文件通常位于%TMP%\.NETFramework,Version=v4.0.AssemblyAttributes.cs; TeamCity 正在更改本地临时目录环境变量以引用代理的临时文件夹。不幸的是,这个文件是由Microsoft.Common.targets构建过程的一部分在不存在时创建的。在每次构建之前删除“临时”文件会导致每次构建都会创建它,并在每个项目文件的构建中动态引用。

我需要找到一种方法来防止在每次构建时重新创建此文件。

4

3 回答 3

11

此问题的解决方法是自定义 MSBuild 过程以设置将创建“目标框架 Moniker 程序集属性”文件(问题中提到的文件的正确名称)的路径。

TargetFrameworkMonikerAssemblyAttributesPath属性在 Microsoft.Common.targets 中定义,确定应在何处创建文件。通过覆盖此属性,可以更改位置以使用不同的位置。

这是一个可用于实现合适替换的脚本:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>
    <PrepareForBuildDependsOn>
        $(PrepareForBuildDependsOn);
        _SetTargetFrameworkMonikerAssemblyAttributesPath
    </PrepareForBuildDependsOn>
</PropertyGroup>

<Target 
    Name="_SetTargetFrameworkMonikerAssemblyAttributesPath"
    Condition="'$(TEAMCITY_VERSION)' != ''">

    <PropertyGroup>
        <TargetFrameworkMonikerAssemblyAttributesDir
            Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
            $([MSBuild]::GetRegistryValue("HKEY_CURRENT_USER\Environment", "TMP"))
        </TargetFrameworkMonikerAssemblyAttributesDir>
        <TargetFrameworkMonikerAssemblyAttributesDir
            Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
            $([MSBuild]::GetRegistryValue("HKEY_CURRENT_USER\Environment", "TEMP"))
        </TargetFrameworkMonikerAssemblyAttributesDir>
        <TargetFrameworkMonikerAssemblyAttributesDir 
            Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
            $(USERPROFILE)
        </TargetFrameworkMonikerAssemblyAttributesDir>
        <TargetFrameworkMonikerAssemblyAttributesDir
            Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
            $([System.IO.Path]::Combine('$(WINDIR)', 'Temp'))
        </TargetFrameworkMonikerAssemblyAttributesDir>
        <TargetFrameworkMonikerAssemblyAttributesPath>
            $([System.IO.Path]::Combine('$(TargetFrameworkMonikerAssemblyAttributesDir)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))
        </TargetFrameworkMonikerAssemblyAttributesPath>
    </PropertyGroup>

    <Message Text="Target Framework Moniker Assembly Attributes path is &quot;$(TargetFrameworkMonikerAssemblyAttributesPath)&quot;" Importance="low" />

</Target>

只有在指定为属性时才会执行目标TEAMCITY_VERSION,这应该是在 TeamCity 代理执行构建时。

注意:的每个子元素都PropertyGroup应该在一行上。它们分布在多行中以增加此处的可读性,但额外的换行符会导致脚本失败。

当目标运行时,它会尝试根据注册表中定义的用户环境变量构建合适的路径,首先查找TMPand TEMP,然后返回到用户的配置文件文件夹,最后返回C:\Windows\Temp目录。这与 System.Path.GetTempPath() 记录的顺序相匹配,并且应该导致行为匹配 TeamCity 之外的 MSBuild 执行。

这应该保存为系统某处的 .targets 文件,并使用<Import>元素导入到 TeamCity 服务器正在构建的项目的 .csproj 文件中。我在我的 MSBuild 扩展目录 ( C:\Program Files\MSBuild\) 下添加了脚本,并通过添加以下导入元素来引用它:

<Import Project="$(MSBuildExtensionsPath)\TeamCity\TeamCity.Incremental.targets" />

Import 元素的位置/顺序无关紧要,但我建议将它包含在<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />应该出现在每个 .csproj 文件中的之后。

于 2012-08-13T12:00:47.267 回答
2

正如 Paul Turner 所提到的,调整 TargetFrameworkMonikerAssemblyAttributesPath 可以解决这个问题。我没有在 Microsoft 的构建系统脚本中与 High Magick 作斗争,而是在 TeamCity 项目参数中添加了一个环境变量来设置 TargetFrameworkMonikerAssemblyAttributesPath。

在 TeamCity 的项目设置中,我将env.TargetFrameworkMonikerAssemblyAttributesDir设置为%env.windir%\Temp

于 2017-05-15T15:51:49.813 回答
1

TeamCity 2017.3 中仍然存在此问题。

我想找到一种比接受的答案详细说明的更容易跟踪的解决方法,所以我做了以下事情:

  1. 我将我的文件副本签入.NETFramework,Version=v4.7.AssemblyAttributes.cs到我的 VCS
  2. 我向使用具有以下属性的 MSBuild 的构建配置添加了一个新的构建步骤:
    • 跑步者类型:命令行
    • 步骤名称:CopyAssemblyAttributesFile
    • 运行:自定义脚本
    • 自定义脚本copy "%system.teamcity.build.workingDir%\<path_to_AssemblyAttributes.cs Dir>\." "%env.TEMP%\."

这将第一次复制我的 AssemblyAttributes 文件版本,其中包含初始 VCS 签出的时间戳,

随后 MSBuild 似乎认为它是同一个文件,因为时间戳将保持一致并且现在将正确执行增量构建,这可以从代理上的构建日志中验证。

于 2017-07-27T18:18:19.873 回答