How do I get errors to propagate in the TeamCity PowerShell runner
As doc'd in the friendly TeamCity manual:
Setting Error Output to
Error
and adding build failure conditionIn case syntax errors and exceptions are present, PowerShell writes them to stderr. To make TeamCity fail the build, set Error Output option to Error and add a build failure condition that will fail the build on any error output.
The keys to making this work is to change two defaults:
- At the top level in the Build Failure Conditions, switch on an error message is logged by build runner:
- In the [PowerShell] Build Step, Show advanced options and set Error output: Error
In 9.1 the following works (I wouldn't be surprised if it works for earlier versions too):
- create a PowerShell Build Step with the default options
- change the dropdown to say Script: Source code
- Add a
trap { Write-Error "Exception $_" ; exit 98 }
at the top of the script (Optional but more correct IMO for the kind of scripting that's appropriate for within TeamCity build scripts)
Show advanced options and switch on Options: Add -NoProfile argument
(Optional, but for me this should be the default as it renders more clearly as suggested by @Jamal Mavadat)
Show advanced options and switch on Error output: Error
(ASIDE @JetBrains: if the label was "Format stderr output as" it would be less misleading)
This covers the following cases:
- Parse errors [bubble up as exceptions and stop execution immediately]
- Exceptions [
throw
n directly or indirectly in your PS code show and trigger an exit code for TC to stop the build] An explicitexit n
in the script propagates out to the build (and fails it if non-zero)
There is an known bug in TeamCity that causes the behavior that the original poster noticed.
It is easy to work around, however.
At the end of your PowerShell script, add output indicating that the end of the script has been reached:
Echo "Packaging complete (end of script reached)"
Then, set up a new Build Failure Condition on your build to fail if the text you are echoing is NOT present in the output.
You're over-thinking things. Try this:
Script
File
Script File
Script.ps1
You don't need to give this a path - by default, it's relative to the checkout directory.
Script execution mode
Put script into PowerShell stdin with "-Command -" arguments
This is exactly what I use to run a bunch of powershell scripts within Teamcity.
Update
I missed the bit in the original post about having failures in the powershell script fail the build. Apologies!
I've solved that part of the puzzle in two different ways.
For regular powershell scripts
Wrap the main code block in a try...catch
; if an exception occurs, return a non-zero integer value. For successful execution, return 0.
This convention of returning zero for success dates back a very long way in history - it's used by Unix/Linux systems, DOS, CP/M and more.
For PSake build scripts
Use a wrapper powershell script to invoke psake and directly set the result of the teamcity build by writing a response message to stdout.
At the start of the script, define a status message that represents failure:
$global:buildResult = "#teamcity[buildStatus status='FAILURE' text='It died.']
Within the psake script, update $global:buildResult
to indicate success in a dedicated task that's run last of all.
$global:buildResult = "#teamcity[buildStatus status='SUCCESS' text='It lives.']
At the end of the wrapper script, output the status message
write-host $global:buildResult
If anything in the build script fails, that last task won't run, and the default message (indicating failure) will be output.
Either way, Teamcity will pick up on the message and set the build status appropriately.