CI/CD of CakePHP with Bitbucket Pipelines & shared hosting server via FTP

Automatically build, test and deploy a CakePHP application using Bitbucket Pipelines to a shared hosting server via FTP with PHPloy.

CI/CD of CakePHP with Bitbucket Pipelines & shared hosting server via FTP
4 min read
Posted: by Kai Niklas

Prerequisites #

  • Bitbucket account
  • Git installed on development machine
  • PHP installed on your development machine
  • Composer installed on development machine

Create a Bitbucket repository #

First we create a new Bitbucket repository.

Create new Bitbucket repository

Initialize and commit CakePHP application #

For this demonstration we create a skeleton CakePHP application by using the following command which we type into our command line:

composer create-project --prefer-dist cakephp/app cakephp-ci-demo

If you are interested in what you just created start it with the build in server and start your favorite browser:

cd cakephp-ci-demo
bin/cake server -p 8765
Demo app in browser

Now we can share (aka link) the local git repository with our Bitbucket repository. You can find your git URL in the Bitbucket repository overview. For me the commands look like this:

# switch to porject folder in ./cakephp-ci-demo

git init
git remote add origin https://kainiklas@bitbucket.org/kainiklas/cakephp-ci-demo.git

git add -A
git commit -m "Initial commit"
git push origin master

Now the code should be visible in our Bitbucket repository.

Initialize Bitbucket Pipeline #

We navigate to our repository on bitbucket.org and click on Pipelines in the left navigation menu. The first time we click on it, it will take some time until we see something (~ 5–10 seconds). We scroll down the page and choose PHP. Then we commit the file and the pipeline starts automatically.

At first, it looks all nice and pretty, but then the pipeline fails with some problems which we will fix later.

#1: cakephp/cakephp 3.5.11 requires ext-intl * -> the requested PHP extension intl is missing from your system.

#2: symfony/debug v4.0.3 requires php ^7.1.3 -> your PHP version (7.1.1) does not satisfy that requirement.

And 5 more.
First Pipeline run fails

Deployment strategy via FTP using PHPloy #

We want to deploy our code to the shared hosting server via FTP. This can be achieved in several ways. A pretty general way is for example the tool git-ftp. But we will use PHPloy which I prefer as it has some handy additional features. Most important for me are the following:

  1. Native PHP support as we have a PHP project
  2. A configuration file phploy.ini to define several staging environments.
  3. Transfer files which are ignored by git, e.g. the/vendor folder which is required to run the app.
  4. Ignore file which are versioned in git, e.g. the /test folder which is not required on a production server.
  5. Remove files on the server, e.g., clean /cache folder.

Install and configure PHPloy for production deployment #

First, we require the PHPloy dependency using composer:

# switch to ./cakephp-ci-demo
composer require "banago/phploy"

Then we create the phploy.ini file with the following content for the production environment. Do not forget to change user and host with your values. The password we set later as an environment variable.

[production]
scheme = ftp
user = 'username'
host = 'demo.com'
path = '/'
ssl = true

; files that should be ignored and not uploaded to the server, but are still tracked in git
exclude[] = 'config/schema/*'
exclude[] = 'tests/*'
exclude[] = '.editorconfig'
exclude[] = '.gitattributes'
exclude[] = '.travis.yml'
exclude[] = 'composer.json'
exclude[] = 'composer.lock'

; Files that are ignored by git, but you should be send to server
include[] = 'vendor/*'

; Filed that should be deleted on the server
purge[] = "tmp/"

Complement the composer.json descriptor #

We want to have a deploy command which we can call via composer. This can be achieved easily by adding the following line in the composer.json file in the scripts section:

"scripts": {
...
"deploy-to-production": "phploy -s production"
}

Before we deploy anything into production we want to run all unit tests to make sure that everything works. Therefore, we need to include it in our composer file:

composer require --dev phpunit/phpunit

Configure Bitbucket Pipeline for CakePHP #

Our goal is to push updated code to a shared hosting provider via FTP if the code builds and all tests pass. Therefore, we first need to store (securely) the credentials to our build server (the pipeline in Bitbucket). We will do this using environment variables instead of hard coded values in the build script.

Set the password environment variable #

The environment variable we set is called PHPLOY_PASS and contains the password of the FTP user.

Important: Never store passwords in any code repository.

Set environment variable in settings

Configure the pipeline #

Lets check out the pipeline file which we generated earlier in Bitbucket and configure it for CakePHP:

# switch to ./cakephp-ci-demo
git pull origin master

Open the filebitbucket-pipelines.yml to configure it.

# This is a sample build configuration for CakePHP >=3.5
# Official Bitbucket Pipeline documentation: https://confluence.atlassian.com/x/e8YWN
# Only use spaces to indent .yml configuration.
# -----

image: edbizarro/bitbucket-pipelines-php7

pipelines:
branches:
master:
- step:
caches:
- composer
script:
- composer install --no-interaction --no-progress --prefer-dist
- composer test
- composer deploy-to-production

Explanation of the configured pipeline #

With image: edbizarro/bitbucket-pipelines-php7 we tell our piepline which docker container should be used for the build. For CakePHP we require a higher PHP 7 version as the default php image provides. Further, we would need to install composer and the php extension intl using the default PHP 7 container. Otherwise our build will fail as we already saw earlier. The docker image edbizarro/bitbucket-pipelines-php7 contains the tool and the php extension (and more which we do not need for the demo).

Using branches: master: we define, that the pipeline should run as soon as we check in code to the master branch.

With caches: -composer we cache all downloaded composer packages which are downloaded during the installation of dependencies. This will speed up the subsequent runs.

The last part are the scripts in the script: section. We 1) install all required modules, 2) test the application and 3) deploy it to the server. If any command fails, the whole pipeline fails. That means, a failed test will prevent from deploying to the server (which is good as we do not want to break the production).

Test the Pipeline #

Testing our pipeline is pretty easy. We simply need to change a file and push it to the master branch. As we have not checked in any file into our repository yet, we can test the pipeline by checking in our work now:

# switch to ./cakephp-ci-demo

git add -A
git push origin master

Final thoughts #

The presented pipeline is a simple demonstration and can be enhanced in several ways. Topics for a follow up include:

  • Deployment to multiple stages (DEV, QA, PROD)
  • Propagation of stable code using different git branches
  • Execution of tests including a DB
  • DB migration tests
  • Rollbacks

Further readings #

PHPCICD

4 min read
Posted: by Kai Niklas

kai-niklas.de - All rights reserved