PHP is a great choice to create web applications. While PHP continues to be a modern language, simply using a modern language is not enough for modern applications. Instead, you also need to ensure you can update your application quickly, and ensure its quality with tests. Of course, all of that must be automatic, and you can do that with Continuous Integration. You have many options for CI, but Azure DevOps is the easiest one. This article is your how to Azure DevOps PHP CI.
In case you still need to explore the benefits of CI, I recommend reading this. If, instead, you want to understand why PHP is still a good choice for modern web applications, start here.
Azure DevOps PHP
Your project in Azure
Azure works great with its native tools. If you have your source control inside of Azure, everything will go much smoother, and that’s what we will do today. However, Azure can support third-party Git providers as well.
The first thing we need to do is having a repository in Azure where we want to put our PHP code. Thus, go to the Azure website and login or register to the DevOps service. Once you are inside Azure DevOps, you will see a dashboard with all the organizations you belong to, like the one below.
If it is the first time, Azure will ask to set up your first organization. Just follow the Wizard, an organization is basically a group of people working on the same set of projects. Once you have some organizations, you can manage different projects in each. As you can see here, the organization named rational scale has one project, named RSBP. You can always create a new one with the button on the top-right. In this example, we already have a project, and we will select it. Instead, you may need to create a new one.
Inside the project
Now that we created the project we are set to continue with our Azure DevOps PHP tutorial. A project does not merely represent an application. Instead, it can include several things beyond code, like Wiki or tasks to do. By creating the project, we created just the outer shell. Now, we actually need to create a Git repository to host the code. You can have as many as you need in each project. To create one, navigate in the Repos page on the left menu.
If you have no repository, you will just see a button to create a new one. If, instead, you already have one, you can select it in the drop-down and select New repository, like in the following screenshot.
Now, you have a repository, and you can add it to your Git client on your PC. To do that, just use the HTTPS URL you see in your browser. Git will ask you to authenticate, you can use the same credentials you use to log-in into the Azure DevOps portal.
At this point, you can treat this repository like any Git repository. Write your PHP code, install composer dependencies, and write the tests. Fork into different branches, have a master and a dev branch, and all the things you usually do when you develop. Once you have some code, you are ready to start the CI process.
CI: Azure Pipelines
Our first Pipeline
The component in Microsoft Azure that takes care of Continuous Integration are Azure Pipelines. A pipeline is a set of steps you want Azure to do. Typically, you let Azure watch your repository. Every time you commit changes to some specific branches, like the master, Azure runs the pipeline. In the pipeline, you want Azure to try to install all the dependencies, run the tests, and eventually build the code.
Azure can do all of that on a Ubuntu server or a Microsoft server, for free. It is Microsoft giving you temporarily the server to do all of that. You may have some special software or hardware version you want to test your code on. If that’s the case, you can configure your server so that Azure can ask it to do the tests. That’s for another tutorial. For today, we are going to use a simple Ubuntu pipeline.
Creating the Pipeline
Before we start, create a file named pipeline.yaml at the root of your project, and ensure all branches have it, even if it is empty. We will need that file to complete the creation of the pipeline.
In the pipeline section, you will have just a button to create a new pipeline, since you don’t have any. Create it, and it will present you with the following dialog, where you tell Azure where your code is. In our case, the code is inside Azure, so we can just select our repository. We may also want to select a default branch. In fact, you can trigger the run of a pipeline whenever you want. If you do that and don’t specify the branch, it will run on the default branch. Be aware that every time you commit and push to azure to any branch, the pipeline will run for that branch as well.
Then, continue and select YAML in the next screenshot. This means we will describe what we want Azure to do using YAML, a user-friendly descriptive language.
Now, in the following screen, select the path to the YAML file we created inside the repository and we are all set.
The YAML File
The YAML file is now at the core of our Azure DevOps PHP project. It defines how Azure should test and build your application, and the good news is that it is part of the source control itself. Of course, we need to write some code to tell Azure what to do. Here is an example YAML file that will work for most PHP projects.
pool:
vmImage: 'ubuntu-16.04'
variables:
phpVersion: 7.2
steps:
- script: |
sudo update-alternatives --set php /usr/bin/php$(phpVersion)
sudo update-alternatives --set phar /usr/bin/phar$(phpVersion)
sudo update-alternatives --set phpdbg /usr/bin/phpdbg$(phpVersion)
sudo update-alternatives --set php-cgi /usr/bin/php-cgi$(phpVersion)
sudo update-alternatives --set phar.phar /usr/bin/phar.phar$(phpVersion)
php -version
displayName: 'Use PHP version $(phpVersion)'
- script: |
composer self-update
composer dump-autoload
composer install --no-interaction --prefer-dist
displayName: 'Install Composer'
- script: './vendor/bin/phpunit --log-junit TEST-RESULTS.xml'
displayName: 'Run tests with phpunit'
- task: PublishTestResults@2
inputs:
testRunner: 'JUnit'
testResultsFiles: '**/TEST-*.xml'
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(system.defaultWorkingDirectory)'
includeRootFolder: false
- task: PublishBuildArtifacts@1
First, we define what environment we want with the pool
group of commands. Then, we define a set of variables to use in the rest of the script. In our case, we just define the variable phpVersion
that will hold the version of PHP we want.
Then, we have the steps. Steps are the things Azure does, one by one, to build and test the code. By default, Azure runs steps in sequence. We have three script
steps, that are commands sent to the CLI of the Ubuntu virtual machine. Then, we have three task
steps, things that Azure itself does.
First, we install PHP with the version specified in the variable. Then, we install dependencies with composer. After that, we run the tests and write the result of the tests in JUnit format in the file TEST-RESULTS.xml
. Finally, we ensure Azure go fetch the tests’ results (PublishTestResults
) and store the result of the build (ArchifeFiles
and PublishBuildArtifacts
).
Save that file into your pipeline.yaml and commit it to the project. See how it goes.
Our pipeline in production
From now on, Azure will take care of running our pipeline every time we commit. It will keep track of failed and successful builds, and you can select each and inspect what went wrong. Azure presents you with a summary where each line is a step, and you can click on them to expand and see what happened, including the output of our Ubuntu server. Here is an example.
In Conclusion
In this article, we presented how to implement an Azure DevOps PHP Continuous Integration process. Now we can implement full CI on our PHP code with the ease of tools provided by Azure. Hopefully, this will help you write better and more reliable code, as it has helped me in several projects. Just let me know what you think about PHP in Azure in the comments.