When deploying an application to Windows Azure Web Sites, a number of deployment steps are executed. For .NET projects, msbuild is triggered. For node.js applications, a list of dependencies is restored. For PHP applications, files are copied from source control to the actual web root which is served publicly. Wouldn’t it be cool if Windows Azure Web Sites refused to deploy fresh source code whenever unit tests fail? In this post, I’ll show you how.
Disclaimer: I’m using PHP and PHPUnit here but the same approach can be used for node.js. .NET is a bit harder since most test runners out there are not supported by the Windows Azure Web Sites sandbox. I’m confident however that in the near future this issue will be resolved and the same technique can be used for .NET applications.
Our sample application
First of all, let’s create a simple application. Here’s a very simple one using the Silex framework which is similar to frameworks like Sinatra and Nancy.
1 <?php
2 require_once(__DIR__ . '/../vendor/autoload.php');
3
4 $app = new \Silex\Application();
5
6 $app->get('/', function (\Silex\Application $app) {
7 return 'Hello, world!';
8 });
9
10 $app->run();
Next, we can create some unit tests for this application. Since our app itself isn’t that massive to test, let’s create some dummy tests instead:
1 <?php
2 namespace Jb\Tests;
3
4 class SampleTest
5 extends \PHPUnit_Framework_TestCase {
6
7 public function testFoo() {
8 $this->assertTrue(true);
9 }
10
11 public function testBar() {
12 $this->assertTrue(true);
13 }
14
15 public function testBar2() {
16 $this->assertTrue(true);
17 }
18 }
As we can see from our IDE, the three unit tests run perfectly fine.

Now let’s see if we can hook them up to Windows Azure Web Sites…
Creating a Windows Azure Web Sites deployment script
Windows Azure Web Sites allows us to customize deployment. Using the azure-cli tools we can issue the following command:
1 azure site deploymentscript
As you can see from the following screenshot, this command allows us to specify some additional options, such as specifying the project type (ASP.NET, PHP, node.js, …) or the script type (batch or bash).

Running this command does two things: it creates a .deployment file which tells Windows Azure Web Sites which command should be run during the deployment process and a deploy.cmd (or deploy.sh if you’ve opted for a bash script) which contains the entire deployment process. Let’s first look at the .deployment file:
1 [config]
2 command = bash deploy.sh
This is a very simple file which tells Windows Azure Web Sites to invoke the deploy.sh script using bash as the shell. The default deploy.sh will look like this:
1 #!/bin/bash
2
3 # ----------------------
4 # KUDU Deployment Script
5 # ----------------------
6
7 # Helpers
8 # -------
9
10 exitWithMessageOnError () {
11 if [ ! $? -eq 0 ]; then
12 echo "An error has occured during web site deployment."
13 echo $1
14 exit 1
15 fi
16 }
17
18 # Prerequisites
19 # -------------
20
21 # Verify node.js installed
22 where node &> /dev/null
23 exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment."
24
25 # Setup
26 # -----
27
28 SCRIPT_DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
29 ARTIFACTS=$SCRIPT_DIR/artifacts
30
31 if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then
32 DEPLOYMENT_SOURCE=$SCRIPT_DIR
33 fi
34
35 if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then
36 NEXT_MANIFEST_PATH=$ARTIFACTS/manifest
37
38 if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then
39 PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH
40 fi
41 fi
42
43 if [[ ! -n "$KUDU_SYNC_COMMAND" ]]; then
44 # Install kudu sync
45 echo Installing Kudu Sync
46 npm install kudusync -g --silent
47 exitWithMessageOnError "npm failed"
48
49 KUDU_SYNC_COMMAND="kuduSync"
50 fi
51
52 if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then
53 DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot
54 else
55 # In case we are running on kudu service this is the correct location of kuduSync
56 KUDU_SYNC_COMMAND="$APPDATA\\npm\\node_modules\\kuduSync\\bin\\kuduSync"
57 fi
58
59 ##################################################################################################################################
60 # Deployment
61 # ----------
62
63 echo Handling Basic Web Site deployment.
64
65 # 1. KuduSync
66 echo Kudu Sync from "$DEPLOYMENT_SOURCE" to "$DEPLOYMENT_TARGET"
67 $KUDU_SYNC_COMMAND -q -f "$DEPLOYMENT_SOURCE" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.deployment;deploy.sh"
68 exitWithMessageOnError "Kudu Sync failed"
69
70 ##################################################################################################################################
71
72 echo "Finished successfully."
73
This script does two things: setup a bunch of environment variables so our script has all the paths to the source code repository, the target web site root and some well-known commands, Next, it runs the KuduSync executable, a helper which copies files from the source code repository to the web site root using an optimized algorithm which only copies files that have been modified. For .NET, there would be a third action which is done: running msbuild to compile sources into binaries.
Right before the part that reads # Deployment, we can add some additional steps for running unit tests. We can invoke the php.exe executable (located on the D:\ drive in Windows Azure Web Sites) and run phpunit.php passing in the path to the test configuration file:
1 ##################################################################################################################################
2 # Testing
3 # -------
4
5 echo Running PHPUnit tests.
6
7 # 1. PHPUnit
8 "D:\Program Files (x86)\PHP\v5.4\php.exe" -d auto_prepend_file="$DEPLOYMENT_SOURCE\\vendor\\autoload.php" "$DEPLOYMENT_SOURCE\\vendor\\phpunit\\phpunit\\phpunit.php" --configuration "$DEPLOYMENT_SOURCE\\app\\phpunit.xml"
9 exitWithMessageOnError "PHPUnit tests failed"
10 echo
On a side note, we can also run other commands like issuing a composer update, similar to NuGet package restore in the .NET world:
1 echo Download composer.
2 curl -O https://getcomposer.org/composer.phar > /dev/null
3
4 echo Run composer update.
5 cd "$DEPLOYMENT_SOURCE"
6 "D:\Program Files (x86)\PHP\v5.4\php.exe" composer.phar update --optimize-autoloader
7
Putting our deployment script to the test
All that’s left to do now is commit and push our changes to Windows Azure Web Sites. If everything goes right, the output for the git push command should contain details of running our unit tests:

Here’s what happens when a test fails:

And even better, the Windows Azure Web Sites portal shows us that the latest sources were commited to the git repository but not deployed because tests failed:

As you can see, using deployment scripts we can customize deployment on Windows Azure Web Sites to fit our needs. We can run unit tests, fetch source code from a different location and so on. Enjoy!