This post is the third in a series of deployment workflows I use to get code into production.
While the WSUWP Platform is the preferred place for new sites at WSU, there are times when a single site WordPress installation is required.
Until about February of 2014, all new sites were configured on our WSU Indie server because the platform was not ready and setting things up in IIS was getting old. Now, a site only goes here if it is going to do something crazy that may affect the performance of the platform as a whole. It’s a separate server and definitely an outlier in our day to day workflows. In fact, I’ve been able to remove all sites except for three from that server, with one more scheduled.
Because WSU Indie is setup to handle multiple single site installs, I needed a way to deploy everything except for WordPress, which is controlled on this server as part of provisioning.
The best current example of how each repository is configured is probably our old P2 configuration:
config/– Contains the Nginx configuration for both local (Vagrant) and production instances.
wp-content/– Contains mu-plugins, plugins, and themes.
.rsync-exclude– A list of files to exclude when
rsyncis used on the server during deployment.
When placed alongside a
wordpress/ directory and an existing
wp-config.php file, everything just works.
On the server, each configured indie site has its own directory setup based on descriptions in a Salt pillar file. An example of what this pillar file looks like is part of our local indie development README.
When provisioning runs, the final web directory looks something this:
Our job with deployment is to get the files from the repository into the production directory.
I decided git hooks would do the trick and be fun to try. In a nutshell, a git repository has a
.git/hooks/ directory where you can define one or more shell scripts that fire at various points during various git actions. Pre-commit, post-commit, etc… These hooks can be configured locally or on a remote server. They are similar in a way to GitHub’s webhooks and can be very powerful.
We have a repository which contains all of these scripts, but it’s currently one of the few that we have as private. I’m not entirely sure why, so I’ll replicate a smaller version of one here.
The file structure we’re dealing with during deployment is this:
/var/repos/news.wsu.edu.git/– A bare git repository setup for receiving deploy instructions.
/var/repos/news.wsu.edu.git/hook/post-receive– The hook that will fire after receiving a push from a developer.
/var/repos/news.wsu.edu/– The directory where the master branch is always checked out.
This is a shortened version of the post-receive hook for the WSU News repository:
For this to work, I add a remote named “deploy” to my local environment for news.wsu.edu that points to the
var/repos/news.wsu.edu.git/ directory in production. Whenever I want to deploy the current master branch, I type
git push deploy master. This sets in motion the following:
/var/repos/news.wsu.edu.git/receives my push of whatever happens to come from my local repo.
/var/repos/news.wsu.edu.git/hooks/post-receivefires when that push is done.
/var/repos/news.wsu.edu/is instructed by the post-receive hook to fetch the latest master.
rsyncis then used to sync the non-excluded files from
And boom, latest master is in production.
There are a few caveats:
- There is no way to rollback, unless you revert in master.
- There is no way to deploy specific versions, you must assume that master is stable.
- It is user friendly only to someone comfortable with the git command line, though it’s probably possible to setup a GUI with multiple remotes. This is not necessarily a bad thing.
- It requires a public key from each developer to be configured on the server for proper authentication. This is also not necessarily a bad thing.
I think this is a pretty good example of how one can start to use git hooks for various things. The script above is definitely not a great long term solution, and if I hadn’t started focusing more on the health of the WSUWP Platform, things likely would have changed drastically. That said, once it was there it worked for multiple sites and multiple people on our team—and having something that works is pretty much the biggest objective of all.