git pre-pu sh hook: запускать тест при каждой новой фиксации - PullRequest
1 голос
/ 05 мая 2020

Контекст

Я хочу убедиться, что каждая фиксация sh проходит тесты.

Я хочу проверить это на своей (клиентской) стороне, т.е. еще до того, как коммиты будут отправлены (поэтому я не хочу полагаться на инструменты CI).

Проблема

В настоящее время я реализовал ловушку pre-commit, запускающую мои тесты, так что я не могу даже зафиксировать неработающее состояние.

Однако мой набор тестов занимает больше нескольких секунд, чтобы запустить. Это столько времени, которое мне нужно подождать, прежде чем писать сообщение о фиксации. Это делает нецелесообразным использование на ежедневной основе; как потому, что я часто фиксирую, так и из-за того, что иногда я намеренно хочу зафиксировать неработающее состояние, чтобы его позже раздавили (я знаю о git commit --no-verify, но дело не в этом).

Вопрос

Поэтому вместо того, чтобы проверять каждую фиксацию по одному (при создании), я хочу протестировать их перед нажатием.

Как реализовать хук pre-push, который запускается мой набор тестов для каждого нового коммита , который нужно отправить?

(Для простоты скажем, что прохождение тестов означает test/run_tests.sh возвращает 0.)

1 Ответ

1 голос
/ 05 мая 2020

Благодаря подсказке phd ( в комментариях ) и бесстыдному грабежу собственного примера git, я составил следующий хук ./.git/hooks/pre-push ( что я позаботился о chmod +x заранее).

Кажется, он работает в ванильной ситуации, посмотрим, как это пойдет со временем. В любом случае, улучшения приветствуются!

#!/usr/bin/sh

# An example hook script to verify that each commit that is about to be pushed
# pass the `./run_tests` suite. Called by "git push" after it has checked the
# remote status, but before anything has been pushed.
# If the test suite (and so the script) exits with a non-zero status, nothing
# will be pushed.
#
# In any case, we revert to the pre `$ git push` state.


# Retrieve arguments
remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000 # SHA of a non existing commit


# Save current "git state"
current_branch=$(git rev-parse --abbrev-ref HEAD)

STASH_NAME="pre-push-$(date +%s)"
git stash save -q --keep-index $STASH_NAME


# Do wonders
while read local_ref local_sha remote_ref remote_sha
do
        if [ "$local_sha" = $z40 ]
        then
                # Handle delete
                continue # to the next branch
        elif [ "$remote_sha" = $z40 ]
        then
                # New branch, examine all commits
                range="$local_sha"
        else
                # Update to existing branch, examine new commits
                range="$remote_sha..$local_sha"
        fi

        # Retrieve list of commit in "chronological" order
        commits=$(git rev-list --reverse $range)

        # Loop over each commit
        for commit in $commits
        do
            git checkout $commit

            # Run the tests
            ./test/run_tests.sh

            # Retrieve exit code
            is_test_passed=$?

            # Stop iterating if error
            if [ $is_test_passed -ne 0 ]
            then
                echo -e "Aborting push: Test failed for commit $commit,"\
                  "with following error trace:\n"
                # something like: tail test/run_tests.log
                break 2
            fi
        done

        fi
done


# Revert to pre-push state
git checkout $current_branch

STASH_NUM=$(git stash list | grep $STASH_NAME | sed -re 's/stash@\{(.*)\}.*/\1/')
if [ -n "$STASH_NUM" ]
then
    git stash pop -q stash@{$STASH_NUM}
fi


# Return exit code
exit $is_test_passed
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...