Skip to content

CI Host TeamCity

Scott Singleton edited this page May 10, 2026 · 1 revision

CI Host: TeamCity

TeamCityHost resolves automatically when TEAMCITY_VERSION is set. Inherits the common CiHost surface (CI Host Integrations) and adds TeamCity-specific properties and commands.

Detection

if (CiHost is TeamCityHost tc)
{
    // TeamCity specifics
}

Read-only properties

Property Env var
Version TEAMCITY_VERSION
ProjectName TEAMCITY_PROJECT_NAME
BuildConfigurationName TEAMCITY_BUILDCONF_NAME
BuildNumber BUILD_NUMBER
VcsNumber BUILD_VCS_NUMBER
BuildPropertiesFile TEAMCITY_BUILD_PROPERTIES_FILE (path to the per-build .properties file)

The .properties file at BuildPropertiesFile carries the full set of typed build properties — including parameter values, agent properties, and (when configured) secret tokens. Tamp doesn't currently parse it; if you need values from there, read the file directly.

Emit commands

TeamCity uses ##teamcity[...] service messages with strict escaping rules (pipes, apostrophes, brackets, newlines). The escape logic is built into every emit method, so values pass through cleanly:

tc.OpenGroup("Build");                  // ##teamcity[blockOpened name='Build']
tc.CloseGroup();                        // ##teamcity[blockClosed name='']
tc.LogWarning("careful");               // ##teamcity[message text='careful' status='WARNING']
tc.LogError("compile failed");          // ##teamcity[message text='compile failed' status='ERROR']
tc.SetVariable("env.MY_VAR", "value");  // ##teamcity[setParameter name='env.MY_VAR' value='value']

Setting a parameter via SetVariable lets subsequent build steps read the value. The env. prefix exposes it as an environment variable to scripts.

TeamCity-specific extras

tc.UpdateBuildNumber("1.2.3");           // ##teamcity[buildNumber '1.2.3']
tc.PublishArtifact("artifacts/*.nupkg");  // ##teamcity[publishArtifacts 'artifacts/*.nupkg']
tc.ReportBuildProblem("compile failed");  // ##teamcity[buildProblem description='compile failed']

ReportBuildProblem is stronger than LogError — it marks the build itself as having a problem, even if the rest of the pipeline succeeds.

Escape rules

TeamCity service messages have specific escape requirements:

Char Becomes
` `
' `
\n `
\r `
[ `
] `

The TeamCityHost adapter handles all of this transparently — pass any string through LogError / LogWarning / SetVariable / artifacts and the escaping is correct without thought.

Recipes

Override the build number from git

Target ResolveBuildNumber => _ => _.Executes(() =>
{
    var bn = $"1.0.0-{Git.Branch}-{Git.Commit[..7]}";
    if (CiHost is TeamCityHost tc) tc.UpdateBuildNumber(bn);
});

Publish a glob of artifacts

Target PublishArtifacts => _ => _
    .DependsOn(nameof(Pack))
    .Executes(() =>
    {
        if (CiHost is TeamCityHost tc)
            tc.PublishArtifact("artifacts/*.nupkg => packages.zip");
    });

The => archive.zip suffix is TeamCity's own syntax for "bundle these files into a zip on the build summary."

Mark the build as failed with a clear cause

Target Validate => _ => _.Executes(() =>
{
    if (!ConfigIsValid())
    {
        if (CiHost is TeamCityHost tc) tc.ReportBuildProblem("Configuration validation failed");
        Verify.Fail("config invalid");
    }
});

ReportBuildProblem shows the description prominently in the TeamCity build overview, distinct from the generic "build failed" status.

See also

Clone this wiki locally