带有 Git 命令错误处理的 Powershell - 在来自外部程序的非零退出代码时自动中止
Posted
技术标签:
【中文标题】带有 Git 命令错误处理的 Powershell - 在来自外部程序的非零退出代码时自动中止【英文标题】:Powershell with Git Command Error Handling - automatically abort on non-zero exit code from external program 【发布时间】:2018-02-19 11:16:33 【问题描述】:我使用 Git 来部署我的 Web 应用程序。所以在 Teamcity 中,我准备了我的应用程序(编译、缩小 JS 和 html、删除未使用的文件等),然后我有一个 Powershell 构建步骤:
$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
但是如果抛出异常,脚本会继续(即使我设置了$ErrorActionPreference = "Stop"
)并且构建成功。
我希望脚本在出现错误时停止,并且构建失败。
我尝试将Format stderr output as: error
放在构建步骤和Fail build if: an error message is logged by build runner
上,所以构建失败,但脚本继续,因此它创建了一个愚蠢的提交。
我尝试在我的脚本中放置一个 try-catch,但它没有进入 catch...
有没有人有想法停止脚本并因错误导致构建失败?
对不起我的英语,我是法国人... ^^
【问题讨论】:
TeamCity 对 Powershell 错误的处理不是很直观。我之前给过this piece of advice - 但你说 Try/Catch 没有帮助。 【参考方案1】:$ErrorActionPreference
变量不适用于调用外部实用程序([控制台]应用程序),例如git
,最多至少 PowerShell 7.2.x
只有两种方法可以确定外部实用程序的成功与否:
通过检查自动$LASTEXITCODE
变量,PowerShell将其设置为外部实用程序**报告的**退出代码。
按照惯例,0
的值表示成功,而任何 非零 值表示失败。 (请注意,某些实用程序,例如 robocopy.exe
,也使用某些非零退出代码来传达非错误条件。)
如果您对报告的特定退出代码不感兴趣,可以检查布尔自动变量$?
,它反映了$True
用于退出代码 0
,$False
用于任何非零退出代码。
警告:从 PowerShell (Core) 7.1 开始,有两个 错误;这两个都通过PSNotApplyErrorActionToStderr
experimental feature (!) 在 7.2 的 preview 版本中暂时修复(所有实验性功能在新安装的预览版本中默认打开) -让我们希望这些修复能够进入 7.2:
$LASTEXITCODE
是 0
时,$?
可能会错误地反映 $false
并且使用标准错误重定向(2>
或 *>
)和该命令发出 stderr 输出(其本身并不一定表示失败) - 请参阅 GitHub issue #10512。
$LASTEXITCODE
而不是$?
来推断失败与成功的好习惯。
如果 $ErrorActionPreference
设置为 'Stop'
并且您碰巧将 2>
或 *>
与外部程序一起使用并且该程序产生实际的标准错误输出,$ErrorActionPreference
出乎意料地确实适用并导致脚本终止错误(无论外部程序是否通过非零退出代码发出实际故障信号) - 请参阅GitHub issue #4002
对失败采取行动需要显式操作,通常通过使用Throw
关键字来生成脚本终止错误。
显然,在每次外部实用程序调用之后检查 $LASTEXITCODE
/ $?
很麻烦,所以这里有一个 包装函数 可以简化这个过程:
注意:虽然此功能有效,但它不会尝试补偿broken-up-to-at-least-v7.2.x passing of arguments with embedded double quotes to external programs。要获得此补偿,您可以使用 Native module 中的 iee
函数,可通过 Install-Module Native
从 PowerShell 库安装。
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)."
现在您只需在所有 git
调用前添加 Invoke-Utility
,如果其中任何一个报告非零退出代码,则脚本将中止。
如果这太冗长,请为您的函数定义一个别名:Set-Alias iu Invoke-Utility
,在这种情况下,您只需在前面加上 iu
:
iu git init
iu git remote add origin '%env.gitFolder%'
iu git fetch
# ...
【讨论】:
对于 powershell 7.0.3 中的某些本机程序,$LASTEXITCODE
报告非零同时$?
报告 True。 i.imgur.com/4P9au0c.png 在此屏幕截图中,packer
是 packer。
刚才我意识到发生了什么——packer 和 go 都安装了scoop,它在可执行文件周围创建了一个 shim。垫片是.ps1
,它会影响结果。案件结案。【参考方案2】:
我认为这里的问题是 git
抛出的错误不能被 PS 捕获。
插图:
try
git push
Write-Host "I run after the git push command"
catch
Write-Host "Something went wonky"
注意catch
块中缺少的Write-Host
!
这里我们需要查看git命令的退出代码。
在 PowerShell 中最简单的方法(我知道)是检查 $?
的值(有关 $?
的更多信息: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
检查我们的自定义错误(现在被catch
块捕获)!
【讨论】:
非常感谢您的解释!但是,就像我的 powershell 脚本中有很多行一样,我不能在每一行上都这样做,这将是不可读的...... 如果您关心可读性;创建一个为您执行“错误处理”的包装函数。功能比可读性更重要。但是,是的;可维护性应始终保持在显着位置! 如果有帮助,您可以单行检查:if ($?) throw
以上是关于带有 Git 命令错误处理的 Powershell - 在来自外部程序的非零退出代码时自动中止的主要内容,如果未能解决你的问题,请参考以下文章
带有 ssh 的 Git 克隆适用于 Linux,但不适用于 Windows PowerShell
使用windows powershell ISE管理命令窗口,并集成git命令