Зафиксировать 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)
Ответы
Ответ 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