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

前端 未结 2 1892
猫巷女王i
猫巷女王i 2020-12-01 19:17

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 b

2条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-01 19:50

    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, $? 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.

      • It is therefore a good habit to form to query only $LASTEXITCODE, not $? to infer failure vs. succcess.

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

    However, note that there is a pending RFC that proposes proper integration of calls to external programs into PowerShell's error-handling mechanisms for future versions.


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

    Note: While this function works, it does not try to compensate for the broken-up-to-at-least-v7.0 passing of arguments with embedded double quotes to external programs. To get this compensation, you can use the iee function from the Native module, installable from the PowerShell Gallery via Install-Module Native.

    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
    # ...
    

提交回复
热议问题