Adding A CI/CD process to my work flow is one of the really quick wins I do on every serious project I work on.
Whilst most of my personal work is hosted on Gitlab, a recent project I was working had its code in Bitbucket. This was my first time working with Bitbucket, so I wanted to document how I built assets, linted and ran tests using its pipelines.
What will these pipelines do?
By the end of this article you should have a working bitbucket-pipelines.yml
file for your Laravel project which will do the following:
- Use
composer
to install your projects dependencies - Run
php-cs-fixer
to enforce a code style - Run
larastan
to run static analysis against the code base - Run
php-cs-fixer
andlarastan
in parallel - Run
phpunit
to run our projects test suite - For a production build
yarn run production
- Allow us to manually trigger a deployment to production using Laravel Deployer.
Gitlab CI vs Bitbucket
If you’ve used Gitlab CI before working with bitbucket-pipelines should feel similar even if the configuration is slightly different.
Here are the key differences I found:
- Instead of using a
.gitlab-ci.yml
file you’ll need to create abitbucket-pipelines.yml
in the root of your project. - Instead of defining stages bitbucket uses pipelines which are broken down by branches or tags and then into “steps”
That’s basically it!
Getting started
Start by adding a bitbucket-pipeline.yml
file in the root of your project and add the following lines:
1 | image: edbizarro/gitlab-ci-pipeline-php:7.4 |
Here we’ve picked a base docker image which has enough of the utilities we’ll need to run our pipeline steps against PHP 7.4.
We’ve also set up a default pipeline with 4 steps.
This will be the pipeline that gets run when we push code to our repository and there isn’t a specific set of rules defined for the given branch / tag that has been pushed to.
Each step has a yaml anchor associated with at the moment (step: *anchor-name). We’ll be making heavy use of these anchors throughout our pipelines in order to give us reusable steps.
Its worth noting that these steps get run in sequence - one after the other, we’ll come on to how we can run certain jobs in parallel shortly.
With our pipe steps defined we now need to define what those steps actually do, lets start by creating a new root level item called definitions
which has a key of steps
.
Now we can start to flesh out the *composer
step defined in our pipeline from before.
1 | definitions: |
Here we create a step called &composer
that the previously defined *composer
symbol refers to. It does the following:
- Checks the PHP version
- Runs composer install
- Creates a
.env
file - Creates an application key in the
.env
file - Caches all of the composer dependencies that have been downloaded for 1 week (bitbucket default)
- Creates artifacts of the .env file and vendor folder that will be passed to every subsequent step in the pipeline
With us having got through that step the rest of the steps in this pipeline should be pretty easy to follow:1
2
3
4
5
6
7
8
9
10
11
12
13
14- step: &php-cs-fixer
name: PHP-CS-Fixer
script:
- vendor/bin/php-cs-fixer fix --config=.php_cs.php --verbose --diff --dry-run
- step:
name: PHPStan
script:
- vendor/bin/phpstan analyse
- step:
name: PHPUnit
script:
- vendor/bin/phpunit --exclude-group=integration
artifacts:
- storage/logs/*.log
This gives us a basic sequential pipeline that will run on every push to our bitbucket repo where each step is after the former step succeeds.
A more advanced configuration
Lets add something to build our frontend assets. I’m going to use Yarn however you can easily amend these steps to use NPM. First we’ll need to add some new steps do our definitions object:
1 | definitions: |
Here we’ll define a step to run yarn to pull in all of our front end packages and cache them for use in our asset build steps which we’ll define next.
This is broken out into 2 separate steps one for our development builds and one for production. We’ll cache their output to be deployed to our target environment.
If we wanted to run a different set of steps for a given branch or tag we can create new keys under the “pipelines” root level item:
1 | pipelines: |
Those of us familiar with gitlab will be used to being able to run “stages” or groups of tasks in parallel. We can do that here to by putting steps under the parallel
keyword:
1 | pipelines: |
Finally if we wanted to manually trigger the running of the step we can use the trigger keyword:
1 | pipelines: |
The “php artisan deploy” command is what I use to deploy simple sites which ive written about here.
Notice the deployment keyword on the final step. Bitbucket allows us to track code changes between environments as well as link in any JIRA issue (if you happen to be using JIRA).