GitHub Actions and Drupal

GitHub Actions is a continuous integration (CI) and continuous delivery (CD) platform. In simpler terms that just means that you can automate your build, test, and deployment pipelines. GitHub has great documentation that will help you understand GitHub Actions, so there's no point in me talking about that.

Instead of talking about how it works and going into all the details, let's explore an example. Our goal is to create a workflow that will run a coding standards check on our custom Drupal module. We want to perform the check on both Drupal 8 and 9, and use both PHP 7 and 8. In total that's 4 different job configurations.

Workflow files use YAML syntax, and you must store them in the .github/workflows directory of your git repository. Let's start by defining basic information about our workflow. We need a name and we have to define which events can cause our workflow to be executed. In our case, those events are git pushes and pull requests.

name: Test
on:
  push:
    branches: [ 8.x-2.x ]
  pull_request:
    branches: [ 8.x-2.x ]

The next step is to define jobs. We have only one job -- let's call it testing. Our job will run on the latest version of Ubuntu with the matrix of different job configurations:

jobs:
  testing:
    name: Drupal ${{ matrix.drupal-core }} - PHP ${{ matrix.php-versions }}
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        drupal-core: ['9.3.x', '9.4.x']
        php-versions: ['7.4', '8.0']

A job is nothing but a set of individual steps, so the last thing we have to define are steps. We need steps for checking out Drupal core and our custom module, then setting up PHP and installing dependencies with Composer, and then the final step is to run the coding standards check:

steps:
  - name: Checkout Drupal core
    uses: actions/checkout@v2
    with:
      repository: drupal/drupal
      ref: ${{ matrix.drupal-core }}

  - name: Checkout module
    uses: actions/checkout@v2
    with:
      path: modules/commerce_product_saleprice

  - name: Setup PHP, with composer and extensions
    uses: shivammathur/setup-php@v2
    with:
      php-version: ${{ matrix.php-versions }}
      coverage: none

  - name: Get composer cache directory
    id: composercache
    run: echo "::set-output name=dir::$(composer config cache-files-dir)"

  - name: Cache composer dependencies
    uses: actions/cache@v2
    with:
      path: ${{ steps.composercache.outputs.dir }}
      key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
      restore-keys: ${{ runner.os }}-composer-

  - name: Install Drupal core dependencies
    run: |
      composer --no-interaction --no-progress --prefer-dist --optimize-autoloader install
  
  - name: Install module dependencies
    run: |
      composer --no-interaction --no-progress require \
        drupal/commerce

  - name: Install Coder module
    run: |
      composer --dev --no-interaction --no-progress require \
        drupal/coder:8.3.13

  - name: Check coding standards
    run: |
      ./vendor/bin/phpcs --config-set installed_paths vendor/drupal/coder/coder_sniffer
      ./vendor/bin/phpcs --standard=Drupal,DrupalPractice --extensions=php,module,install,js modules/commerce_product_saleprice

You can find the complete workflow file in the repository of the Commerce Product Saleprice module. To check out workflow runs go to the Actions page, where you can for example see that Test #1 failed and Test #2 completed successfully.

Image

As you can see in the screenshot above, workflows are executed very fast. It takes about 30 seconds per configuration, and all 4 configurations are executed in parallel. Caching Composer dependencies improves workflow execution time, so always use a caching action.

I'll conclude this article by saying that options are almost endless. You can add steps for static analysis check or PHPUnit tests, or something else. Now go on and configure some GitHub actions. And if you need help with anything let me know.

About the Author

Goran Nikolovski is an experienced web and AI developer skilled in Drupal, React, and React Native. He founded this website and enjoys sharing his knowledge.