Teamcity running build steps even when tests fail

DevDave picture DevDave · Mar 6, 2013 · Viewed 11.3k times · Source

I am having problems with Teamcity, where it is proceeding to run build steps even if the previous ones were unsuccessful.

The final step of my Build configuration deploys my site, which I do not want it to do if any of my tests fail.

Each build step is set to only execute if all previous steps were successful.

In the Build Failure Conditions tab, I have checked the following options under Fail build if:

-build process exit code is not zero
-at least one test failed
-an out-of-memory or crash is detected (Java only)

This doesn't work - even when tests fail TeamCity deploys my site, why?

I even tried to add an additional build failure condition that will look for specific text in the build log (namely "Test Run Failed.")

When viewing a completed test in the overview page, you can see the error message against the latest build:

"Test Run Failed." text appeared in build log

But it still deploys it anyway.

Does anyone know how to fix this? It appears that the issue has been running for a long time, here.

Apparently there is a workaround:

So far we do not consider this feature as very important as there is an obvious workaround: the script can check the necessary condition and do not produce the artifacts as configured in TeamCity.

e.g. a script can move the artifacts from a temporary directory to the directory specified in the TeamCity as publish artifacts from just before the finish and in case the build operations were successful.

But that is not clear to me on exactly how to do that, and doesn't sound like the best solution either. Any help appreciated.

Edit: I was also able to workaround the problem with a snapshot dependency, where I would have a separate 'deploy' build that was dependent on the test build, and now it doesn't run if tests fail.

This was useful for setting the dependency up.

Answer

adamjcooper picture adamjcooper · Mar 13, 2013

This is a known problem as of TeamCity 7.1 (cf. http://youtrack.jetbrains.com/issue/TW-17002) which has been fixed in TeamCity 8.x+ (see this answer).

TeamCity distinguishes between a failed build and a failed build step. While a failing unit test will fail the build as a whole, unfortunately TeamCity still considers the test step itself successful because it did not return a non-zero error code. As a result, subsequent steps will continue running.

A variety of workarounds have been proposed, but I've found they either require non-trivial setup or compromise on the testing experience in TeamCity.

However, after reviewing a suggestion from @arex1337, we found an easy way to get TeamCity to do what we want. Just add an extra Powershell build step after your existing test step that contains the following inline script (replacing YOUR_TEAMCITY_HOSTNAME with your actual TeamCity host/domain):

$request = [System.Net.WebRequest]::Create("http://YOUR_TEAMCITY_HOSTNAME/guestAuth/app/rest/builds/%teamcity.build.id%")
$xml = [xml](new-object System.IO.StreamReader $request.GetResponse().GetResponseStream()).ReadToEnd()
Microsoft.PowerShell.Utility\Select-Xml $xml -XPath "/build" | % { $status = $_.Node.status }

if ($status -eq "FAILURE") {
    throw "Failing this step because the build itself is considered failed. This is our way to workaround the fact that TeamCity incorrectly considers a test step to be successful even if there are test failures. See http://youtrack.jetbrains.com/issue/TW-17002"
}

This inline PowerShell script is just using the TeamCity REST API to ask whether or not the build itself, as a whole, is considered failed (the variable %teamcity.build.id%" will be replaced by TeamCity with the actual build id when the step is executed). If the build as a whole is considered failed (say, due to a test failure), then this PowerShell script throws an error, causing the process to return a non-zero error code which results in the individual build step itself to be considered unsuccessful. At that point, subsequent steps can be prevented from running.

Note that this script uses guestAuth, which requires the TeamCity guest account to be enabled. Alternately, you can use httpAuth instead, but you'll need to update the script to include a TeamCity username and password (e.g. http://USERNAME:PASSWORD@YOUR_TEAMCITY_HOSTNAME/httpAuth/app/rest/builds/%teamcity.build.id%).

So, with this additional step in place, all subsequent steps set to execute "Only if all previous steps were successful" will be skipped if there are any previous unit test failures. We're using this to prevent automated deployment if any of our NUnit tests are not successful until JetBrains fixes the problem.

Thanks to @arex1337 for the idea.