SVN è un ottimo software per il versioning dei sorgenti di qualunque tipo. Quando si utilizza però per progetti Web, può essere necessario avere un qualche tipo di deploy automatico. In altre parole si vuole che il ramo dei sorgenti resi pubblici dal server Web sia automaticamente aggiornato ad ogni commit sul repository SVN. La FAQ di SVN presenta già una soluzione al problema, ma io ne ho messa a punto una leggermente differente che non fa uso di programmi compilati e di suid, ma semplicemente di script shell e di sudo.
L'idea è quella di creare un post-commit-hook, ossia un comando da eseguire a seguito di un commit, che effettui l'aggiornamento dell'albero dei sorgenti web. Nello specifico andrà a fare un update dell'albero dei sorgenti web prendendo solo gli ultimi file modificati in fase di commit (ovviamente si ipotizza che il server web sia locale al repository SVN). Il file post-commit della directory hooks del repository SVN deve quindi contenere il seguente codice shell:

REPOSITORY=$1
REVISION=$2

GREP_CMD=`which grep`
SED_CMD=`which sed`
ECHO_CMD=`which echo`
SU_CMD=`which su`
WWW_USER="www-data"
SUDO_CMD=`which sudo`
DEPLOY_CMD="/usr/local/bin/svnWeb.sh"
SVNLOOK_CMD=`which svnlook`
TMP_FILE=/tmp/svn.changed
WEB_REPOSITORY="myProject"

# controllo se il repository include la parte web
$ECHO_CMD $REPOSITORY | $GREP_CMD $WEB_REPOSITORY > /dev/null 2>&1
if [ $? -eq 0 ]
then
# e' il repository web, faccio la pubblicazione automatica

echo "Pubblicazione web automatica " > $TMP_FILE
echo "per il repository $WEB_REPOSITORY " >> $TMP_FILE
echo " (vedere il file post-commit del server svn) " >> $TMP_FILE
echo "\nSeguono i dettagli dell'aggiornamento web\n" >> $TMP_FILE

# mi faccio dire i file che sono cambiati
$SVNLOOK_CMD changed $REPOSITORY | $AWK_CMD '{print $2;}' >> $TMP_FILE

# faccio la pubblicazione diventando un utente apposito tramite
# il comando su, invocato a sua volta tramite sudo. E' importante
# che l'utente con il quale si esegue il comando sudo abbia
# una impostazione di /etc/sudoers che non richiede password, altrimenti
# questo script non verra' eseguito correttamente.
$SUDO_CMD $SU_CMD -c $DEPLOY_CMD $WWW_USER >> $TMP_FILE

fi

Come si può notare, oltre all'inizializzazione di alcune variabili (si presti attenzione poiché post-commit potrebbe eseguire con un PATH modificato o nullo) si effettua un primo controllo sul tipo di commit, affinché si riferisca al repository/progetto di cui si vuole fare il deployment. Dopodiché si scrive un semplice file di log per tenere traccia delle ultime modifiche effettuate (questo può essere utile da inviare come allegato in una e-mail di notifica del commit). Infine, si effettua un cambio utente (tramite su) all'utente cui appartiene la directory del server web e si esegue il comando di deploy (DEPLOY_CMD). Tutto questo viene fatto tramite sudo, per evitare che venga richiesta una password per diventare l'utente del server web. Infatti, se nel file di configurazione di sudo (/etc/sudoers) l'utente che effettua il commit è configurato perché non venga richiesta nessuna password, allora egli può diventare prima superutente (con sudo) e da li un utente qualunque (tramite su) senza che nessuna password sia richiesta.
Il comando di deploy (DEPLOY_CMD) è uno script che effettua l'update tramite SVN e sistema i permessi della directory del server Web:

#!/bin/bash

SRC_DIR=/var/www/myProject
SVN_REPOSITORY=file:///sviluppo/svn/myProject/trunk
SVN_CMD=`which svn`
CHMOD_CMD=`which chmod`
CHOWN_CMD=`which chown`
WWW_USER="www-data"
WWW_GROUP="www-data"



# entro nella directory in cui aggiornare l'albero dei sorgenti
cd $SRC_DIR || exit 1

# effettuo l'aggiornamento dei sorgenti
echo "Aggiornamento dell'albero dei sorgenti..."

$SVN_CMD update $SVN_REPOSITORY `pwd`
echo "fatto <$?>"

# cambio i permessi dei file copiati
$CHOWN_CMD $WWW_USER:$WWWGROUP `pwd` -Rf
$CHMOD_CMD 755 `pwd` -Rf

L'utilizzo di un post-commit hook per la pubblicazione del server Web ha comunque alcuni difetti:
  • occorre più tempo per ogni commit, poiché il server Web deve essere aggiornato;
  • per testare le modifiche occorre fare dei commit, e quindi si va a fare il commit di codice non proprio stabile. A tal fine è bene inserire uno schema di branching o tagging.

The article Pubblicazione di un progetto Web gestito tramite SVN has been posted by Luca Ferrari on September 16, 2008