Git pre-commit / pre-push hook для запуска модульных тестов при коммитах с незафиксированными изменениями в рабочем дереве - PullRequest
1 голос
/ 08 октября 2019

В настоящее время у меня есть простой pre-commit хук для моего проекта (в R, хотя это не относится к этому вопросу), который выполняет модульные тесты:

#!/bin/sh
a=$(Rscript tests/testthat.R)
exit $a

Где tests/testthat.R - это файл-обертка, который обрабатываетвсе тесты.

Этот хук имеет проблему, хотя: если я делаю частичные коммиты (такие, что есть изменения, которые остаются незафиксированными), тесты будут выполняться в текущем состоянии рабочего дерева, включаянезафиксированные изменения.

Итак, допустим, я заканчиваю «Шаг 1» чем-то, что я делаю, но забываю зафиксировать это. Затем я начинаю «Шаг 2», но потом понимаю, что забыл совершить «Шаг 1». Если «Шаг 2» в настоящее время находится в нерабочем состоянии из-за незавершенных изменений, я не смогу выполнить частичную фиксацию для «Шаг 1», потому что тесты обнаружат, что «Шаг 2» неисправен.

Итак, есть ли способ для перехвата на версии, которая на самом деле фиксируется? Я думаю, что это будет ловушка, которая фактически временно проверяет фиксацию, запускает тесты для этой проверки, удаляет проверку и затем определяет, разрешить ли прохождение фиксации. Но, учитывая, что этот хук срабатывает до того, как коммит завершен, я предполагаю, что проверить его невозможно.

Я также был бы открыт для хака pre-push. Это кажется более правдоподобным, поскольку ловушка получает SHA для отправки коммитов, поэтому моя идея выше кажется более разумной: получить последний SHA, создать временный каталог, проверить этот SHA, запустить тесты, удалить каталог. Но тогда у меня возникает вопрос: действительно ли это предлагаемый метод или я слишком усложняю вещи из-за своего невежества?

Ответы [ 2 ]

2 голосов
/ 08 октября 2019

В этой статье предлагается сохранить изменения, которые не были внесены перед запуском тестов, а затем снять их после запуска тестов. Соответствующий фрагмент кода:

# pre-commit.sh
STASH_NAME="pre-commit-$(date +%s)"
git stash save -q --keep-index $STASH_NAME

# Test prospective commit
...

STASHES=$(git stash list)
if [[ $STASHES == "$STASH_NAME" ]]; then
  git stash pop -q
fi
1 голос
/ 08 октября 2019

Заканчивается тем, что git stash страница справочника описывает именно этот вариант использования:

Вы можете использовать git stash push --keep-index, когда хотите сделать два или более коммитовизменений в рабочем дереве, и вы хотите проверить каждое изменение перед фиксацией:

# ... hack hack hack ...
$ git add --patch foo            # add just first part to the index
$ git stash push --keep-index    # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part'     # commit fully tested change
$ git stash pop                  # prepare to work on all other changes
# ... repeat above five steps until one commit remains ...
$ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'

Так что просто сделайте

git stash push --keep-index
# 
# testing...
#
git stash pop

Используя это в хукеТем не менее, существует риск крайнего случая: у вас может быть старый несвязанный тайник, о котором вы забыли, и вы можете сделать чистый коммит (не оставляя незафиксированных изменений).

В этом случае вызовgit stash push --keep-index на самом деле не создаст тайник (возвращает «Нет локальных изменений для сохранения»). Но когда тесты будут завершены, git stash pop найдет старый тайник, что приведет, по крайней мере, к головной боли.

Так что мой настоящий pre-commit крючок выглядит так:

#/bin/sh

hasChanges=$(git diff)    
if [ -n "$hasChanges" ]; then
    git stash push --keep-index
fi

#
# testing...
#

if [ -n "$hasChanges" ]; then
    git stash pop
fi

exit $testSuccess

В основном, используйте git diff, чтобы увидеть, есть ли какие-либо изменения в отслеживаемых файлах. Если есть, спрятать, а потом совать их. В противном случае не беспокойтесь о тайниках.

...