Mercurial: Autopushing changes from a central repository
When you have hundreds of applications managed via a central repository which are checked out to multiple production and staging servers, it can become burdensome to manage and/or remember where every working copy of that code resides. We recently ran into this issue at my work so we needed a solution that was going to be developer friendly and easy to manage on a per-repository basis.
Not only did we want to automatically push new changesets to working copies, but we wanted to automatically update those working copies based upon their nature; staging working copies needed to be updated to the ‘qa’ branch, and production copies needed to be updated to the latest tag (all of our tags reside on the stable branch).
I eventually accomplished this task with a small bash script that runs on the ‘changegroup’ hook and reads the contents of a specific version controlled file in that repository, .hgautopush. The contents of the bash file are below. I simply added this hook to the Rhodecode admin screen, created the file in any repository I wanted to automatically push changes from, and we were set.
#!/bin/bash
mktemp_bin=`which mktemp`;
# create a random temp file
temp_file=`$mktemp_bin -t autopushXXX`;
hg cat -r default .hgautopush 1>"$temp_file" 2>/dev/null
# Add an extra newline to the file, just in case
echo -e "\n" >> $temp_file
cat $temp_file | while read URL; do
IFS=':' read -ra PARTS <<< "$URL"
if [ -z "${PARTS[1]}" ] || [ -z "${PARTS[0]}" ]; then
continue
fi
# If the destination doesn't exist, attempt to create it
if [ ! -d "${PARTS[1]}" ]; then
echo "Remote repository does not exist; Attempting to create..." >/dev/stdout
hg init "${PARTS[1]}" 2>/dev/null
# If it still doesn't exist, error
if [ ! -d "${PARTS[1]}" ]; then
echo "Could not create remote repository at ${PARTS[1]}" > /dev/stderr
continue
fi
fi
# Push to the path, this could take a small amount of time due to automounting
hg push "${PARTS[1]}" --force
if [ "${PARTS[0]}" = "staging" ]; then
echo "Updating to latest QA revision..." >/dev/stdout
hg update qa --repository "${PARTS[1]}" 2>/dev/null
elif [ "${PARTS[0]}" = "production" ]; then
echo "Updating to latest tag on \"stable\" branch..." >/dev/stdout
hg update --rev "max(branch(stable) and tagged())" --repository "${PARTS[1]}" 2>/dev/null
fi
done
rm $temp_file
To prepare for this to actually work, I installed autofs on our server, obtained an active directory user for our Windows servers, and created a local user on all of the Linux servers with SSH authentication, assigned the proper permissions, and setup autofs for both sshfs and cifs access to the appropriate servers. The .hgautopush file has a format similar to this:
staging:/windows/path/to/windows/share production:/linux/path/to/linux/share
This accomplished all of our goals with minimal effort. Our developers are now able to create a simple file in any repository they want autopushed to another location (very handy for repositories that live on our public servers which have no reverse connection back inside the network).
| Print article | This entry was posted by Matt on May 8, 2012 at 1:49 pm, and is filed under Linux. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |