Contents


Test and deploy PHP applications automatically on IBM Bluemix

Use an IBM Bluemix Continuous Delivery toolchain with GitHub integration and Travis CI to automatically deploy your latest codebase to your IBM Bluemix environment

Comments

Back when I started out as a developer, testing an application usually involved compressing the application code files into a ZIP archive or placing them on a shared network file server, transferring them to a test environment, decompressing or copying them to the correct location, compiling them if necessary, then manually running various tests. Needless to say, this was a time-consuming, frustrating, and error-prone process, not one that many people enjoyed.

Fast forward to now when things are so much easier. With new continuous delivery tools readily available, application code is pulled from its repository whenever a change is made and deployed to a test or production environment automatically and securely. There's no manual fiddling with ZIP files, network shares, or configuration files, and it's very easy to check the current status of a deployment or roll it back to a previous version.

IBM Bluemix Continuous Delivery provides a secure, automated way to build, test, and deploy your PHP applications in a consistent and error-free manner.

The IBM Bluemix® Continuous Delivery service is a useful because with it, you can set things up so that every new commit or successful pull request in your GitHub repository automatically builds, tests, and deploys your revised application code to IBM Bluemix. Let me show you how.

What you will need

The goal of this article is to introduce you — a PHP developer looking to add continuous delivery to your PHP application hosted on Bluemix — to the Bluemix Continuous Delivery service and the capabilities it can add to PHP applications. I will use a basic PHP application (including unit tests) and a simple toolchain to move the application from GitHub to Bluemix. In this scenario, the target Bluemix deployment will always reflect the latest tests passed version of the PHP application's development branch.

The basic process outlined in this article is as follows:

  1. Each time a pull request is created in the GitHub source repository, the source code will be automatically tested by Travis CI with PHPUnit to ensure all unit tests pass.
  2. If the unit tests pass, the pull request will be manually or automatically merged into the repository's development branch. This merge will automatically trigger a new deployment of the application on Bluemix using a Bluemix Continuous Delivery toolchain.
  3. If the unit tests fail, the pull request will not be merged and the current deployment on Bluemix will remain unaffected.

This simple process should work to keep your Bluemix deployment current with your latest development branch. Once you understand this process, you should have no trouble adapting it to meet more complex requirements.

Note that the approach described in this article is primarily intended to ensure that your test and development environments always reflect the latest changes in the under development branch of your application code. Although you can also use the approach described here to automate deployment to your application's production environment, this is not something you'd want to do without first considering the inherent risks involved (and subsequently, putting the appropriate controls in place to manage such risks).

Here's what you'll need:

1

Create the PHP application

To follow the steps in this article, you will need a PHP application with PHPUnit unit tests in your local development environment; here are the instructions for creating such an application. You can skip this step if you already have a PHP application that meets these requirements either in your local environment or in a GitHub repository. If you don't, you can follow these instructions or clone the example application's source code on GitHub.

Begin with this Composer configuration file, which should be saved to $APP_ROOT/composer.json ($APP_ROOT refers to your project directory). The processor class and namespace don't exist yet, but you'll create them shortly.

{
    "require": {
          "slim/slim": "^3.8",
          "slim/php-view": "^2.2",
          "phpunit/phpunit": "^5.7",
          "ext-mbstring": "*"
    },
    "autoload": {
        "psr-4": {
            "App\\Processor\\": "src/app/processors"	 
        }
    }
}

Install the configuration file using Composer with the command

shell> php composer.phar install

Next, set up the main control script for the application. This script will load the Slim framework and initialize the Slim application. It will also contain callbacks for each of the application's routes; each callback defines the code to be executed when the route is matched to an incoming request. Create this script at $APP_ROOT/public/index.php with the following content:

<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

// autoload files
require '../vendor/autoload.php';

// configure Slim application instance
// initialize application
$app = new \Slim\App();

// initialize dependency injection container
$container = $app->getContainer();

// configure processor in DI container
$container['processor'] = function ($container) {
  return new \App\Processor\MyProcessor();
};

// "hello world" controller
$app->get('/hello[/{name}]', function (Request $request, Response $response) {
    $name = $request->getAttribute('name');
    if ($name) {
      $processedName = $this->processor->process($name);
      $response->getBody()->write("Hello, $processedName!");
    } else {
      $response->getBody()->write("Sorry, we haven't been introduced yet.");    
    }
    return $response;
});

$app->run();

This code is a variant of the Slim framework's official "Hello world" script. It sets up the application route /hello/$NAME and, when you browse to this route and provide a name, it greets you with a welcome message. If no name is provided, it displays a polite error.

This version of the script adds a processor class to the Slim dependency injection container to perform some basic string processing on the input name. This processor class is included only to add some meat to the bones of the PHPUnit unit tests, and it looks like this (save it to $APP_ROOT/src/app/processors/MyProcessor.php):

<?php
namespace App\Processor;
class MyProcessor
{
  public function process($string)
  {
    return ucfirst(strtolower($string));
  }
}

Finally, add the recommended Apache rewrite rules to $APP_ROOT/public/.htaccess:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^ index.php [QSA,L]
</IfModule>

Check to determine that the application works by browsing to http://localhost/hello/james (update this URL to reflect your local Apache environment as needed) and you should see similar output:

Figure 1. Example PHP application
Example PHP application
2

Create the PHPUnit test suite and GitHub repository

Now add some real and dummy PHPUnit tests for your application to use at $APP_ROOT/tests/AppTest.php:

<?php
use PHPUnit\Framework\TestCase;
class AppTest extends TestCase
{
    public function testTrue()
    {
        $value = true;
        $this->assertTrue($value);
    }

    public function testEmpty()
    {
        $arr = [];
        $this->assertEmpty($arr);
    }
    
    public function testProcessor()
    {
        $processor = new \App\Processor\MyProcessor();
        $this->assertEquals('John', $processor->process('john'));
        $this->assertEquals('John', $processor->process('JOHN'));
    }

}
?>

Create a minimal PHPUnit configuration file at $APP_ROOT/phpunit.xml with the following content:

<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnFailure="false" syntaxCheck="false">

    <testsuites>
        <testsuite name="Test suite">
            <directory>./tests/</directory>
        </testsuite>
    </testsuites>

</phpunit>

Run PHPUnit and make sure all your tests pass:

Figure 2. PHPUnit test runner
PHPUnit test runner
PHPUnit test runner

Finally, create a repository through the GitHub website and push your code to it using commands like the ones shown in the following code listing. Create two branches: master for the production codebase and dev-master for the development codebase.

shell> git init
shell> git add .
shell> git commit -a
shell> git remote add origin https://github.com/$GITHUB-USERNAME/$GITHUB-REPOSITORY-NAME.git
shell> git push origin master
shell> git checkout -b dev-master
shell> git push origin dev-master

Make a note of the GitHub repository URL because you will need it for the next step.

Figure 3. GitHub repository URL
GitHub repository URL
GitHub repository URL
3

Deploy to Bluemix

It's now time to deploy the application to Bluemix from your local development environment. If you skipped the previous two steps because you already had a PHP application repository in GitHub, clone your repository to your local development environment before proceeding.

Create the application manifest file, remembering to use a unique host and application name by appending a random string to it (like your initials).

---
applications:
- name: myapp-dev-[initials]
memory: 256M
instances: 1
host: myapp-dev-[initials]
buildpack: https://github.com/cloudfoundry/php-buildpack.git
stack: cflinuxfs2

You must also configure the build pack to use the public/ directory of the application as the web server directory. Create a $APP_ROOT/.bp-config/options.json file with the following content:

{
    "WEB_SERVER": "httpd",
    "COMPOSER_VENDOR_DIR": "vendor",
    "WEBDIR": "public",
    "PHP_VERSION": "{PHP_56_LATEST}"
}

Now, go ahead and push the application to Bluemix:

shell> cf api https://api.ng.bluemix.net
shell> cf login
shell> cf push

You should now be able to browse to the application at http://myapp-dev-[initials].mybluemix.net/hello/james and see the welcome message you saw at the end of Step 1 where you created the PHP application. If you don't see the message, find out what went wrong using a debug log.

4

Create the Bluemix Continuous Delivery toolchain

From within the Bluemix console, click the menu icon in the top left corner and then select the Services -> DevOps submenu. On the service details page, click Create a Toolchain and choose the Simple Cloud Foundry toolchain.

Figure 4. Toolchain creation
Toolchain creation
Toolchain creation

This toolchain template comes pre-configured to use GitHub and the Delivery Pipeline service. On the toolchain configuration page, enter a name for the toolchain. Select the GitHub icon and authorize Bluemix to access your GitHub account. Once this one-time authorization process is complete, choose an existing repository and enter the source repository URL on GitHub from Step 2 where you created the GitHub repository.

Figure 5. Repository integration
Repository integration
Repository integration

Click Create to create the toolchain. The toolchain and Delivery Pipeline service will now be initialized with some preset defaults, and a webhook will be added to your GitHub repository so that the Delivery Pipeline service is automatically notified about changes to the repository. You should see something like Figure 6 in the toolchain overview page in your Bluemix dashboard.

Figure 6. Toolchain overview
Toolchain overview
Toolchain overview

Click the Delivery Pipeline icon and you should see that the pipeline is already configured with two stages: Build and Deploy.

Figure 7. Toolchain stages
Toolchain stages
Toolchain stages

Although these stages use sensible defaults for most settings, you will still need to check them once, following these steps:

  1. In the Build stage panel, click the Configure Stage icon. In the Input tab, check that the GitHub repository details are correct and that the Branch field is set to dev-master.
    Figure 8. Build stage configuration
    Build stage configuration
    Build stage configuration
  2. In the Deploy stage panel, click the Configure Stage icon. In the Jobs tab, check that the deployment details (region, organization, space, and application name) are correct. Note that the application name will be overriden by the settings in the application manifest file in the repository.
    Figure 9. Deploy stage configuration
    Deploy stage configuration
    Deploy stage configuration

Save any changes made to the stages.

Test the toolchain by committing a minor change to the dev-master branch of the GitHub repository — for example, by changing the welcome message from "Hello..." to "Aloha..." If the toolchain is configured correctly, the change should be detected by the Bluemix Delivery Pipeline service and this in turn should trigger the Build and Deploy stages in sequence. You should be able to see the changes in real time as the new version of the application is built and deployed to Bluemix.

Figure 10. Toolchain in action
Toolchain in action
Toolchain in action

In case of an error, you can use the View logs and history link in each stage to obtain logs detailing what went wrong.

Figure 11. Toolchain logs
Toolchain logs
Toolchain logs

At this point, your toolchain is operational and every commit to the specified GitHub repository and branch will trigger a new deployment of the application code on Bluemix. But you're not done yet.

5

Configure Travis CI to build and test pull requests

If you're working in a distributed team, it's likely that you won't be committing directly to a main repository branch. Most of the time, you'll be creating pull requests that will be reviewed, tested, and merged manually or automatically.

That's where Travis CI comes in. Travis CI is a continuous integration engine that's available for all GitHub repositories, and it can be configured to build and run tests (including PHPUnit tests) for each new pull request and flag the build as a pass or a fail. A reviewer can then manually merge the pull request into the repository, or Travis CI can be configured to automatically perform this task through a custom script.

I'm sure you can see where I'm going with this. You can set things up so that changes proposed to your application through pull requests can be automatically tested by Travis CI and then merged into your dev-master branch. Remember that this branch is already being monitored by the Delivery Pipeline service, so each successful merge will result in the new version of the application being automatically deployed to Bluemix by the toolchain configured in Step 4.

Begin by logging in to the Travis CI website with your GitHub account credentials and granting Travis CI access to your GitHub account.

Figure 12. Travis CI-GitHub integration
Travis CI-GitHub integration
Travis CI-GitHub integration

From your Travis CI profile page, turn on the Travis CI engine for your GitHub repository. Once Travis CI is enabled for your repository, click the Settings icon for the repository in the Travis CI interface to configure build settings.

Figure 13. Travis CI engine activation
Travis CI engine activation
Travis CI engine activation

In the General section, ensure that Build pull request updates is on.

Figure 14. Travis CI configuration
Travis CI configuration
Travis CI configuration

Create a minimal Travis CI configuration file at $APP_ROOT/.travis.yml with the following content:

language: php

php:
  - 5.6
    
install:
  - composer install --no-interaction

branches:
  only:
    - "dev-master"
    
script:
  - vendor/bin/phpunit

Briefly, this configuration file tells Travis CI to only build the dev-master branch and to use the vendor/bin/phpunit script to test the build. If successful, Travis CI will flag the build as passing so that it can be manually merged.

Test the configuration by creating a new pull request in your GitHub repository's dev-master branch. Travis CI should register the pull request and go to work building and testing it. You will be able to track the progress of the build from your Travis CI profile page.

Figure 15. Travis CI in action
Travis CI in action
Travis CI in action

If the code builds and passes tests, merge it into the dev-master branch of your GitHub repository.

Figure 16. GitHub merge operation
GitHub merge operation
GitHub merge operation

The IBM Continuous Delivery toolchain will now take over and deploy the revised codebase to Bluemix, as I described in Step 4 where you created the Bluemix Continuous Delivery toolchain.

If you're the impatient sort and don't want to wait to manually merge successful builds or if you have a substantial ongoing stream of pull requests, you can have Travis CI automatically merge successful builds into your repository. This type of unattended, automated merging carries risks with it, so you should only consider this for your development branch.

Travis CI doesn't include any built-in capabilities for automated merging, so you will need a custom script to do this. For examples of some auto-merge scripts, refer to the links at the end of this article. You can also create your own script to do this and other related tasks, such as issuing a notification or updating a project board.

Once you've created the custom script, remember that you must tell Travis CI to invoke it on successful builds by adding a block similar to the example in your $APP_ROOT/.travis.yml file:

after_success:
  - chmod +x ./do-merge.sh 
  - ./do-merge.sh

Conclusion

In this article, I demonstrated how you can use the Bluemix Continuous Delivery service to keep your Bluemix application deployment in sync with your GitHub code repository. By providing a ready-made toolchain template that's configured to work with GitHub out of the box, Bluemix Continuous Delivery provides a secure, automated way to build, test, and deploy your PHP applications in a consistent and error-free manner.

Bluemix offers a number of ready-made tool integrations, so you can also combine your toolchain with other popular tools, such as Slack for notifications or JIRA for issue tracking. Try it out and see for yourself!

Acknowledgements

Thanks to Chris Down for his Travis auto-merge script, a modified version of which was used when writing this article.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Cloud computing
ArticleID=1048623
ArticleTitle=Test and deploy PHP applications automatically on IBM Bluemix
publish-date=08212017