tuutti.iki.fi

Using GitHub Actions to test a Drupal contrib module

#automation #github-actions

See tuutti/github-actions-drupal-module for a complete example.

Setting up

You can either run your tests in a container, or use something like shivammathur/setup-php to set up Actions environment.

Running tests in a container

# .github/workflows/test.yml
on: [push]
name: Tests
env:
  SIMPLETEST_DB: "mysql://drupal:drupal@mariadb:3306/drupal"
  SIMPLETEST_BASE_URL: "http://127.0.0.1:8080"
  DRUPAL_MODULE_NAME: "github_actions_example"
  DRUPAL_CORE_VERSION: 9.4.x
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: true
      matrix:
        php-version: ['8.0', '8.1']
    container:
      # See https://github.com/tuutti/docker-images/tree/main/drupal/ci
      # to see how this image is built.
      image: ghcr.io/tuutti/drupal-php-docker:${{ matrix.php-version }}

    services:
      mariadb:
        image: mariadb:10.9
        env:
          MYSQL_USER: drupal
          MYSQL_PASSWORD: drupal
          MYSQL_DATABASE: drupal
          MYSQL_ROOT_PASSWORD: drupal
        ports:
          - 3306:3306
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 1

      # The next two steps exposes $DRUPAL_ROOT and $MODULE_FOLDER environment
      # variables.
      #
      # They have to be set in separate steps because $DRUPAL_ROOT variable
      # won't be accessible in currently active step.
      # You can access them either with $DRUPAL_ROOT and $MODULE_FOLDER or
      # ${{ env.DRUPAL_ROOT }} and ${{ env.MODULE_FOLDER }}.
      - name: Define DRUPAL_ROOT env variable
        run: echo "DRUPAL_ROOT=$HOME/drupal" >> $GITHUB_ENV

      # Change the module folder according to your needs, it's probably either
      # modules/contrib/$DRUPAL_MODULE_NAME or modules/custom/$DRUPAL_MODULE_NAME.
      - name: Set module folder
        run: |
          echo "MODULE_FOLDER=$DRUPAL_ROOT/modules/contrib/$DRUPAL_MODULE_NAME" \
            >> $GITHUB_ENV

      # Clone Drupal core into $DRUPAL_ROOT folder.
      # Core version can be set by changing $DRUPAL_CORE_VERSION.
      - name: Clone drupal
        run: |
          git clone --depth 1 --branch "$DRUPAL_CORE_VERSION" \
            http://git.drupal.org/project/drupal.git/ $DRUPAL_ROOT

      # Override the platform.php config with currently active PHP version.
      # As of writing this, the composer.json shipped with core sets
      # platform.php version to 7.3.0, meaning we possibly get dependencies
      # that won't work with php 8+.
      - name: Override the platform.php version
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: composer config platform.php ${{ matrix.php-version }}

      # Set the module folder as a composer repository, so the latest code
      # is symlinked from $GITHUB_WORKSPACE to modules/ folder.
      - name: Install the module
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          composer config repositories.0 path $GITHUB_WORKSPACE
          composer require drupal/$DRUPAL_MODULE_NAME

      # PHP 8+ requires newer phpunit, use core's composer script
      # to upgrade it.
      - name: Upgrade phpunit
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: composer run-script drupal-phpunit-upgrade

      # We use drush's build-in webserver to run tests. Make sure
      # Drush is installed.
      - name: Install drush
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: composer require "drush/drush ^11.0"

      - name: Install PHPCS
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          composer config --no-plugins \
            allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
          composer require --dev "drupal/coder"

      # Install Drupal using minimal installation profile and enable the module.
      - name: Install Drupal
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          php -d sendmail_path=$(which true); vendor/bin/drush --yes -v \
            site-install minimal --db-url="$SIMPLETEST_DB"
          vendor/bin/drush en $DRUPAL_MODULE_NAME -y

      - name: Run PHPCS
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          vendor/bin/phpcs $MODULE_FOLDER --standard=Drupal \
            --extensions=php,module,inc,install,test,info

      - name: Start Drush webserver and chromedriver
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          vendor/bin/drush runserver $SIMPLETEST_BASE_URL > /dev/null 2>&1 &
          chromedriver --port=4444 > /dev/null 2>&1 &
          # Wait for drush server to start.
          for i in {1..5}; do \
            RESPONSE_CODE=$(curl -s -o /dev/null \
            -w "%{http_code}" "$SIMPLETEST_BASE_URL" || true); \
            if [ "$RESPONSE_CODE" -gt "301" ] || [ "$RESPONSE_CODE" -lt "200" ]; \
            then sleep 2; fi; done

      # Chromium browser is required to run functional javascript tests.
      # You can remove or uncomment this step if you don't have any functional
      # js tests.
      - name: Start chromium-browser
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          chromium-browser --headless --disable-gpu \
            --no-sandbox \
            --remote-debugging-port=9222 &

      # Run tests using core's run-tests.sh script. See the example below
      # to run tests using phpunit.
      - name: Run tests
        working-directory: ${{ env.DRUPAL_ROOT }}
        run: |
          php ./core/scripts/run-tests.sh --dburl $SIMPLETEST_DB \
            --php /usr/local/bin/php --color --verbose \
            --sqlite /tmp/test.sqlite \
            --url $SIMPLETEST_BASE_URL $DRUPAL_MODULE_NAME

      # Uncomment this step to run tests using phpunit. Your module is expected
      # to ship with 'phpunit.xml' file. See the repository for an example
      # phpunit.xml file.
      #- name: Run tests
      #  working-directory: ${{ env.DRUPAL_ROOT }}
      #  run: |
      #    vendor/bin/phpunit --bootstrap $DRUPAL_ROOT/core/tests/bootstrap.php \
      #      -c $MODULE_FOLDER/phpunit.xml $MODULE_FOLDER

Running tests using shivammathur/setup-php action

You can use the same workflow as above just by replacing the container section with:

      - name: Setup PHP with composer v2
        uses: shivammathur/setup-php@v2
        with:
          php-version: '${{ matrix.php-version }}'
          tools: composer:v2

and changing SIMPLETEST_DB host from mariadb to 127.0.0.1.

Full diff:

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 171f5ae..8395381 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,7 +1,7 @@
 on: [push]
 name: CI
 env:
-  SIMPLETEST_DB: "mysql://drupal:drupal@mariadb:3306/drupal"
+  SIMPLETEST_DB: "mysql://drupal:drupal@127.0.0.1:3306/drupal"
   SIMPLETEST_BASE_URL: "http://127.0.0.1:8080"
   DRUPAL_MODULE_NAME: "github_actions_example"
   DRUPAL_CORE_VERSION: 9.4.x
@@ -12,11 +12,6 @@ jobs:
       fail-fast: true
       matrix:
         php-version: ['8.0', '8.1']
-    container:
-      # See https://github.com/tuutti/docker-images/tree/main/drupal/ci
-      # to see how this image is built.
-      image: ghcr.io/tuutti/drupal-php-docker:${{ matrix.php-version }}
-
     services:
       mariadb:
         image: mariadb:10.9
@@ -32,6 +27,12 @@ jobs:
         with:
           fetch-depth: 1

+      - name: Setup PHP with composer v2
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: '${{ matrix.php-version }}'
+          tools: composer:v2

See .github/workflows/setup-php.yml.