views:

862

answers:

3

Hi All,

How to correctly deploy applications from development to production and how to deal with multiple site configurations. All my development are done thru svn located at var/svn/myapp/trunk and the actual production code is in /var/www/myapp.

I check out the latest code to my local machine into a directory called "myapp_latest_svn". I have site and location specific code in my main settings.php, which has H_PATH = 'http://myapp.com' & db config settings for db_host, db_user_name and db_password which is as you know different in local machine settings ( where localhost/myapp.com is just an Apache alias) & on the production ( live site runs on myapp.com) server.

Also the .htaccess file is different from that on the production server. In short, there are a number of differences between dev and production.

I keep all my work in SVN. Every morning i use SVN Update which updates the latest code to my local svn repository. When I am ready to go live, I build a release with svn Commit.

Then in the release I have to remember to change all the appropriate dev files to their production counterpart. Now I had to manually edit the production settings.php & .htaccess to reflect the site specific changes.

I am looking for an automated way to go from dev to production complete with versioning and no manually editing of files which is error prone and bad practice.

One way is making the production version of files read only (0444). That way when I do a svn export, they are not overwritten by the dev version of the files and I don't have to worry about editing files on each move from dev to production. But that's bad way of doing things like continuous integration.

Also by making multiple copies of the settings.php (one for localhost, beta, and prod). Then using a shell script that exports from svn, and then once the export is done, it replaces the settings.php with the correct settings.php, depending on the location that we are deploying to. That way everything is automated. But this is also a lame way to go.

Last way is

if( eregi ("myapp.com$", $_SERVER['HTTP_HOST']) ){

    define('H_PATH', 'myapp.com');

} else {

    define('H_PATH', 'localmyapp.com');

}

This is fine as far as settings.php is concerned. But what abt the .htaccess, u cannot check like the above in .htaccess.

What I don't want end up doing every time I deploy my site that I have to change settings.

My DB schema is not in version control so db is not an issue with me, only the settings.php and .htaccess.

Also how can i tell svn not to update some directories since that is also site specific (/log, /cache, /assets, /downloads). Also i need to preserve the apache ( www_data) write access intact for the above files as well.

Lastly i don't want to copy the empty trunk directory and the .svn files to the production server when i export.

How can i use Phing or even a shell script to integrate without causing any of these issues when building from svn to production servers.

This could be useful for many wannabe app developers out there in the wild.

Thanks in advance,

ocptime

+8  A: 

I'd recommend you look at Capistrano for your deployment woes. I used it to deploy PHP systems, and it will do everything you describe (with a little script work in your deploy recipe). Take a look here for more info.

I don't keep any config files in my remote repo - when I checkout in dev, I can add them once, then ignore them so I don't check them im by accident. When it comes to deploying, my cap deploy recipe is set up so that it will write the settings files into the deployed version. This way, I never have to worry about deploying and missing anything critical.

Cap also takes care of any uploaded assets (symlinking the directories so they remain in place on each deploy), and it also automatically backs up all asset files and the database on deploy to Amazon S3. Pretty nifty, eh?

Mr. Matt
Great link! Thanks!
Doug Neiner
+1  A: 

I store my settings files and .haccess in SVN with renamed filenames, e.g. settings.php.example and .htaccess.example. This way when I create a new release I don't need to worry about overwriting stuff.

Tom Haigh
+2  A: 

I have a Phing task called config, which asks me which environment I would like to configure the code for. The task accepts several possible values: local, development, staging, production, etc.

Once I tell it the environment, it reads in the appropriate .properties file (i.e. local.properties, production.properties, etc)

The next step will be the key for you: store TEMPLATES of your configuration and htaccess files, then run a filterChain replaceTokens task on them so their tokens are replaced with the values from the properties file.

Create these files:

common/build/templates/settings.tpl

define('H_PATH','##H_PATH##');
define('ENVIRONMENT', '##ENVIRONMENT##');

build/templates/htaccess.tpl

http://##H_PATH##

build/properties/local.properties

site.H_PATH = localmyapp.com
site.ENVIRONMENT = local

build/properties/production.properties

site.H_PATH = myapp.com
site.ENVIRONMENT = production

common/build/build.xml

<target name="config">
   <input propertyname="env" validargs="local,production">Enter environment name:</input>
   <property file="build/properties/${environment}.properties" />
   <copy file="build/templates/settings.tpl" 
     tofile="config/settings.php" overwrite="true"> 
     <filterchain>
      <replacetokens begintoken="##" endtoken="##">       
          <token key="H_PATH" value="${site.H_PATH}" />
          <token key="ENVIRONMENT" value="${site.ENVIRONMENT}" />
      </replacetokens>          
     </filterchain>
   </copy>      
   <copy file="build/templates/htaccess.tpl" 
     tofile="public/.htaccess" overwrite="true">    
     <filterchain>
      <replacetokens begintoken="##" endtoken="##">       
          <token key="H_PATH" value="${site.H_PATH}" />                                                           
      </replacetokens>          
     </filterchain>
   </copy>              
   <echo msg="Configured settings.php and .htaccess for ${environment}" />              
</target>                               

Now when you want to configure the site for running locally just type:

phing config

then type:

local

and press return. That's it! One huge benefit of this is that you no longer need ANY if/else statements in your code. Plus, it's not dependent on $_SERVER variables, so it'll work fine on the commandline.

lo_fye