Release early, Release often, A SVN/FTP Deployment Task

Posted by Felix Geisendörfer, on Nov 22, 2006 - in PHP & CakePHP » Other

Deprecated post

The authors of this post have marked it as deprecated. This means the information displayed is most likely outdated, inaccurate, boring or a combination of all three.

Policy: We never delete deprecated posts, but they are not listed in our categories or show up in the search anymore.

Comments: You can continue to leave comments on this post, but please consult Google or our search first if you want to get an answer ; ).

Warning: All of this is meant for CakePHP 1.2 which is still under heavy development. People are not recommended to use 1.2 so far unless they are very experienced with CakePHP and able to fix their problems them selfs. There will be no official support for the 1.2 branch before it's released and it might go through some major changes before that.

After recently releasing my experimental little testsuite called CakeTaster it is time for me to release the next project I've been working on. This one might be even more interesting for most people, as it's already pretty advanced. Nevertheless I consider this to be an experimental release, so plz don't depend on it quite yet ; ).

As the headline says, this time it's going to be my SVN/FTP Deployment Task written for the new Bake in CakePHP 1.2. It will not work with the Cake 1.1.x.x branch, and I currently do not have time to explain the procedure to work around this.

First of all let me explain what it does (or is supposed to do). The job of this task is to SYNC a given SVN repository with a remote folder of an FTP server. It provides functions to install, update, or delete this remote copy of your application. The install/update function also allow you to specifiy a revision you want to install or update to. This way you can roll back a recent update if you discover a problem, or simply take your app back in time for the fun of it ; ).

Sounds interesting? Time to get started. First of all download the code. Then directly copy all the folders over the ones of your application. Nothing should be overwritten, but it's your responsible to double check that. Once you are done with this, go to /app/config/deployment.php and start to edit this file. You should see something like this:

php
  1.  
  2. class AppDeployment extends BasicDeployment
  3. {
  4.     var $ftpConfig = array('host'      => 'playground.thinkingphp.org',
  5.                            'connect'   => 'ftp_connect',
  6.                            'login'     => 'user',
  7.                            'password'  => 'secret-pw',
  8.                            'port'      => '21',
  9.                            'timeout'   => '30',
  10.                            'base_path' => '/',
  11.                            'svn_file'  => '/app/webroot/revision.txt');
  12.  
  13.     var $ftpActions = array('chmod_777' => array('/app/tmp'));
  14.                            
  15.     var $svnConfig = array('url'       => 'file:///C:/Repositories/project',
  16.                            'login'     => '',
  17.                            'password'  => '',
  18.                            'path'  => '/trunk');
  19.  
  20.     // pluse some code I added to beautify the log output and set the php time limit to infinite
  21. }
  22.  

All you have to do is to fill in your FTP / SVN information and that's it. You're ready for the first little ride. Fire up your command line / shell and navigate to /cake/scripts/. Then type in the following command.

php -q bake2.php deploy install

Now you'll see that little shell of yours becoming very busy. It will export the latest version of your application from the SVN directory you specified into a temporary folder (If you see an error, please make sure the application can write to /app/tmp). After that it will login to the FTP server, upload all files, and finally recursively chmod the remote /app/tmp to 777.

Go ahead and make some changes to your application. Save them, commit them to svn. Then run this command:

php -q bake2.php deploy update

If everything is setup correctly, the task will contact the ftp server and download the revision file in order to know what revision is located on the remote server. After it knows this information it will diff this version vs. SVN:HEAD, checkout the modified files and upload (only) them in order to overwrite the old ones. It will also delete files that have been removed in the repository.

Alright, once you are finished jumping around your work place after enjoying this delightful deployment experience it's time to get a little fancier. (In case you hit a problem before that, leave a comment and I'll try to help you to get to the happy-jumping-around part). For a simple application the default deploy behavior will be all you ever need. But as we developers tend to create space ships whenever we are asked to do something sligthly more complex then printing "Hello World", here comes some freedom: The /app/config/deployment.php contains a class called AppDeployment which extends BasicDeployment. Functionality like install/update/uninstall are actual functions inside the BasicDeployment class. This means you can overwrite them.

Just take a look at the BasicDeployment::install() function, to get a better feel for how it works:

php
  1. function install($installRevision = 'HEAD')
  2. {
  3.     $remotePath = $this->ftpConfig['base_path'];
  4.     $tmpFolder = TMP.'svn';
  5.  
  6.     $this->__deleteTmpFolder($tmpFolder);
  7.    
  8.     if (!$this->__svnExport($Svn, $tmpFolder, $installRevision))
  9.         return false;
  10.    
  11.     if (!$this->__svnCreateRevisionFile($Svn, $tmpFolder, $installRevision))
  12.         return false;
  13.    
  14.     if (!$this->__ftpConnect($Ftp))
  15.         return false;
  16.    
  17.     if (!$this->__ftpUploadDir($Ftp, $tmpFolder, $remotePath, true, false))
  18.         return false;
  19.  
  20.     if (!$this->__ftpExecuteActions($Ftp, $remotePath))
  21.         return false;
  22.    
  23.     $this->__ftpDisconnect($Ftp);
  24.     $this->__deleteTmpFolder($tmpFolder);
  25.    
  26.     $this->log('Succesfully installed app at '.$this->ftpConfig['base_path'].' (Revision '.$this->__svnResolveRevision($Svn, $installRevision).').', 'info');
  27.    
  28.     return true;
  29. }

Now it's your turn. Try out the task, start playing around with it, and let me know what yout hink about it. I've been talking with the other devs and it's not out of question for this to become part of the CakePHP core. But to make this possible I need all the testing I can get, and as much feedback as you guys can give me ; ).

-- Felix Geisendörfer aka the_undefined