Подтвердить что ты не робот

Зафиксировать git только в случае прохождения тестов

Недавно я начал использовать git, а также начал модульное тестирование (используя модуль Python unittest). Я хотел бы запускать свои тесты каждый раз, когда я совершаю, и только совершать, если они пройдут.

Я предполагаю, что мне нужно использовать pre-commit в /hooks, и мне удалось заставить его запустить тесты, но я не могу найти способ остановить фиксацию, если они не пройдут проверку. Я запускаю тесты с make test, который, в свою очередь, работает python3.1 foo.py --test. Похоже, что у меня не получается другое условие выхода, проходят ли тесты или терпят неудачу, но я могу искать не то место.

Изменить: Является ли это чем-то необычным, что я хочу здесь сделать? Я бы подумал, что это обычное требование...

Edit2: На всякий случай люди не могут потрудиться, чтобы прочитать комментарии, проблема заключалась в том, что unittest.TextTestRunner не выходит с ненулевым статусом, является ли тестовый пакет успешным или не. Чтобы поймать это, я сделал:

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

Ответ 1

Я бы проверял, чтобы на каждом шаге ваш script возвращал ненулевой код выхода при ошибке. Проверьте, не возвращает ли ваш 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 - последняя команда в hook, так как статус выхода последней команды будет состоянием выхода из script. Но если у вас есть более поздние проверки в вашем тэге pre-commit, вам нужно убедиться, что вы выходите с ошибкой; в противном случае успешная команда в конце hook приведет к тому, что ваш script завершится со статусом 0.

Ответ 2

Не могли бы вы проанализировать результат тестового сеанса python и убедиться, что вы покинули свой крюк pre-commit с ненулевым статусом?

Ключ должен выйти с ненулевым статусом после выдачи соответствующего сообщения, если он хочет остановить фиксацию.

Итак, если ваш python script не возвращает соответствующий статус по какой-либо причине, вам нужно определить этот статус непосредственно из pre-commit hook script.
Это гарантирует, что фиксация не будет идти вперед, если тесты не удались.
(или вы можете вызвать из крючка оболочку python, которая будет вызывать тесты, и обеспечить sys.exit(exit_status) в соответствии с результатами теста).

Ответ 3

Другой вариант, если вы не хотите обрабатывать вручную pre-commit: Существует хороший инструмент для запуска тестов и синтаксических проверок для Python, Ruby и т.д.: github/overcommit