带有 Git 命令错误处理的 Powershell - 自动中止外部程序的非零退出代码 [英] Powershell with Git Command Error Handling - automatically abort on non-zero exit code from external program

查看:13
本文介绍了带有 Git 命令错误处理的 Powershell - 自动中止外部程序的非零退出代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Git 来部署我的 Web 应用程序.所以在 Teamcity 中,我准备了我的应用程序(编译、缩小 JS 和 HTML、删除未使用的文件等...),然后我有一个 Powershell 构建步骤:

$ErrorActionPreference = "停止"混帐初始化git remote add origin '%env.gitFolder%'混帐git reset --mixed origin/mastergit 添加.git commit -m '%build.number%'git push origin master

但是如果抛出异常,脚本会继续(即使我设置了 $ErrorActionPreference = "Stop")并且构建成功.

我希望脚本在出现错误时停止,并且构建失败.

我尝试在构建步骤中将 Format stderr output as: errorFail build if: an error message is logging by build runner,因此构建失败,但脚本继续运行,因此它创建了一个愚蠢的提交.

我尝试在我的脚本中放入一个 try-catch,但它没有进入 catch...

有没有人有停止脚本的想法并因错误而导致构建失败?

对不起我的英语,我是法国人...^^

解决方案

$ErrorActionPreference 变量不适用于调用外部实用程序em>([控制台] 应用程序)例如 git.

只有两种方法可以确定外部实用程序的成功与否:

  • 通过检查自动$LASTEXITCODE变量,PowerShell将其设置为外部实用程序报告的**退出代码**.
    按照惯例,0 表示成功,而任何非零值表示失败.(请注意,某些实用程序,例如 robocopy.exe,也使用某些非零退出代码来传达非错误条件.)

  • 如果您对报告的特定退出代码不感兴趣,您可以检查 Boolean 自动变量 $?,它反映退出代码 0$True 和任何非零退出代码的 $False.

    • 注意事项:自 PowerShell (Core) 7.1 起,有两个错误;这两个都是通过 PSNotApplyErrorActionToStderr 实验性功能 (!) 在 7.2 的预览 版本中暂时修复的(所有实验性功能在新版本中默认打开已安装的预览版本)- 希望这些修复能够使其成为 7.2:

      • $? 可以在 $LASTEXITCODE0 时错误地反映 $false 使用 stderr 重定向(2>*>) 发出 stderr 输出的命令(它本身不不一定表示失败)- 请参阅 GitHub 问题 #10512.

        • 因此形成只查询 $LASTEXITCODE 而不是 $? 来推断失败与成功的好习惯.
      • 如果 $ErrorActionPreference 设置为 'Stop' 并且您碰巧使用了 2>*>; 使用外部程序并且该程序产生实际的 stderr 输出,$ErrorActionPreference 意外确实 应用并导致脚本终止错误(无论外部程序是否发出信号通过非零退出代码导致的实际失败) - 参见 GitHub 问题 #4002

对失败采取行动需要显式行动,通常通过使用 Throw 关键字来生成脚本-终止错误.

但是,请注意,有一个 待定 RFC 建议正确集成将外部程序调用到 PowerShell 未来版本的错误处理机制中.


显然,在每次外部实用程序调用后检查 $LASTEXITCODE/$? 很麻烦,所以这里有一个 包装函数 来促进这个过程:

注意:虽然此功能有效,但它不能尝试补偿将带有嵌入式双引号的参数传递给外部程序.要获得此补偿,您可以使用 Native 模块中的 iee 函数,可通过 Install-Module Native 从 PowerShell Gallery 安装.

function Invoke-Utility {<#.概要调用外部实用程序,确保成功执行..描述调用外部实用程序(程序),如果该实用程序通过以下方式指示失败非零退出代码的方式,引发脚本终止错误.* 以直接执行命令的方式传递命令.* 不要使用 &如果可执行文件名称不是文字,则作为第一个参数..例子调用实用程序 git push执行 `git push` 并在退出代码时抛出脚本终止错误非零.#>$exe, $argsForExe = $Args# 解决方法:防止 2>应用于调用此函数的重定向# 意外触发终止错误.# 请参阅 https://github.com/PowerShell/PowerShell/issues/4002 上的错误报告$ErrorActionPreference = '继续'尝试 { &$exe $argsForExe } catch { Throw } # 只有在找不到 $exe 时才会触发 catch,不会因为 $exe 本身报告的错误而触发if ($LASTEXITCODE) { 抛出$exe 表示失败(退出代码 $LASTEXITCODE;完整命令:$Args)".}}

现在您只需要将 Invoke-Utility 添加到您所有的 git 调用中,如果其中任何一个报告非零退出代码,脚本就会中止.>

如果这太冗长,请为您的函数定义一个别名:Set-Alias iu Invoke-Utility,在这种情况下,您只需添加 iu :

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

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

解决方案

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.

    • Caveats: As of PowerShell (Core) 7.1, there are two bugs; both these are tentatively fixed via the PSNotApplyErrorActionToStderr experimental feature (!) in preview versions of 7.2 (all experimental features are turned on by default in newly installed preview versions) - let's hope these fixes make it into 7.2:

      • $? 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 GitHub issue #10512.

        • It is therefore a good habit to form to query only $LASTEXITCODE, not $? to infer failure vs. succcess.
      • If $ErrorActionPreference is set to 'Stop' and you happen to use 2> or *> with an external program and that program produces actual stderr output, $ErrorActionPreference unexpectedly does apply and causes a script-terminating error (whether or not the external program signals actual failure via a nonzero exit code) - see GitHub issue #4002

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.1 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
  # Workaround: Prevents 2> redirections applied to calls to this function
  #             from accidentally triggering a terminating error.
  #             See bug report at https://github.com/PowerShell/PowerShell/issues/4002
  $ErrorActionPreference = 'Continue'
  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
# ...

这篇关于带有 Git 命令错误处理的 Powershell - 自动中止外部程序的非零退出代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆