powershell teamcity exit-code

¿Por qué mis códigos de salida de PowerShell siempre son "0"?



teamcity exit-code (4)

Tengo un script de Powershell de la siguiente manera

##teamcity[progressMessage ''Beginning build''] # If the build computer is not running the appropriate version of .NET, then the build will not run. Throw an error immediately. if( (ls "$env:windir/Microsoft.NET/Framework/v4.0*") -eq $null ) { throw "This project requires .NET 4.0 to compile. Unfortunatly .NET 4.0 doesn''t appear to be installed on this machine." ##teamcity[buildStatus status=''FAILURE'' ] } ##teamcity[progressMessage ''Setting up variables''] # Set up varriables for build script $invocation = (Get-Variable MyInvocation).Value $directorypath = Split-Path $invocation.MyCommand.Path $v4_net_version = (ls "$env:windir/Microsoft.NET/Framework/v4.0*").Name $nl = [Environment]::NewLine Copy-Item -LiteralPath "$directorypath/packages/NUnit.2.6.2/lib/nunit.framework.dll" "$directorypath/Pandell.Tests/bin/debug" -Force ##teamcity[progressMessage ''Using msbuild.exe to build the project''] # Build the project using msbuild.exe. # note, we''ve already determined that .NET is already installed on this computer. cmd /c C:/Windows/Microsoft.NET/Framework/$v4_net_version/msbuild.exe "$directorypath/Pandell.sln" /p:Configuration=Release cmd /c C:/Windows/Microsoft.NET/Framework/$v4_net_version/msbuild.exe "$directorypath/Pandell.sln" /p:Configuration=Debug # Break if the build throws an error. if(! $?) { throw "Fatal error, project build failed" ##teamcity[buildStatus status=''FAILURE'' ] } ##teamcity[progressMessage ''Build Passed''] # Good, the build passed Write-Host "$nl project build passed." -ForegroundColor Green ##teamcity[progressMessage ''running tests''] # Run the tests. cmd /c $directorypath/build_tools/nunit/nunit-console.exe $directorypath/Pandell.Tests/bin/debug/Pandell.Tests.dll # Break if the tests throw an error. if(! $?) { throw "Test run failed." ##teamcity[buildStatus status=''FAILURE'' ] } ##teamcity[progressMessage ''Tests passed'']

Por lo que creo, un Throw no capturado dará como resultado un código de salida de 1 , pero desafortunadamente TeamCity está diciendo lo contrario.

[19:32:20]Test run failed. [19:32:20]At C:/BuildAgent/work/e903de7564e599c8/build.ps1:44 char:2 [19:32:20]+ throw "Test run failed." [19:32:20]+ ~~~~~~~~~~~~~~~~~~~~~~~~ [19:32:20] + CategoryInfo : OperationStopped: (Test run failed.:String) [], [19:32:20] RuntimeException [19:32:20] + FullyQualifiedErrorId : Test run failed. [19:32:20] [19:32:20]Process exited with code 0 [19:32:20]Publishing internal artifacts [19:32:20][Publishing internal artifacts] Sending build.finish.properties.gz file [19:32:20]Build finished

También podría ser importante tener en cuenta que mi Execution Mode está configurado para Execute .ps1 script with "-File" arguement .

Traté de cambiarlo a Put script into PowerShell stdin with "-Command -" arguements pero luego falló con un código de salida de 1 incluso con pasar las pruebas. Estoy seguro de que ejecutarlo como -File va a ser el camino correcto.

Si abro el script ubicado en C:/BuildAgent/work/e903de7564e599c8/build.ps1 y lo ejecuto manualmente en CMD, hace lo mismo ... IE: las pruebas fallidas fallan, y el %errorlevel% sigue siendo 0 .

AUN, si lo ejecuto en PowerShell y llamo a $LASTEXITCODE , devuelve el código correcto cada vez.


Estaba teniendo este problema exacto mientras ejecutaba el archivo, pero por alguna razón la sintaxis de trampa o la sintaxis de ''salida'' proporcionada por Kevin no funcionaba en mi escenario. No estoy seguro por qué, pero solo en caso de que alguien más tenga el mismo problema, utilicé la siguiente sintaxis y funcionó para mí:

try{ #DO SOMETHING HERE } catch { Write-Error $_ ##teamcity[buildStatus status=''FAILURE''] [System.Environment]::Exit(1) }


Este es un problema conocido con PowerShell. Ejecutar un script con -file devuelve un código de salida de 0 cuando no debería.

(Actualización: los siguientes enlaces ya no funcionan. Busque o informe sobre este problema en https://windowsserver.uservoice.com/forums/301869-powershell )

Como usar -command no funcionaba para ti, podrías intentar agregar una trampa en la parte superior del script:

trap { write-output $_ ##teamcity[buildStatus status=''FAILURE'' ] exit 1 }

Lo anterior debería dar como resultado un código de salida apropiado cuando se lanza una excepción.


Hasta que (presumiblemente) se cierre como duplicado de mi auto-respuesta de una pregunta anterior , resumiré la solución más limpia aquí:

  • La mayoría de las otras respuestas implican emitir algo al stderr desde el bit de PowerShell. Esto se puede realizar directamente con TeamCity a través de la salida de formato stderr como opción (configúrelo en Error en lugar del valor predeterminado, que es Advertencia )

  • Sin embargo, críticamente, también es necesario activar "Fail build if: ... Un mensaje de error es registrado por (sic) build runner " en " Failure Conditions " (si cualquiera de las otras respuestas funciona para usted, probablemente ya lo haya encendido, pero IME es muy fácil de olvidar!)


Ninguna de estas opciones funcionó para mí en mi script de powershell por el motivo que sea. Pasé horas en eso.

Para mí, la mejor opción fue poner una capa entre TeamCity y Powershell. Así que simplemente escribí la aplicación de la consola ac # que llama al script de powershell.

La forma en que lo hago es, en teamcity llamamos un script llamado: RemoteFile.ps1

Con argumentos de guión:% system.RemoteServerFQDN%% system.RemoteUser%% system.RemoteUserPassword%% system.RemoteScriptName%% system.RemotePropertiesFile%% system.BuildVersion%% system.RunList%

param ( [Parameter(Mandatory=$true)] $Computername, [Parameter(Mandatory=$true)] $Username, [Parameter(Mandatory=$true)] $Password, [Parameter(Mandatory=$true)] $ScriptName, [Parameter(Mandatory=$true)] $Propfile, [Parameter(Mandatory=$true)] $Version, [Parameter(Mandatory=$true)] [string[]]$DeploymentTypes ) $securePassword = ConvertTo-SecureString -AsPlainText -Force $Password $cred = New-Object System.Management.Automation.PSCredential $Username, $securePassword write-host "Readying to execute invoke-command..." Invoke-Command -ComputerName $Computername -Credential $cred -ScriptBlock { D:/Deployment/PowershellWrapper.exe $using:ScriptName $using:Propfile $using:Version $using:DeploymentTypes } -ArgumentList $ScriptName,$Propfile,$Version,$DeploymentTypes

Que existe en el servidor remoto en la ubicación especificada.

Entonces ese archivo llama a esto: powershellwrapper.exe también en la ubicación especificada (Mi script tiene 4 parámetros para pasar al powershell)

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; namespace PowershellWrapper { class Program { static void Main(string[] args) { try { string argFull = @"""{0} {1} {2} {3}"""; string arg0 = args[0]; string arg1 = args[1]; string arg2 = args[2]; string arg3 = args[3]; string argFinal = string.Format(argFull, arg0, arg1, arg2, arg3); ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = @"powershell.exe"; startInfo.Arguments = argFinal; startInfo.RedirectStandardOutput = false; startInfo.RedirectStandardError = false; startInfo.UseShellExecute = false; startInfo.RedirectStandardInput = true; startInfo.CreateNoWindow = false; Process process = new Process(); process.StartInfo = startInfo; process.Start(); } catch (Exception e) { Console.WriteLine("{0} Exception caught.", e); Console.WriteLine("An error occurred in the deployment.", e); Console.WriteLine("Please contact [email protected] if error occurs."); } } }

}

Y eso llama a mi script con 4 parámetros, siendo el script el primer parámetro, más 3 argumentos. Así que, básicamente, lo que está sucediendo aquí es que estoy ejecutando PowershellWrapper.exe en lugar de la secuencia de comandos de PowerShell para capturar los códigos de salida erróneos 0 y todavía informa de que la secuencia de comandos completa vuelve al registro de TeamCity.

Espero que tenga sentido, funciona como un encanto para nosotros.