Using ANT To Deploy Drupal
So you’ve decided to use Drupal… awww. Well I really dislike drupal, but thats another article. For now I would like to discuss my strategy for doing ANT based builds of Drupal.
Doing ANT deployments is a great way to leverage some XP programming methodologies, but most importantly it allows you to do deployments to different environments in one step, making screw ups less likely.
Let’s assume you have some developers with a full version of the application on their workstations and you have a qa and production environment. You also store all your files in version control (we’ll use subversion because its the most common). If your not using version control… well you really should do that before you do any builds!!!!
We want ANT to do everything for us, checkout from subversion, do some configuring, then copy everything to target server. So lets get started.
Here is an outline of what we are going to do:
- Get Drupal Ready
- Get ANT Ready – set up with dependencies
- Create environment specific property files for ANT
- Create ANT build.xml file
Get Drupal Ready
First thing we need to do, is add a folder build to the root of our drupal project. This folder will hold our properties files and the build.xml file. We will also need to create the necessary settings.php files for each environment. I like to store these in version control and have ANT deal with copying/renaming the right one. Below is a screenshot of what my Drupal project looks like:
The setting.php files have all the environment specific settings. settings.php should not be entered into version control as each developer will have specific settings. As part of their local workstation setup they should copy settings.php.example to settings.php and customize as they need to.
Get Ant Ready
Go ahead and install ANT from the apache website, you will also need these libraries:
- SVN ANT – allows you to checkout from subversion from ANT
- JSCH JARS – allows you to SCP and do other nifty things
Make Your Properites File
We are going to use property files to store all the values that ANT will use for the project. Use a different one for each environment (see above screenshot). Here are the values contained in mine:
# -----------------------------------------------------------------------------
# build.properties
# This file is referenced by the build.xml file.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# External jars needed for Subversion
# Example:
# lib.dir=/usr/local/ant/lib
# svnant.jar=${lib.dir}/svnant.jar
# svnClientAdapter.jar=${lib.dir}/svnClientAdapter.jar
# svnjavahl.jar=${lib.dir}/svnjavahl.jar
# -----------------------------------------------------------------------------
lib.dir=
svnant.jar=
svnClientAdapter.jar=
svnjavahl.jar=
# -----------------------------------------------------------------------------
# Subversion Login and URL
# Example:
# svnant.repository.user=username
# svnant.repository.passwd=password
# svnant.project.url=svn://XXX.XXX.XX.XX/path/to/project
# -----------------------------------------------------------------------------
svnant.repository.user=
svnant.repository.passwd=
svnant.project.url=
# -----------------------------------------------------------------------------
# Build Folder Locations
# Example:
# temp.dir=temp
# build.dir=release
# -----------------------------------------------------------------------------
temp.dir=
build.dir=
# -----------------------------------------------------------------------------
# Comment File Location, Where we output revision information requires tokens
# in file
# Example:/themes/xxx/parts/basic_footer.inc
#
# CSS Cache Busting File Location, where we output revision to bust CSS cache
#
# -----------------------------------------------------------------------------
comment.file.path=
cache.buster.file.path=
# -----------------------------------------------------------------------------
# Deploy Location
# Example:
# deploy.server=sugababes.com
# deploy.path=/path/to/directory
#
# -----------------------------------------------------------------------------
deploy.server=
deploy.path=
Create your build.xml file
Here is a basic outline of what we want ANT to do:
We will want our ANT build script to do the following:
- Checkout Project from Subversion
- Cleanup Project & Configure For Target Environment
- Add A Revision Number & Timestamp To A Specific File
- Zip Up The Build
- Securely Transfer and Extract The Build On Target Server
To be slick, we will pass the following paramters into ANT on the command line:
- Target Environment
- Subversion Revision For Build (or HEAD)
- Username and Password for Target Environment – dont store this info in the properties file.
For ANT, this is an example of what I want to type in:
ant build-drupal -Denv=qa -Drevision=HEAD -Duser=benny -Dpass=xxpassxx
That should be all to do a build, what environment do you want to deploy too, what revision do you want deployed, what is the username and password to login.
Here is my ANT target to checkout from subversion:
<property file=”build.properties.${env}” />
<path id=”project.classpath”>
<pathelement location=”${svnjavahl.jar}” />
<pathelement location=”${svnant.jar}” />
<pathelement location=”${svnClientAdapter.jar}” />
</path>
<typedef resource=”org/tigris/subversion/svnant/svnantlib.xml” classpathref=”project.classpath” />
<target name=”checkout”>
<svn username=”${svnant.repository.user}” password=”${svnant.repository.passwd}”>
<checkout url=”${svnant.project.url}” revision=”${revision}” destPath=”${temp.dir}” />
</svn>
</target>
Note the ${env} syntax, this is how you pull in values from the command line. For example I want to type the following to ant ant deploy-drupal -Denv=qa and then will use the qa value to get the right properties file.
Below is the task to insert the build number into the footer and to bust any CSS cache:
<target name=”revisionnumber”>
<svn>
<status path=”${temp.dir}” revisionProperty=”Revision” />
</svn>
<tstamp />
<!– For CSS Cache Busting Constant in index.php –>
<replace file=”${temp.dir}${cache.buster.file.path}” token=”@@@” value=”${Revision}”/>
<!– For Info In Footer –>
<replace file=”${temp.dir}${comment.file.path}” token=”@@@” value=”Revision: ${Revision}, Build Date: ${DSTAMP} : ${TSTAMP}”/>
</target>
Below is the target to copy the correct settings file:
<target name=”populateRelease”>
<move file=”${temp.dir}/sites/default/settings.php.${env}” tofile=”${temp.dir}/sites/default/settings.php”/>
</target>
These two targets zip and scp the file:
<target name=”zipRelease”>
<mkdir dir=”${build.dir}”/>
<zip destfile=”${build.dir}/FILE-NAME_${revision}.zip” basedir=”${temp.dir}” />
<antcall target=”clean”/>
</target>
<target name=”deploy”>
<scp file=”${build.dir}/FILE-NAME_${revision}.zip”
todir=”${user}@${deploy.server}:${deploy.path}”
password=”${pass}”
trust=”true”
/>
</target>
Most importantly is this task that extracts the files on the target server, note that the Uploads and Files folders are not touched, since these contain user created data they are not stored in subversion and are not included in the build.
<target name=”extractConfigure”>
<sshexec host=”${deploy.server}”
username=”${user}”
password=”${pass}”
trust=”yes”
command=”cd ${deploy.path};
rm -R includes;
rm -R misc;
rm -R modules;
rm -R profiles;
rm -R scripts;
rm -R sites;
rm -R themes;
rm .htaccess;
rm robots.txt;
rm cron.php;
rm index.php;
rm xmlrpc.php;
unzip -o FILE-NAME_${revision}.zip;
rm FILE-Name_${revision}.zip;”/>
</target>
And thats pretty much all the pieces you need, the rest of the plumbing is standard ANT.

Thanks for the great article! I have several drupal websites and have been looking for the right solution to manage my dev/qa/prod deployments. What do you do about the database?
- Greg
Greg – great question, I think I will write a followup blog post addressing this issue. Stay tuned
That’s great Ben! In the meantime any hints you can provide would be more than welcome. I am considering checking the backup sql file into SVN and then doing a merge with the staging DB backup file and then finally a production restore. However there are several problems with this approach due to identity columns and the fact that some configuration data could be different in production than staging (i.e. we use the SSL module that forces SSL on certain pages).
Greg… quick thoughts.