Klepię sobie ostatnio mały projekcik i używam mojego domowego serwera jako testserwera dla niego (dlatego że jest w miarę “czysty” więc jak zapomnę dodać jakiegoś liba do zależności bo już mam go na swoim desktopie to wyłapie to przy deployu na serwer). Jak na razie deploy sprowadzał się do wejściu na serwer, zrobieniu pulla i restart aplikacji, ale nie było to zbyt wygodne. Postanowiłem to uprościć (lenistwo przyjacielem automatyzacji;] )

Zacząłem od zrobienie clona “bare” mojego repo gitowego. To taki klon który zawiera sam katalog .git, a potrzebny jest dlatego że bez tego zdalny push do aktywnego brancha sypałby tylko śmiesznymi errorami (autentykacja przez pubkey).

serwer $ git clone --bare ssh://xani@desktop/home/xani/src/project
git clone --bare ssh://xani@desktop/home/xani/src/project
Initialized empty Git repository in /usr/src/git/project.git/
remote: Counting objects: 78, done.
remote: Compressing objects: 100% (69/69), done.
remote: Total 78 (delta 20), reused 0 (delta 0)
Receiving objects: 100% (78/78), 13.31 KiB, done.
Resolving deltas: 100% (20/20), done

teraz (na desktopie) możemy dodać te repo jako cel pusha
git remote add deploy master
i pushować do niego zmiany przez git push deploy master

Kolejny krok to oskrypcenie deployu:

PATH=/bin:/sbin:/usr/bin:/usr/sbin
unset GIT_DIR # wymagane żeby git log poprawnie załapał          
# są lepsze metody robienia tego ;)
killall app.pl
cd /var/www || exit 1 #jeżeli dir nie istnieje nie rób niczego głupiego
# czysczenie starej aplikacji
mv app app.old
git clone /usr/src/app.git
rm -rf app.old
cd /var/www/app
# tutaj dorzucamy info o commicie do configa aplikacji,
# tak że może on wyświetlić która rewizja jest aktualnie odpalona na serwerze
LAST_COMMIT=$(git log -1 --abbrev-commit --date=local  --format="%h %aD %aN %s")
echo "rev_info: \"$LAST_COMMIT\"" >>config.yml
# w końcu, app jest odpalany na screenie
screen -fn -dmS app ./app.pl

Następnie robimy symlinka ./hooks/post-receive w katalogu stworzonego wcześniej repo, będzie on odpalany za każdym razem ktoś zrobi push do tego repo. Ten sposób działa też z gitosis.

Sama metoda jest raczej prosta, deployuje tylko jeden branch i raczej nie będzie działać przy intensywnym developingu przez paru programistów (dwa jednoczesne pushe powodują odpalenie deployu x2), ale można ją łatwo “upgradować” np.:

  1. skrypt post-receive dostaje zakres “od-do” rewizji, wystarczy użyć tego i albo zbudować wszystkie commity po drodze albo wyciągnąć nazwę brancha i zbudować “ostatni commit z każdego brancha” – używałem podobnego rozwiązania do budowania paczek, sprawdza się swietnie, można testować paczkę na serwerze dosłownie minutę po commicie, łącznie z logiem “co poszło nie tak” podczas buildu.
  2. skrypt “blokuje” (po odpaleniu git push na kliencie czeka do skończenia skryptu zanim klient dostanie spowrotem shella), ale to można łatwo rozwiązać przez odpalanie joba w cronie i używaniu post-receive tylko do łapania info “nowy commit czeka na build”. Zabezpiecza to też przed podwójnym odpaleniem deploya, lub zbyt częstym odpaleniem go.

Na sam koniec odpaliłem

git config alias.deploy "push deploy master"

Tak że teraz odpalenie aplikacji na zdalnym serwerze sprowadza się do git deploy I kto mówi że lenistwo nie popłaca ? :D