09 February 2015

I have spent some time researching incremental builds in TeamCity. I’ve already written a post about it some time ago(Sequential build in TC). This solution is far from ideal, that’s why I’ve never used it in production environment. JetBrains doesn’t offer any real solution for this problem (they opened a ticket tho’) and since I’m not the only guy on the internet with this problem, a guy from StackOverflow came up with a similar, though more elegant, hack.

This solution works fine if we assume that you have a single build agent on a build machine. If you have multiple build agents on a single machine, the following target configuration should be used:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<PropertyGroup>
		<PrepareForBuildDependsOn>
			$(PrepareForBuildDependsOn);
			_SetTargetFrameworkMonikerAssemblyAttributesPath
		</PrepareForBuildDependsOn>
	</PropertyGroup>
	<Target 
		Name="_SetTargetFrameworkMonikerAssemblyAttributesPath"
		Condition="'$(TEAMCITY_VERSION)' != '' And '$(TEAMCITY_AGENT_NAME)' != '' And '$(TEAMCITY_BUILDCONFIGURATION_ID)' != ''">
		<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)','$(TEAMCITY_AGENT_NAME)-$(TEAMCITY_BUILDCONFIGURATION_ID)$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))</TargetFrameworkMonikerAssemblyAttributesPath>
		</PropertyGroup>
		<Message Text="Target Framework Moniker Assembly Attributes path is "$(TargetFrameworkMonikerAssemblyAttributesPath)"" Importance="Normal" ></Message>
	</Target>
</Project>

This is not enough, TEAMCITY_AGENT_NAME and TEAMCITY_BUILDCONFIGURATION_ID are not set by TeamCity as is TEAMCITY_VERSION, so we have to manually set them in the build step configuration.

We can pass these values in a build by using the following line for Command line parameters in Visual Studio (sln) or MSBuild runner type.

/p:TEAMCITY_AGENT_NAME=%teamcity.agent.name% /p:TEAMCITY_BUILDCONFIGURATION_ID=%system.teamcity.buildType.id%

This is far from perfect, but it does the trick, hopefully JetBrains will allow overrides of TEMP dir soon and no nasty hacks will be required.



blog comments powered by Disqus