Przejdź do treści

Automatyczny strażnik commit’ów

You shall not passJesteśmy ludźmi – lubimy porządek, ale nie lubimy sami sprzątać. Dlatego też dobrze jest jeżeli niektóre rzeczy same dbają o porządek.

Codzienną czynnością programistów jest oddawanie (operacja commit) kodu do repozytorium kodu źródłowego. Przy tej operacji można wpisać komentarz opisujący jakie zmiany funkcjonalne są oddawane, np. „dodana możliwość usuwania kontrahentów” czy „poprawienie błędu przy definiowaniu nowej operacji”. Wszyscy wiedzą, że opisywanie tych zmian jest bardzo ważne – ale też bardzo często w repozytorium lądują zmiany bez żadnych opisów. A sprawdzenie listy zmienionych obiektów oraz zmian w ich w celu określenia co się zmieniło jest bardzo pracochłonne…

Co wtedy robimy?

Punktem pierwszym jest spotkanie zespołu, powiedzenie dlaczego te opisy są ważne i wprowadzenie zasady „od dzisiaj wpisujemy zmiany przy operacji commit”. Czy to pomaga? Przeważnie tak, ale nie do końca – w praktyce, pomimo określenia pewnych zasad, zdarzają się przypadki zmian, które nie są opisane. Można wtedy wprowadzić ręczne kontrole opisów przy ostatnich zmian – codziennie ktoś sprawdza wczorajsze operacje commit, czy są poprawne. Ale można też oszczędzić sobie niepotrzebnej pracy i napisać króciutki skrypt, który dołączymy jako pre-commit hook – czyli fragment kodu wykonywany przed operacją commit i potrafiący ją zablokować przy niespełnieniu pewnych warunków. Poniższy przykład pokazuje kod takiego skryptu napisanego dla systemu kontroli wersji SVN.

[crayon lang=”bash”]
#!/bin/sh
REPOS=$1
TXN=$2
SVNLOOK=/usr/bin/svnlook
# Check arguments
if [ -z „$REPOS” -o -z „$TXN” ]; then
echo „Syntax: $0 path_to_repos txn_id” >&2
exit 1
fi
# Check comment length
COMMENT_LEN=$($SVNLOOK log -t „$TXN” „$REPOS” | wc -m)
if [ $COMMENT_LEN -le 7 ]; then
echo „——————————————————————” >&2
echo „Please write some informative commit message so that your friends” >&2
echo „could see what was changed… It really doesn’t take so much time :)” >&2
echo „Your message length was: $COMMENT_LEN, minimum is: 8″ >&2
exit 1
fi
exit 0
[/crayon]

Co więcej – kontrola obecności komentarza to tylko najprostsze automatyczne sprawdzenie, które możemy zaimplementować. Można przed commit’em sprawdzać również jeszcze inne rzeczy, poniżej dwa przykłady.

Sprawdzenie czy użytkownik nie próbuje oddać do kontroli wersji fragmentów, które są markerami konfliktów:

[crayon lang=”bash”]
# We scan through the transaction diff, looking for things that look
# like conflict markers. If we find one, we abort the commit.
SUSPICIOUS=$($SVNLOOK diff -t „$TXN” „$REPOS” | grep -E '^\+({7} \.)’ | wc -l)
if [ $SUSPICIOUS -ne 0 ]; then
echo „—————————————————————-” >&2
echo „Some parts of your commit look suspiciously like merge” >&2
echo „conflict markers. Please double-check your diff and try” >&2
echo „committing again.” >&2
exit 1
fi
[/crayon]

Możemy również wymusić niestosowanie pewnych konstrukcji programistycznych:

[crayon lang=”bash”]
# System.out.print… is forbidden
SUSPICIOUS=$($SVNLOOK diff -t „$TXN” „$REPOS” | grep -E '^\+.*System\.out\.print’ | wc -l)
if [ $SUSPICIOUS -ne 0 ]; then
echo „—————————————————————-” >&2
echo „Please don’t use System.out.print” >&2
echo „Change such lines to log.debug and try to commit again!” >&2
exit 1
fi
# gc is forbidden
SUSPICIOUS=$($SVNLOOK diff -t „$TXN” „$REPOS” | grep -E '^\+.*\.gc\(\)’ | wc -l)
if [ $SUSPICIOUS -ne 0 ]; then
echo „—————————————————————-” >&2
echo „You are EVIL! Don’t use System.gc()” >&2
exit 1
fi
[/crayon]

Tworzenie takich skryptów jest proste – a oszczędzają one manualnej pracy i w prosty sposób zapobiegają niepożądanym praktykom.

Pomysł oraz kod skryptów: Witold Bołt. Tekst wpisu: Stanisław Matczak.

4 komentarze do “Automatyczny strażnik commit’ów”

  1. Drobne uwagi do skryptów:

    1. Skrypt sprawdzający markery konfliktów powinien działać tylko na plikach tekstowych (można sprawdzić Mime Type pliku w SVN i na tej podstawie decydować), bo przy „commitowaniu” np. obrazków trudno będzie rozwiązać problem bez wyłączenia skryptu.

    2. Skrypt sprawdzający zakazane konstrukcje językowe powinien działać tylko na plikach tekstowych z określonymi rozszerzeniami – System.gc() ma sens w przypadku *.java, ale nie koniecznie w pliku instrukcja.txt informującym o zakazie użycia takiego polecenia ;-)

    Oczywiście sam pomysł automatyzacji jest jak najbardziej sensowny, tylko trzeba uważać na pułapki…

    1. Skrypty pokazane w artykule to tylko ilustracja. Oczywiście, że mają wady – te, które wymieniłeś to jedno. Inna rzecz, że powinny bardziej dokładnie informować użytkownika co i gdzie było nie tak. Tak czy inaczej na tyle na ile zrozumiałem intencje Stasia :) chodzi o pokazanie samej (nie nowej – ale bardzo produktwynej i mądrej) idei automatyzowania wszystkiego co się da w kwestii trzymania jakości.

      Z resztą powyższe przykłady napisano z myślą o subversion, ale podobne techniki można użyć w git i innych bardziej cywilizowanych narzędziach :) Idea jest więc ogólna i bardzo skuteczna.

      Z drugiej strony nie można przesadzać, żeby hooki nie trwały pół godziny na dużych commitach :)

  2. Witaj,

    fajny przyklad, ale w drugim przypadku znacznie mniej pracochlonne bedzie podpiecie PHP_CodeSniffer’a pod hook z ustalonymi regulami dla calej firmy/projektu no i oczywiscie znacznie wiecej mozliwosci zyskujemy dzieki temu.

    1. Uważam, że podpisanie Code Sniffera pod SVN mija się z celem. SVN jest systemem kontroli wersji, a nie narzędziem do Continous Integration. O ile weryfikacja komentarzy przy commicie, wysyłanie powiadomień mailowych po commicie i tym podobne mają sens, to już szczegółowa analiza kodu powinna następować w narzędziach do tego przeznaczonych jak np. Jenkins.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.