【问题标题】:Return error message on subprocess exit to VSCode Git将子进程退出时返回错误消息到 VSCode Git
【发布时间】:2022-01-20 06:55:50
【问题描述】:

我正在实现一个小的预提交钩子,它在每次提交之前调用 gitleaks 保护。

这在终端中运行良好,但是当尝试从 VSCode 中提交时,会返回一个非描述性的“Git: O”(我假设这只是 gitleaks 的第一行,它的 ascii 徽标的一部分)。

如您所知,我尝试了多种方法让 VSCode 的 Git 模块在退出子模块时返回正确的消息。但是,在这方面似乎没有任何作用。

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

exit_code = subprocess.run("gitleaks protect -v --staged -c gitleaks.toml",shell=True)
if exit_code.returncode == 1:
    eprint("This is a test")
    sys.exit("TEST")

当子进程以退出代码 1 退出时,如何在 VSCode 中返回一个显示消息的警报窗口?

编辑:

好的。这以某种方式起作用,但它失败了 subprocess.run("gitleaks version", shell=True, stdout=dev_null, stderr=dev_null) 仅适用于我的 WSL Bash,而 subprocess.run("gitleaks version", stdout=dev_null, stderr=dev_null)(没有 shell=True)仅适用于我的 VSCode 和 Windows Git Bash。

有什么方法可以使这个可移植的,所以 FileNotFoundError 在两个系统上都能正确抛出?

#!/usr/bin/env python3
# pylint: disable=C0116,W0613

import sys
import warnings
import subprocess

dev_null = subprocess.DEVNULL

def eprint(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

def gitleaks_installed():
    try:
        subprocess.run("gitleaks version", shell=True, stdout=dev_null, stderr=dev_null)
        return True
    except FileNotFoundError:
        return False

if gitleaks_installed():
    exit_code = subprocess.run("gitleaks protect -v --staged -c gitleaks.toml", shell=True, stdout=dev_null, stderr=dev_null)
    if exit_code.returncode == 1:
        eprint("gitleaks has detected sensitive information in your changes. Commit aborted.")
        subprocess.run("gitleaks protect -v --staged -c gitleaks.toml", shell=True)
        sys.exit(1)
else:
    eprint("gitleaks is not installed or in the PATH.")
    sys.exit(1)

EDIT2:NVM。 gitleaks_installed 部分在 WSL Bash 下根本不起作用。它要么总是 True 要么总是 False,这取决于我是否包含 shell=True

有没有更好的方法来检测 gitleaks 是否安装/在 PATH 中?

【问题讨论】:

    标签: python git visual-studio-code pre-commit-hook pre-commit


    【解决方案1】:

    subprocess.run 返回的对象是 CompletedProcess 对象,不是返回码。你必须访问它的.returncode 属性来检查它返回的内容。

    但是,您可以改为添加 check=True 以让 Python 在失败时抛出错误。

    您几乎肯定也应该通过自己将命令行解析为标记来摆脱多余的shell=True

    try:
        subprocess.run(
            ["gitleaks", "protect", "-v", "--staged", "-c", "gitleaks.toml"],
            check=True)
    except subprocess.CalledProcessError:
        eprint("gitleaks has detected sensitive information in your changes. Commit aborted.")
        sys.exit(1)
    except FileNotFoundError:
        eprint("gitleaks is not installed or in the PATH.")
        sys.exit(1)
    

    这也避免了为了获得输出而第二次运行该进程。如果您想强制将自己的消息置于顶部,请捕获输出并在您的消息之后打印(添加capture_output=Truetext=True)。

    您可能还想将eprint 替换为logging.warn,并可能在不同的错误情况下返回不同的退出代码。 (当找不到二进制文件时,Bash 通常会返回 127,但这只是 Bash。)

    在没有shell=True 的情况下在字符串而不是列表上运行subprocess.run 奇怪地恰好在Windows 上工作,但我的建议是始终避免为了方便而尝试利用它。或许也可以看看Actual meaning of shell=True in subprocess

    【讨论】:

    • 我知道我必须访问.returncode 属性。
    • 我现在就看看你的解决方案。谢谢。
    • 我测试了您的解决方案。它工作得很好(不过我可能会使用 subprocess.run 在try 块中,我无法从except 块中访问它。
    • 我想通了。我可以做except subprocess.CalledProcessError as e: 然后通过print(e.output) 打印。
    • 很抱歉,感谢 cmets。您可能还想检查e.stderr,或者改为。
    【解决方案2】:

    不是最优雅的解决方案,但这是可行的。 我们使用的是subprocess.run 返回码,而不是FileNotFoundError 异常。

    #!/usr/bin/env python3
    # pylint: disable=C0116,W0613
    
    import sys
    import subprocess
    
    dev_null = subprocess.DEVNULL
    
    def eprint(*args, **kwargs):
        print(*args, file=sys.stderr, **kwargs)
    
    def gitleaks_installed():
        exit_code = subprocess.run("gitleaks version", shell=True, stdout=dev_null, stderr=dev_null)
    
        if exit_code.returncode == 0:
            return True
        else:
            return False
    
    if gitleaks_installed():
        exit_code = subprocess.run("gitleaks protect -v --staged -c gitleaks.toml", shell=True, stdout=dev_null, stderr=dev_null)
    
        if exit_code.returncode == 1:
            eprint("gitleaks has detected sensitive information in your changes. Commit aborted.")
            subprocess.run("gitleaks protect -v --staged -c gitleaks.toml", shell=True)
            sys.exit(1)
    else:
        eprint("gitleaks is not installed or in the PATH.")
        sys.exit(1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-01
      • 2016-06-11
      • 2016-02-17
      相关资源
      最近更新 更多