GitHub Actions is a powerful tool that enables developers to automate their software development workflows. In this article, we will demonstrate how to use GitHub Actions to set up and run tests on a Laravel application and then deploy the application using Laravel Forge.
Setting Up GitHub Actions
To get started with GitHub Actions, you need to create a workflow file in your Laravel project repository. This file will define the actions that GitHub will perform. Create a new directory .github/workflows
and add a new file main.yml
within it.
This file is basically a list of instructions that GitHub runs sequentially in a VM. You can then configure how and when these commands are run.
name: Laravel CI/CD
on:
push:
branches: [ master ]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
- name: Install Dependencies
run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --ignore-platform-req=ext-imagick
- name: Generate key
run: php artisan key:generate
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- name: Create Database
run: |
mkdir -p database
touch database/database.sqlite
- name: Migrate
env:
DB_CONNECTION: sqlite
DB_DATABASE: database/database.sqlite
run: php artisan migrate
- name: Cache node modules
id: cache-npm
uses: actions/cache@v3
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
name: List the state of node modules
continue-on-error: true
run: npm list
- name: Compile assets
run: |
npm install
npm run production
- name: Run tests
run: php artisan test
deploy:
needs: build-and-test
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Deploy to Forge
env:
FORGE_API_KEY: ${{ secrets.FORGE_API_KEY }}
FORGE_SERVER_ID: ${{ secrets.FORGE_SERVER_ID }}
FORGE_SITE_ID: ${{ secrets.FORGE_SITE_ID }}
run: |
curl -X POST "https://forge.laravel.com/api/v1/servers/$FORGE_SERVER_ID/sites/$FORGE_SITE_ID/deploy" \
-H "Authorization: Bearer $FORGE_API_KEY"
Let's run through exactly what we're doing here, step by step.
Job set up
Starting with the beginning of the file:
name: This sets the name of the workflow.
on: This specifies the event that triggers the workflow. In this case, the workflow will run whenever you push changes to the master
branch (change this line if you use main
).
jobs: This section contains the steps that GitHub Actions will perform.
Jobs
Now let's go through the list of jobs.
Build and test
The first job is build-and-test, which will run on an ubuntu-latest environment. This job has several steps:
Checkout repository: This step uses the actions/checkout@v2 action to check out your Laravel repository. Set up PHP: This step uses the shivammathur/setup-php@v2 action to set up PHP with the specified version and extensions.
Copy env
: This step copies the example .env
file. If you want to house some test-specific environment here you could have an .env.testing
file you copy instead, just ensure you keep any sensitive variables OUT of here.
Install dependencies: This step installs the Laravel project dependencies using Composer.
Generate key: Laravel needs a key to run, so we generate it using it a command here.
Directory permissions: The storage and bootstrap cache folders need to be writable for most apps to function, so lets set that up.
Create database: Most apps need a database. The easiest way to do this is using SQLite, so that's what we're setting up here.
Migrate: Create database schema by migrating.
Cache node_modules: This is an optional step, but here we are going to cache the output of npm install
. We've actually written a dedicated article on this step so we won't go into too much detail here: Caching npm install
for faster build times on GitHub Actions.
Compile assets: Build our assets using npm run build
or npm run production
. Most Laravel apps will have tests that involve loading a frontend, so this step is essential.
Run tests: This step runs the Laravel tests using the php artisan test command.
Deploy
The second task is to deploy. To deploy here we're using Laravel Forge's API.
We've opted to use the API as it allows you to extend the GitHub Action to do more than simply deploy if you wanted to. There's a much easier way to deploy using Laravel Forge than use the API, and that's to use the deployment webhook for your environment. Simply go to the environment in Forge, find the webhook URL and then make a cURL request to it in your Action:
- name: Deploy to Laravel Forge
run: curl ${{ secrets.FORGE_DEPLOYMENT_WEBHOOK }}
You'll notice the use of ${{ secrets }}
variable throughout here. You don't want to store anything sensitive in your repo, and that includes in your GitHub workflow file, so GitHub has a secret vault for you to use.
Anyway, back to the Forge API, here we're doing a couple of things. First off, we set a bunch of environment variables from the GitHub secrets vault:
env:
FORGE_API_KEY: ${{ secrets.FORGE_API_KEY }}
FORGE_SERVER_ID: ${{ secrets.FORGE_SERVER_ID }}
FORGE_SITE_ID: ${{ secrets.FORGE_SITE_ID }}
and then we run a cURL request to the API endpoint:
run: |
curl -X POST "https://forge.laravel.com/api/v1/servers/$FORGE_SERVER_ID/sites/$FORGE_SITE_ID/deploy" \
-H "Authorization: Bearer $FORGE_API_KEY"
This is pretty straightforward, it just makes a POST request to the deployment endpoint.
Adding GitHub secrets
Before any of this works you'll need to configure GitHub secrets:
-
FORGE_API_KEY
: Your Forge API key, which can be obtained from the Forge dashboard. -
FORGE_SERVER_ID
: The ID of the server you created in Forge. -
FORGE_SITE_ID
: The ID of the site you created in Forge.
To add GitHub secrets navigate to the "Settings" tab of your GitHub repository, click on "Secrets" in the left sidebar, and then click on the "New repository secret" button.
Testing it all
Once everything is configured simply commit and push a change to your master
(or main
) branch and then load the Actions page of your repo in your browser. This is usually found at:
https://github.com/[your username]/[your repo]/actions
Just navigate to your repo URL and click the Actions tab at the top.
You'll be able to watch as the Action runs and each step is running. In our experience a full Laravel build, configuration and run of a small test suite takes about 2 minutes, but most of that is spent configuring the underlying VM and building your assets, so the actual time spent running will differ greatly depending on whether you're using Vite or Webpack, and the amount of assets or frontend components you're building. And, of course, the number of tests in your test suite.
Interested in proving your knowledge of this topic? Take the PHP Fundamentals certification.
PHP Fundamentals
Covering the required knowledge to create and build web applications in PHP.
$99
Related articles
Tutorials PHP Sysadmin Tooling
How To Set Up Laravel, Nginx, and MySQL With Docker Compose on Ubuntu 20.04
Learn to set up a Laravel application with Nginx and MySQL using Docker Compose on Ubuntu 20.04. This guide provides a step-by-step approach to containerize your Laravel application.