【问题标题】:Commit in git only if tests pass仅当测试通过时才在 git 中提交
【发布时间】:2011-01-06 10:20:09
【问题描述】:

我最近开始使用 git,也开始了单元测试(使用 Python 的 unittest 模块)。我想在每次提交时运行我的测试,并且只有在它们通过时才提交。

我猜我需要在/hooks 中使用pre-commit,并且我已经设法让它运行测试,但是如果测试失败,我似乎无法找到停止提交的方法。我正在使用make test 运行测试,而后者又运行python3.1 foo.py --test。无论测试通过还是失败,我似乎都没有得到不同的退出条件,但我可能看错了地方。

编辑:这是我想在这里做的不寻常的事情吗?我原以为这是一个常见的要求......

Edit2:以防万一人们懒得阅读 cmets,问题是 unittest.TextTestRunner 不会以非零状态退出,无论测试套件是成功还是不是。为了抓住它,我做了:

result = runner.run(allTests)
if not result.wasSuccessful():
    sys.exit(1)

【问题讨论】:

  • 最近关于 SO 的问题很快就会出现在 Google 查询的顶部;然后排名也迅速下降。提出问题并在 5 分钟后成为 Google 的热门话题并不少见;但一周后,您可能会更难找到它。
  • @Brian Ah,很公平。我没有意识到 Google 是这样工作的。
  • 您的python3.1 foo.py --test 命令是否返回非零退出状态?如果您手动运行 make 是否返回非零退出状态?你的pre-commit钩子的内容是什么?

标签: python unit-testing git githooks


【解决方案1】:

另一个选项,如果您不想手动处理预提交: 有一个很好的工具可以运行 Python、Ruby 等的测试和语法检查:github/overcommit

【讨论】:

    【解决方案2】:

    我会检查以确保在每一步中,您的脚本都会在失败时返回非零退出代码。如果测试失败,请检查您的 python3.1 foo.py --test 是否返回非零退出代码。检查以确保您的 make test 命令返回非零退出代码。最后,检查您的 pre-commit 钩子本身是否在失败时返回非零退出代码。

    您可以通过在命令末尾添加|| echo $? 来检查非零退出代码;如果命令失败,它将打印出退出代码。

    以下示例适用于我(我将 stderr 重定向到 /dev/null 以避免在此处包含过多的无关输出):

    $ python3.1 test.py 2>/dev/null || echo $?
    1
    $ make test 2>/dev/null || echo $?
    python3.1 test.py
    2
    $ .git/hooks/pre-commit 2>/dev/null || echo $?
    python3.1 test.py
    1
    

    test.py

    import unittest
    
    class TestFailure(unittest.TestCase):
        def testFail(self):
            assert(False)
    
    if __name__ == '__main__':
        unittest.main()
    

    Makefile

    test:
        python3.1 test.py
    

    .git/hooks/pre-commit

    #!/bin/sh
    make test || exit 1
    

    注意|| exit 1。如果make test 是钩子中的最后一个命令,则不需要这样做,因为最后一个命令的退出状态将是脚本的退出状态。但是如果您稍后检查了您的pre-commit 钩子,那么您需要确保您退出时出现错误;否则,钩子末尾的成功命令将导致您的脚本以0 的状态退出。

    【讨论】:

    • @Brian - 谢谢。问题是我正在使用unittest.TextTestRunner 运行我的测试,它不会以非零状态退出。我不得不做if not result.wasSuccessful(): sys.exit(1)
    • 这里的另一个问题是测试是在修订版的工作副本上运行的,而不是暂存的。如果您总是提交所有更改,这不是问题,但如果您进行部分提交,那么您的中间提交可能无法通过测试(请参阅:[stackoverflow.com/questions/2412450/…
    • 这不是:make test || exit 1exec make test一模一样吗?
    • @AdonisK。正如我所解释的,如果这是你的钩子中的最后一个命令,你不需要|| exit 1。但是如果你稍后在你的钩子中有其他命令,那么你不能依赖make test失败导致整个钩子失败,你不能使用exec。如果你只有一个命令,是的,exec make test 工作正常。 || exit 1 的替代方法是使用 set -e 退出任何错误。
    【解决方案3】:

    您能否解析 python 测试会话的结果并确保以非零状态退出预提交挂钩?

    在发出适当的消息后,钩子应该以非零状态退出,如果 它想停止提交。

    因此,如果您的 python 脚本由于任何原因没有返回适当的状态,您需要直接从 pre-commit 挂钩脚本中确定该状态。
    如果测试失败,这将确保提交不会继续进行。
    (或者你可以从钩子中调用一个 python 包装器来调用测试,并根据测试结果确保sys.exit(exit_status))。

    【讨论】:

    • heikkitoivonen.net/blog/2009/01/28/… 在这里也可能是相关的
    • 有趣的是,在 Git Book 中,Scott Chacon 做了类似的事情(解析测试结果),使用 Ruby:book.git-scm.com/5_git_hooks.html
    • 感谢您对此的帮助。你是对的,问题在于没有返回适当的状态。部分问题在于我的 shell 技能 - 我还没有完全掌握窍门!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2017-11-04
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多