Laravel application with Bitbucket Pipelines

Article header
Article header

Currently, there are multiple services for continuous integration and continuous deployment (CI&CD). Though, if you use Atlassian products, you might have heard about the Bitbucket service called Pipelines. It enables continuous delivery in Bitbucket Cloud repositories for projects using any programming languages, such as Java, Node.js, PHP, Python, Ruby, etc.

Documentation of the service describes various cases. This is a universal technology. However, if you are working on a specific solution, it will require more efforts.

To better understand how Bitbucket Pipelines works for Laravel, let’s focus on an example situation. So, we have:

  • An application written with Laravel;
  • Tests that should be launched for every Push;
  • Remote server with SSH access, where the application is deployed to.

And the work begins!

Enable Pipelines

Go to your repository settings and tick “Enable Pipelines”.

This will work only if you are an admin in your repository. If not - contact your admin and request enabling Pipelines. You won’t need admin access rights for any further actions.

Bitbucket-pipelines.yml

The admin panel will immediately suggest you to create a bitbucket-pipelines.yml file. You can agree, or create the file in the root of the project and add it to the next commit.

According to its extension, the file will have YML syntax. So, you might want to enable support of it in your code editor or IDE.

Your YML file should look like this:

pipelines:

default:

  - step:

      script:

        - echo "It's Clockwise, baby!"

Usually, it also includes a link to an container image the commands will be executed in, and a set of operations, bash commands, which should be executed in this container.

As soon as you make push in the repository, Pipelines will launch. According to our mentioned example, it will display the phrase “It’s Clockwise, baby!”.

In the repository in Pipelines section you will see something like this:

After that, every push will initiate execution of commands from this file.

Getting closer to PHP

To work with PHP, we have to add image: directive with the required value to our pipelines. Since we are talking about a Laravel project, we’ll need a PHP Docker image. The documentation suggests using the basic official image. The configuration file will look as follows:

image: php:7.1.1

pipelines:

default:

  - step:

      script:

        - php -v

However, this is still not enough.

The project will also require you to install a variety of PHP modules and composer packages including Laravel itself. Further, there will be several options:

  • Describe bitbucket-pipelines.yml to include all needed dependencies;
  • Create a custom image including all required components and reuse it;
  • Search Docker Hub for the appropriate image.

Docker image

For our example project we create a custom image. It includes the needed dependencies and uses different systems and different PHP variations, depending on the tag. This image can be used for development or production environment (php-fpm), as well as with various CI&CD systems (cli).

Now, we can launch commands in the container which includes the whole code of our repository. This is how the bitbucket-pipelines.yml file looks like:

image: clockwise/docker-phpunit-alpain:master

pipelines:

default:

  - step:

      caches:

        - composer

      script:

        - composer --version

        # install composer vendor scripts

        - composer install

        - vendor/bin/phpunit --version

        # generate key

        - cp .env.example .env

        - php artisan key:generate

        # do not migrate - it's happens in test environment setup

        # - php artisan migrate --seed --database=sqlite

        # run tests

        - vendor/bin/phpunit

The overall concept is quite simple. However, the key points need some deeper explanation.

In the first string, directive image: refers to container image, which will be used for all further operations. We also use tag: master which derives from master branch of the repository, including alpine version of the official php repository from Docker Hub.

The general pipelines behavior for each of the repository branches is as follows:

  • caches: describes one of the new Bitbucket Pipelines features. It enables caching the deployment of the vendor part of the project, which results in faster deployment in pipelines.
  • script: includes the list of commands to be executed. It resembles deployment of the project, which was just cloned from the repository.
  • composer --version ensures that the container includes a composer and displays its version.
  • composer install installs all the vendor dependencies;
  • vendor/bin/phpunit --version checks the availability of phpunit in the vendor directory;
  • cp .env.example .env copies the default environment config;
  • php artisan key:generate generates the application key;
  • php artisan migrate --seed --database=sqlite - this command is commented in the example configuration, since we are using SQLite in Memory for the project. If you use SQLite database for testing, this command is required;
  • vendor/bin/phpunit - the command that runs the tests.

If one of the tests fails, you will be notified via email. The repository history will display a red exclamation mark for your commit.

The pipelines history will highlight the failed build. You will see the full conclusion, as if you were running a test in your console.

If one of the commands fails during the execution, the process will stop on the command that couldn’t be executed successfully.

Enabling in-memory SQLite in a Laravel application

SQLite doesn’t require creating an extra file to store the database. Instead, you can store it directly in the system memory, which is extremely handy for testing. To enable this, you will have to modify the Laravel application.

Start with modifying the config/database.php file by extending the connections section with the following strings:

'sqlite_memory' => [

  'driver' => 'sqlite',

  'database' => ':memory:',

  'prefix' => '',

]

This enables using sqlite_memory as a database connection parameter.

Also, you will have to update the phpunit.xml file, responsible for default PHPUnit configuration, in the root of your application. Add the following:

<env name="DB_CONNECTION" value="sqlite_memory"/>

The last, but not least. The application should apply migrations and seeds on the database. So, you’ll have to update the tests/CreateApplication.php file by adding setUp method redefinition:

public function setUp()

{

  parent::setUp();

  \Artisan::call('migrate');

  \Artisan::call('db:seed');

}

These simple actions enable you to add or remove files from SQLite database without any issues.

One more thing

The commands will be executed for every push in the repository. In addition, the same will happen for pull-requests as well. This is very helpful for the whole team, however, with a single condition: you should cover your own code with tests.

 

Liked this article? Sign up to be notified of new blog posts.

You might also like

Discovering main web app vulnerabilities with manual and automated security testing

Overview of map services that bring the whole world to the smartphone screen

Top JavaScript frameworks for cross-platform development. Who is the leader?

Manual or automated? Which type of security testing enables finding more vulnerabilities? Forget this either-or question. It is all about finding the balance. Let's dig deeper into the capabilities of manual and automated security testing!
Paper maps are not in trend anymore. All we need is already on our smartphone. A variety of map services enable software developers to create multi-functional applications. In our new article, we take a closer look at the most popular of them. Some use cases are also reviewed!
There are tens of frameworks for cross-platform app development. The choice is hard. However, our comprehensive market review enabled us to discover the true leaders. Read about the frameworks that promise you top performance coupled wit native-like experience

Discovering main web app vulnerabilities with manual and automated security testing

Manual or automated? Which type of security testing enables finding more vulnerabilities? Forget this either-or question. It is all about finding the balance. Let's dig deeper into the capabilities of manual and automated security testing!

Overview of map services that bring the whole world to the smartphone screen

Paper maps are not in trend anymore. All we need is already on our smartphone. A variety of map services enable software developers to create multi-functional applications. In our new article, we take a closer look at the most popular of them. Some use cases are also reviewed!

Top JavaScript frameworks for cross-platform development. Who is the leader?

There are tens of frameworks for cross-platform app development. The choice is hard. However, our comprehensive market review enabled us to discover the true leaders. Read about the frameworks that promise you top performance coupled wit native-like experience