Powershell with Git Command Error Handling - automatically abort on non-zero exit code from external program

﹥>﹥吖頭↗ 提交于 2020-02-25 04:18:10

问题


I use Git to deploy my web application. So in Teamcity I prepare my application (compilation, minify JS and HTML, delete unused files, etc...) and then I have a Powershell build step :

$ErrorActionPreference = "Stop"
git init
git remote add origin '%env.gitFolder%'
git fetch
git reset --mixed origin/master
git add .
git commit -m '%build.number%'
git push origin master

But if an exception throw, the script continue (even if I set $ErrorActionPreference = "Stop") and the build is successful.

I want the script to stop when there is an error, and the build to failed.

I tried to put Format stderr output as: error on the build step and Fail build if: an error message is logged by build runner, so the build failed, but the script continue, and so it's creating an stupid commit.

I try to put a try-catch in my script, but it doesn't enter in the catch...

Does anyone have an idea to stop the script and failed the build on error ?

Sorry for my English, I'm French... ^^


回答1:


The $ErrorActionPreference variable does not apply to calling external utilities ([console] applications) such as git.

There are only two ways to determine success vs. failure of an external utility:

  • By examining the automatic $LASTEXITCODE variable, which PowerShell sets to the exit code reported by the external utility.
    By convention, a value of 0 indicates success, whereas any nonzero value indicates failure. (Do note that some utilities, e.g., robocopy.exe, use certain nonzero exit codes to communicate non-error conditions too.)

  • If you're not interested in the specific exit code reported, you can examine the Boolean automatic variable $?, which reflects $True for exit code 0, and $False for any nonzero exit code.

    • Caveat: Up to at least PowerShell [Core] 7.0.0-rc2, $? can falsely reflect $false when $LASTEXITCODE is 0 and a stderr redirection (2> or *>) is used and the command emitted stderr output (which in itself doesn't necessarily indicate failure) - see this GitHub issue.

Acting on a failure requires explicit action, typically by using the Throw keyword to generate a script-terminating error.


Clearly, checking $LASTEXITCODE / $? after every external-utility call is cumbersome, so here's a wrapper function that facilitates this process:

function Invoke-Utility {
<#
.SYNOPSIS
Invokes an external utility, ensuring successful execution.

.DESCRIPTION
Invokes an external utility (program) and, if the utility indicates failure by 
way of a nonzero exit code, throws a script-terminating error.

* Pass the command the way you would execute the command directly.
* Do NOT use & as the first argument if the executable name is not a literal.

.EXAMPLE
Invoke-Utility git push

Executes `git push` and throws a script-terminating error if the exit code
is nonzero.
#>
  $exe, $argsForExe = $Args
  $ErrorActionPreference = 'Continue' # to prevent 2> redirections from triggering a terminating error.
  try { & $exe $argsForExe } catch { Throw } # catch is triggered ONLY if $exe can't be found, never for errors reported by $exe itself
  if ($LASTEXITCODE) { Throw "$exe indicated failure (exit code $LASTEXITCODE; full command: $Args)." }
}

Now you just need to prepend Invoke-Utility  to all your git calls, and if any of them reports a nonzero exit code, the script is aborted.

If that is too verbose, define an alias for your function: Set-Alias iu Invoke-Utility, in which case you only need to prepend iu :

iu git init
iu git remote add origin '%env.gitFolder%'
iu git fetch
# ...



回答2:


I believe the problem here is that the error thrown by git is not trappable by PS.

Illustration:

try {
    git push
    Write-Host "I run after the git push command"
}
catch {
    Write-Host "Something went wonky"
}

Note the missing Write-Host from the catch block!

This is where we need to look at the exit code of the git commands.

The easiest way (I know) in PowerShell is to check the value of $? (more information on $? here: What is `$?` in Powershell?)

try {
    git push
    if (-not $?) {
        throw "Error with git push!"
    }
    Write-Host "I run after the git push command"
}
catch {
    Write-Host "Something went wonky"
    throw
}

Check our custom error (now caught by the catch block)!



来源:https://stackoverflow.com/questions/60266883/automatically-abort-powershell-script-when-external-process-returns-a-non-zero-e

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!