a dev's blog

Some thoughts about thoughts.

Jekyll publishing mit git und post-receive hook

2015-03-07 Development Jekyll

Jekyll hat nicht lange gebraucht um meine Liebe zu erkaufen. Abgesehen von der klaren Struktur und den netten Build-Tools ist das publishen von Änderungen einfach nur ein Traum, insofern man sich der Sache mit git hooks nähert. Ich selber nutze git seit einiger Zeit im beruflichen und privaten Umfeld, habe allerdings lange gebraucht um für mich einen Anwendungsfall für hooks zu finden. Jetzt habe ich ihn ;)

Ein paar Worte vorab

Diese Website liegt auf einem Server mit ssh Zugang und wird von einem nginx ausgeliefert. Auf dem Server gibt es neben meinem User auch noch einen git User, in dessen Home Verzeichnis meine Repositories liegen. Die folgende Anleitung bezieht sich auf diese Infrastruktur.

In diesem Post wird der gesamte Prozess vom anlegen eines virtual hosts mit nginx, anlegen eines git Repos mit post-receive hook, bis hin zur Veröffentlichung erklärt.

Was sind git hooks?

Hooks kann man nutzen, um nach bestimmten Aktionen Skripte auszuführen. Beispielsweise kann man mit einem clientseitigen hook dafür sorgen, dass kein commit möglich ist, wenn die commit message nicht einem bestimmten Format entspricht oder man kann nach einem erfolgreichen commit eine Mail versenden lassen. Im git Buch ist bereits einiges dazu verkmerkt aber alles in allem ist da sicherlich Phantasie gefragt.

Nun gibt es neben clientseitigen hooks auch serverseitige hooks, die beispielsweise ausgeführt werden wenn ein push in ein Repository erfolgt ist - und ebendiesen habe ich mir zunutze gemacht. Eine schöne Vorlage habe ich bei halfthetruth.de gefunden.

Los geht’s

Repo erzeugen

Als ersten muss auf dem Server ein git Repository erzeugt werden, in das die push-Operation erfolgen soll. Das Repository nennen wir mywebsite.de.

cd /home/git
sudo -u git git init --bare mywebsite.de.git

Daraufhin legen wir in dem git Konfigverzeichnis eine Datei namens post-receive mit folgendem Inhalt an:

sudo -u git vi /home/git/chclaus.de.git/hooks/post-receive
sudo -u git chmod +x /home/git/chclaus.de.git/hooks/post-receive
export GIT_WORK_TREE=/var/www/git-repos/chclaus.de
cd $GIT_WORK_TREE
sudo -u www-data git pull
echo "Website ist up2date"

Und sorgen dafür, dass der user git in die sudoer Gruppe aufgenommen wird und die Permissions erhält ein pull auszuführen. Dies machen wir mit dem Befehl:

visudo

Und tragen folgenden Inhalt ein:

Defaults!/usr/bin/git env_keep=GIT_WORK_TREE
git ALL=(www-data) NOPASSWD: /usr/bin/git

Als nächstes legen wir im Arbeitsverzeichnis unseres Webservers einen Ordner an, in dem wir git Repositories klonen können. Daraufhin wechseln wir in dieses neue Verzeichnis, klonen unser Repo und legen einen Symlink darauf, so dass wir über /var/www/website.de in das _site Verzeichnis unseres geklonten Jekyll Projects kommen.

sudo -u www-data mkdir /var/www/git-repos
cd /var/www/git-repos
sudo -u www-data git clone /home/git/mywebsite.de.git/
cd ..
sudo -u www-data ln -s git-repos/mywebsite.de/_site mywebsite.de

Nginx Konfiguraiton anpassen

In der ngninx Konfiguration einen neuen Server anlegen mit:

sudo vi /etc/nginx/sites-available/mywebsite.de

Als Inhalt verwenden wir folgendes:

server {
  listen 80;
  server_name mywebsite.de;
  root /var/www/mywebsite.de;
  index index.html index.htm;
  location / {
    try_files $uri $uri/ /index.html;
  }
  error_log /var/log/nginx/mywebsite.de.error.log;
  access_log /var/log/nginx/mywebsite.de.access.log;
}

Zu guter Letzt aktivieren wir die Konfiguration und laden sie.

sudo ln -s /etc/nginx/sites-available/mywebsite.de /etc/nginx/sites-enabled/mywebsite.de
sudo service nginx reload

Jekyll Repo zu git Projekt machen

Zurück zu unserem Rechner. Ich gehe mal davon aus, dass es bereits ein bestehendes Jekyll Projekt (bei mir website) gibt. Jekyll bringt bereits eine fertige gitignore mit, die u.a. alle Dateien unterhalb des generierten _site Ordners ausschließt. Da ich ein Fan davon bin, nur die notwendigsten Pakete auf meinem Server zu installieren, habe ich den _site Ordner aus der gitignore herausgenommen und commite einfach alle generierten Dateien.

# entferne _site aus gitignore (s.o.)
# ...

cd ~/Developer/chclaus/website
git init
git add -A
git commit -m "initial commit"
git remote add origin git@myserver:/home/git/mywebsite.de.git
git push --set-upstream origin master

Script zum bauen und pushen

Zu guter letzt legen wir uns noch ein Shell Script irgendwo (sollte im Path sein) mit folgendem Inhalt hin. Bei mir unter _~/bin/buildjekyll.sh. Und dann habe ich mir noch einen Alias bj angelegt, der auf das Script zeigt.

if [ -n "$1" ]; then
  jekyll build && git add -A && git commit -m "$@" && git push
else
  echo commit message not set
  exit 1
fi

Wenn ich jetzt eine Änderung gemacht habe und sie veröffentlichen möchte, gebe ich einfach nur ein:

bj "Das hier ist meine commit message"

Und daraufhin wird das Projekt gebaut, sämtliche Dateien werden hinzugefügt, commited und gepushed. Als Antwort bekommt man dann vom Remote:

remote: Website ist up2date

Fazit

Ich kann nach Änderungen in meinem Blog mit dem Kommand bj und einer commit message den kompletten publishing Prozess durchführen und bin happy. :)