These days as a developer you spend a great part of your day on github.com. Git is the most powerful version control we have right now and github added an easy to use UI on top of it where with a couple of clicks you can add your repository and start to have a versioned control data.
But still there are some scenarios in which you don't want to use github (or any other hosted git service). What if you don't want to push your source code into cloud? What if you want a versioned data as part of your data-model? Of course there are solutions like Github Enterprise available, but they all come at a relatively high cost.
Gitolite is an open-source project that allows you to setup git hosting on a central server.
Setup and installation is straightforward and there is a good cookbook at hand.
For me, the most interesting point of Gitolite is its hook points. With a little plumbing you can connect it to your other backend services and make it part of your application stack. These hooks are called by Gitolite when certain event happen in your code repository, like pull or code push of commits.
Let's see how we can call an endpoint to update some model data on backend server:
There is a post-receive
hook you can configure which will be called after each push to a repository.
This is a one-line script I need to call my backend server every time someone pushes code into the repository.
#!/bin/sh
wget http://my-backend-server-address/git --post-data "user=$GL_USER&repo=$GL_REPO"
First I need to change the /home/git/.gitolite.rc
file and add follwing line to it :
LOCAL_CODE => "/home/git/local"
Now we should copy above script into a specific folder on Gitolite server :
$ mkdir -p /home/git/local/hooks/common
$ cp my-post-receive-hook /home/git/local/hooks/common/post-receive
$ chmod +x /home/git/local/hooks/common/post-receive
At the end run following commend to update Gitolite server settings:
$ gitolite setup --hooks-only
It is ready and we will start to get some post calls on backend server after each push to repositories.
There are more hook points you can play with. As an example there is a pre-receive
hook, you may use to add an authorization step before user can push to a repository.
Unfortunately there is no official Docker Image for Gitolite yet but you can find several unofficial one in Docker hub. I tried couple of them and they do the job. The Gitolite docker container can be setup very easy and I can push and pull my repositories without any issue.
https://hub.docker.com/r/elsdoerfer/gitolite/ is one of the good ones which supports hooks points as well. You need to pass the address of your script in $LOCAL_CODE
environment variable.
If you are a fan of small Alpine images like me , this is a good and easy to use image: https://hub.docker.com/r/jgiannuzzi/gitolite/
This image however does not support hook points. But this is not going to stop us from trying to add them ourselves!
Following the previous steps on configuring a real server, first we need to have our script inside the image, then we should change the .rc
file and at last we need to run the gitolite setup
.
The script can be part of image so it can be added in Dockerfile
but changes in .rc
file should happen on a running server which in container world means running inside a container.
jgiannuzzi/gitolite uses a docker-entrypoint.sh
to setup Gitolite container in runtime we can add our setup steps to it.
#!/bin/sh
# if command is sshd, set it up correctly
if ["${1}" = 'sshd']; then
set -- /usr/sbin/sshd -D
# Setup SSH HostKeys if needed
for algorithm in rsa dsa ecdsa ed25519
do
keyfile=/etc/ssh/keys/ssh_host_${algorithm}_key
[-f $keyfile] || ssh-keygen -q -N '' -f $keyfile -t $algorithm
grep -q "HostKey $keyfile" /etc/ssh/sshd_config || echo "HostKey $keyfile" >> /etc/ssh/sshd_config
done
fi
# Fix permissions at every startup
chown -R git:git ~git
# Setup gitolite admin
if [! -f ~git/.ssh/authorized_keys]; then
if [-n "$SSH_KEY"]; then
[-n "$SSH_KEY_NAME"] || SSH_KEY_NAME=admin
echo "$SSH_KEY" > "/tmp/$SSH_KEY_NAME.pub"
su - git -c "gitolite setup -pk \"/tmp/$SSH_KEY_NAME.pub\""
rm "/tmp/$SSH_KEY_NAME.pub"
##########################################
############START OF HOOK SETUP###########
##########################################
######CHANGING .gitolite.rc
sed -i "s|# LOCAL_CODE.*=>.*$|LOCAL_CODE => \"/var/lib/git/local\",|" /var/lib/git/.gitolite.rc
######give the script run access
chmod +x /var/lib/git/local/hooks/common/post-receive
######run gitolite setup
su - git -c "gitolite setup --hooks-only"
##########################################
############END OF HOOK SETUP#############
##########################################
else
echo "You need to specify SSH_KEY on first run to setup gitolite"
echo "You can also use SSH_KEY_NAME to specify the key name (optional)"
echo 'Example: docker run -e SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" -e SSH_KEY_NAME="$(whoami)" jgiannuzzi/gitolite'
exit 1
fi
# Check setup at every startup
else
su - git -c "gitolite setup"
fi
exec "$@"
And this is the docker file to add our script :
FROM jgiannuzzi/gitolite
MAINTAINER ShaB
USER git
RUN mkdir -p /var/lib/git/.gitolite/logs
RUN mkdir -p /var/lib/git/local/hooks/common
ADD post-receive /var/lib/git/local/hooks/common/
USER root
COPY docker-entrypoint.sh /
RUN chown root:root /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
Create a script file called post-receive
and copy the contents of above oneline script into it. Copy the above docker-entrypoint.sh
and Dockerfile
in the same folder and build a new image:
docker build -t gitolite-alpine-hook .
The result is a hook enabled gitolite alpnie image can be used in your docker stack.