A Web based system to push your SVN code through development, staging and production environments

Note the files in this post are now on GitHub

Hello there!

In development, having a seamlessly integrated process where you can propagate your code through whatever QA, testing and development policy you have is invaluable and a definite time saver.

We work with SVN as well as GIT code repository systems and have developed a web based system to “Export” or “Push” the code through development, staging and production environments as such.

I have already talked about sanitizing your code during the commit process, to ensure commit messages are standard and there are no PHP fatal errors, so now I will be showcasing you a simple web based system for propagating your code through development, staging and production servers.

This system should be on a secure web accessible page on each server. For the sake of argument , I’ll call each server the following :

dev.server.com — development server

staging.server.com — staging server

www.server.com — production server

We will be using PHP for the web based interface, and we will assume that you will be password protecting access to this page via htpasswd, as well as forcing SSL. I am also assuming that within your SVN repository, you have multiple “sites” that you will be individually pushing or exporting (svn export). Once you have the secure, password protected page (lets call it https://dev.server.com/svn) , the following PHP page will be the main index :

svnupdate.php

 "Site A",
"url" => "http://site-a.server.com",
"path" => "/usr/local/www/site-a.server.com",
"source" => "svn://svn.server.com/repository/branches/site-a",
"login" => "svnlogin",
"base" => "1.00",
"notes" => "Standard build for Site A"
);

"name" => "Site B",
"url" => "http://site-b.server.com",
"path" => "/usr/local/www/site-b.server.com",
"source" => "svn://svn.server.com/repository/branches/site-b",
"login" => "svnlogin",
"base" => "1.00",
"notes" => "Standard build for Site B"
);

?>





        SVN Update Page  

Server:

View Development Export Log

$value) { ?>
Site Source UN/PW Base Revision Export Pending Updates Notes
View

If you carefully look at the above code, you will see that this page will be dependent on 3 external scripts, which I will describe below. The page itself generates a list of whatever sites you want to include in the push process, within a PHP based Array. The array details important info per site such as the name, svn location, location of the files on the server as well as whatever other notes and additional info you want to provide.

Each time a site is “exported” by clicking the export button, it calls an external script called svnupdate_process.php. This executes the SVN EXPORT command, as well as logging which user requested the action into a simple text based log file. The user is determined by the authentication user that is accessing the page. The htpassword credentials you will be providing to your users should be set per-user so that it can be easier to determine who pushed the code and whatnot.

The other two external scripts are one that will view the log file in an iframe on the same page, as well as a script to extrapolate the pending commits that are in the queue since the LAST code push / svn export. That is really useful, as you can imagine.

Script to view the export log

This script, log.php is used to dump the contents of the log.txt export log file. Very simple

log.php





        Untitled



Development Export Log:
display(); ?>

Simple, right? The log.php code includes a functions.inc.php file, used for writing and reading the log.txt file. The above code depends on it, as well as the svnupdate_process.php code (described below), in order to log each time someone hits the export code button

functions.inc.php

filename = "log.txt";
                $this->Username = $_SERVER['PHP_AUTH_USER'];
                $this->logfile = $this->filename;
        }

        function write($data) { // write to logfile
                $handle = fopen($this->logfile, "a+");
                $date = date("Y-m-d H:i:s");
                $IP = getenv('REMOTE_ADDR');
                $data = "[$date] {$this->Username}:{$IP} - " . $data . "n";
                $return = fwrite($handle, $data);
                fclose($handle);
        }

        function display() { // display logfile
                $handle = fopen($this->logfile, "a+");
                while(!feof($handle)) { // Pull lines into array
                        $lines[] = fgets($handle, 1024);
                }
                $count = count($lines);
                $count = $count - 2;
                for($i=$count;$i>=0;$i--) {
                        echo $lines[$i] . "
"; } fclose($handle); } } ?>

The code of the svn export process is handled by the following script below. Again its self explanatory. PHP executes a shell command to export the svn code based on the array variables defined in the very first script. Make sure all the variables match up to whats in svn and the location of the files, and even execute a test run of the command manually with the variables. If there are problems, you can modify the command to pipe the output to a log file for further analysis. Additionally you may need to alter the permissions of the apache user so that the command can be properly run. Avoid setting the apache user to have a shell (big no-no) ,but maybe a nologin shell or something along those lines. Its completely up to you , but be very careful about the choices you make to get it to run properly.

svnupdate_process.php

Update/Status Window

&1"; if($_POST['submitbutton'] == "Export") { $output = shell_exec("umask 022;".$command); } echo "
$output

";
$logtext = "Exported to {$_POST['site']}";
$logfile->write($logtext);
eaccelerator_clear();
}

?>

Finally the last script will be the script that parses the SVN log output with a date/time range from the last time the export button was pushed, until the current date and time. This will load the output in the same iframe log window on the svn page so the user can see what pending commits are in the code since the last time it was exported. Invaluable information, right?

Note that this has a function to filter out additional illegal characters to avoid cross site scripting injections. This code should be completely 100% restricted from outside public use, however it might be worth it to put this function in the svnupdate_process.php script as well. Can’t be too careful. I thought I’d include it here for you to use.

viewcommit.php

',"'",'"',')','('), array('<',':','|','&','>',''','"',')','('), $input_str );
        $return_str = str_ireplace( '%3Cscript', '', $return_str );
        return $return_str;
        }

        $xss_path=xss_cleaner($_GET['path']);
        $xss_svn=xss_cleaner($_GET['svn']);
        $xss_name=xss_cleaner($_GET['name']);

        echo "Viewing Pending Updates For : ". $xss_name . "";
        echo "
"; $command = "/usr/bin/svn --username svnuser --password 'svnpassword' --config-dir /tmp log " . $xss_svn . " -r {"`grep "" . $xss_path . "" log.txt | tail -n 1 | awk -F " " '{printf "%s %s", $1,$2}' | sed -e 's/[//g' -e 's/]//g'`"}:{"`date "+%Y-%m-%d %H:%M:%S"`"}"; $output = shell_exec("umask 022;".$command); echo "
$output

";
}
else {
echo "No queries passed!";
}

?>

Lets break down the SVN log command, so you know whats going on. I’m grabbing the SVN site array variables when the “view log” link is clicked on the svn page. I am also parsing the export log text file to get the last entry for the particular site in question, grabbing the date and time.

I am then getting the current date and time to complete the date/time range in the svn log query. The finished query should look something like this :

svn --username svnuser --password 'svnpassword' --config-dir /tmp log svn://svn.server.com -r {"2013-01-01 12:01:00"}:{"2013-02-01 12:01:00"}

Note the files in this post are now on GitHub

Menu