Continuous integration(CI) for laravel using github actions

php laravel github

Github provides continuous integration(CI) build pipelines using their service called github actions.

Github actions CI builds are called workflows, and a workflow can be triggered when a certain event happens on your github repository.

Events like a commit is made, a pull request is opened, etc will trigger workflow runs on github actions.

If you are working with a team of developers, Github actions can help you validate the pull requests by running required test cases against a pull request, So we can confidently merge a pull request when it is opened and all the test cases are passed.

Github actions provides unlimited build minutes for public repositories. For private repositories, The free account gives us 2000 build minutes/month. For a solo developer, This is more than enough.

Laravel CI generally consists of various steps to make sure the application runs smoothly when it goes to production. We will create a github actions workflow to perform the following tasks when a pull request is opened.

Once the above tasks are successfully executed without any issues, Then we can confidently merge the pull request if the code changes looks good.

Create Workflow File For Laravel

All the workflow files should reside inside .github/workflows directory inside your project root.

So first, Create these two directories.

1mkdir .github && mkdir .github/workflows

Workflow files uses yaml syntax to define the tasks. A single workflow file can contain multiple tasks.

Let's create our workflow file inside .github/workflows directory. I am going to call this file laravel-ci.yml. You can use any file name you want. Just make sure the file extension is .yml or .yaml.

1touch .github/workflows/laravel-ci.yml

Open the file in your favourite code editor and add the following code in it.

1name: Laravel CI
2
3on:
4 pull_request:
5 branches: [ master, staging ]
6
7jobs:
8 laravel-tests:
9
10 runs-on: ubuntu-latest
11
12 steps:
13 - uses: actions/checkout@v2

The above file provides a basic skeleton for our github actions laravel ci build. It is configured to run the workflow on the latest version of ubuntu operating system when a pull request is opened against master or staging branches.

Our workflow is currently not running any tasks. So let's start by adding some tasks to this workflow.

1. Setup PHP(Optional)

The ubuntu-latest image comes with the latest version of php installed already. If your application requires php version of 7.3 and lower, Add the below code to steps section in your workflow file to switch to the php version your application is using.

1- name: Setup PHP
2 uses: shivammathur/setup-php@v2
3 with:
4 php-version: 7.2 # Change to the php version your application is using
5 extensions: mbstring, bcmath # Install any required php extensions

2. Create .env file

Every laravel application should have a .env file in it to manage its environment variables. The first task we run on our workflow is copying .env.example file to .env.

Update the steps section in the workflow file with below

1- name: Copy .env.example to .env
2 run: php -r "file_exists('.env') || copy('.env.example', '.env');"

3. Install composer dependencies

The next step is installing composer dependencies. By testing the installation of composer dependencies, We are making sure there are no broken packages in the pull request.

1- name: Install composer dependencies
2 run: composer install

4. Set our directory permissions correctly

Laravel requires certain directories to be writable by the web server. We can set these directory permissions to 777 as this is just a CI server.

You should never set directory permissions to 777 in your actual server. Setting this might result in unauthorized access to restricted files.

1- name: Set required directory permissions
2 run: chmod -R 777 storage bootstrap/cache

5. Generate application encryption key

Since we are creating our .env file freshly, It will not have an encryption key. So let's create and set an encryption key.

1- name: Generate encryption key
2 run: php artisan key:generate

6. Create temporary database

In the next steps, We are going to run database migrations and unit tests. We need a temporary database to run these tasks. We can create a temporary sqlite database by adding the following task.

1- name: Create temporary sqlite database
2 run: |
3 mkdir -p database
4 touch database/database.sqlite

7. Run database migrations

We can run database migrations on the temporary database we created. Doing so we can make sure that the new and existing migration files still work and makes necessary schema changes.

Before we run the migrations, We need to set our DB_CONNECTION and DB_DATABASE environment variables to the newly created temporary sqlite database. We can set these environment variables using the env command as shown below.

1- name: Run laravel database migrations
2 env:
3 DB_CONNECTION: sqlite
4 DB_DATABASE: database/database.sqlite
5 run: php artisan migrate --force

8. Install NPM Dependencies

The next step is installing node dependencies. By testing the installation of npm dependencies, We are making sure there are no broken npm packages in the pull request.

1- name: Install NPM dependencies
2 run: npm install

9. Minify CSS and JS files

We can run npm run prod command to test and make sure our frontend build command works as expected and minifies our css and js files.

1- name: Minify CSS and JS files
2 run: npm run prod

10. Run Unit tests

Finally, Our application is completely ready with all the necessary composer and node packages installed. It has a temporary database, env file, and the frontend assets are compiled and minified.

Now we can dive into running our unit tests to make sure the new code changes did not break existing functionality.

1- name: Run unit tests via PHPUnit
2 env:
3 DB_CONNECTION: sqlite
4 DB_DATABASE: database/database.sqlite
5 run: ./vendor/bin/phpunit

Completed workflow file

If you follow all the steps correctly, Your completed workflow file should look like below.

1name: Laravel CI
2
3on:
4 pull_request:
5 branches: [ master, staging ]
6
7jobs:
8 laravel-tests:
9
10 runs-on: ubuntu-latest
11
12 steps:
13 - uses: actions/checkout@v2
14 - name: Copy .env.example to .env
15 run: php -r "file_exists('.env') || copy('.env.example', '.env');"
16 - name: Install composer dependencies
17 run: composer install
18 - name: Set required directory permissions
19 run: chmod -R 777 storage bootstrap/cache
20 - name: Generate encryption key
21 run: php artisan key:generate
22 - name: Create temporary sqlite database
23 run: |
24 mkdir -p database
25 touch database/database.sqlite
26 - name: Run laravel database migrations
27 env:
28 DB_CONNECTION: sqlite
29 DB_DATABASE: database/database.sqlite
30 run: php artisan migrate --force
31 - name: Install NPM dependencies
32 run: npm install
33 - name: Minify CSS and JS files
34 run: npm run prod
35 - name: Run unit tests via PHPUnit
36 env:
37 DB_CONNECTION: sqlite
38 DB_DATABASE: database/database.sqlite
39 run: ./vendor/bin/phpunit

After you commit the above file to your github repository, Github will run the said tasks when ever a new pull request is opened against master and staging branches.

Failure / Success status of the workflow run will be displayed on the pull request on which it ran.

You can view all the workflow runs triggered in a specific repository by clicking on the actions tab in the navigation menu of a repository page.

For daily laravel tips and interesting finds, Follow me on X