views:

360

answers:

4

We use the ExpressionEngine CMS (php) to create websites. For each site, we set up a subversion repository and commit the EE installation as well as any custom templates, images, javascript, etc. that are used. Included in the repository is the file containing all of the environment variables and the .htaccess file.

We have a development server with a working copy of the repository updated via post-commit that we use to develop. When we are ready to release we create a branch in subversion, make any changes required for the production environment, tag the release number, export the repository, upload it to a new directory on the live server, and symlink the files into place. A rollback is as simple as symlinking back to the previous release.

The problem is that step where we have to modify the environment variables that need to be different for the dev and production servers. This is stuff like (un)commenting htaccess rules that would redirect to the wrong places, swapping out google map API keys because the domains are different, running scripts that minimize the javascript into one obfuscated file to keep the size and http connections down, etc.

The question is how could this be more automated? We would love to get the release procedure down to the bare minimum. I'm familiar with the existence of tools such as Capistrano and Make but I'm not sure how I could get them to modify all the files necessary... how would you organize such a thing? Is this worth spending time automating when it happens maybe once every couple of weeks?

A: 

I deal with this problem by adding configuration file to Subversion ignore list. It was already addressed here on Stackoverflow: see question #149485

Basically, I only keep setup.default.php in SVN, and in every installation I manually copy it to setup.php which is on ignore list. This prevents the file to be checked back in to the repo. There are rarely changes to this file and can be handled as the requirement occurs.

Michał Rudnicki
I guess I should've mentioned that the file with the API keys and whatnot has things added to it on nearly every release. Almost every new feature we add requires some environment variable.
Ty W
+3  A: 

A lot of the configuration options could be dealt with by switching on $_SERVER['HTTP_HOST'].

For example

switch ($_SERVER['HTTP_HOST']) {
    case 'developement.domain.com':
     $api_key = "dev environment api key";
     break;
    default:
     $api_key = "live environment api key";
}

Then for .htaccess issues you can set an alternate .htaccess file in your vhost definition using the AccessFileName directive:

<VirtualHost *:80>
    ServerName sitename
    AccessFileName .htaccess-dev
</VirtualHost>
Ben
I think we're going to use a variant on this answer. Instead of using $_SERVER['HTTP_HOST'] we'll probably use apache mod_env and php's getenv()... then have different values for the variable in .htaccess .htaccess-dev like you mentioned. all that's left is to rig something up in our makefile to minimize the javascript and such.
Ty W
A: 

Another alternative is to branch the configuration files once, into a release branch, and then mark them as edited on the destination, and then use a merge script that remember how to do a three-way merge. If the configuration changes on the source, then it will likely generate a conflict, which is a good thing, because you probably need to do similar changes on the destination.

Thus, you keep two trees going for the lifetime of the project: development, and release. As things mature in development, you integrate them over to release. You can have a third, QA, tree as well, if you have a more involved release process.

When you pull a new release, you copy from the working area to the "release" area (as a merge/integration), rather than pull a brand new branch. If you also want a snapshot-in-time of the release tree at that point, then make a separate branch/copy/tag that you use only for archival purposes.

Btw: this is one of the areas where Perforce shines -- it remembers what you already merged, and won't ever attempt to merge twice.

A: 

We deal with this by maintaining a config-specific directory.

So, for instance if you have different .htaccess and config.php files between dev and production they would be maintained in /trunk/config/{environment}/

We use ant/nant scripts to create release packages, and the scripts have a build task for each environment. Those tasks pick up the config specific files.

--

Another commenter suggests to switch on HTTP_POST. Unfortunately I can't comment directly (not a high enough rep). Using HTTP_POST to determine environmental configuration has potential security issues since the value of this comes from the client.

Will Hughes
I've always considered switching on user entered data secure because you are defining exactly what is allowed. Do you have an example of when it is not?
Ben
If you enable certain functions when executing in the development environment, then that functionality can be enabled by anyone providing the correct host. If instead you put those in a config-specific directory, then that risk is removed.
Will Hughes