GitHub Actions and D

For several years I used Travis CI and AppVeyor for running integration tests of my projects, and recently decided to switch to Actions — cloud-based CI/CD service integrated into GitHub. Actions has many industry-standard features such as matrix builds, containers and artifacts. It provides great platform support including Linux, macOS and Windows. And, most importantly, Actions is fully free for public projects.

Actions supports popular languages, so if you use JavaScript, C#, Python or Java you can set it up quickly using one of the predefined workflow templates. However, until recently D support was nonexistent, and setting up a workflow for a D project was tricky. For example, I used Snap to install DMD. Fortunately, now there is a community-supported starter workflow for D that works right out of the box!

By going to “Actions” section of your repository page, you can create .github/workflows/d.yml which will look like this (comments omitted, setup-dlang version may change):

name: D
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dlang-community/setup-dlang@v1
- name: 'Build & Test'
run: |
dub build
dub test

Now each time someone pushes changes or makes a PR, GitHub checks out corresponding revision and runs a test build using default D compiler, DMD. This can be enough for a very simple project.

First thing you’ll probably want to change is to limit workflow runs by only commits for some files and directories. Usually there’s no need to run tests when README file is changed, for example. This can be done by adding a paths option to push event:

on: 
push:
paths:
- 'src/*'
- 'dub.json'
- '.github/workflows/*'

Next is job matrix. A matrix in CI is a way to run multiple parallel builds. It is like a multi-dimensional spreadsheet: you can define several platforms, CPU architectures and compilers, and CI system will run a build job for each of their combinations. For D projects matrix builds are important, because there are at least two mainstream compilers (DMD and LDC), and applications usually expected to target Windows, Linux and macOS. An updated jobs section looks as follows:

jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
dc: [dmd-latest, ldc-latest, dmd-2.094.2, ldc-1.24.0]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: dlang-community/setup-dlang@v1
with:
compiler: ${{ matrix.dc }}
- name: 'Build & Test'
run: |
dub build
dub test

In this example I’m using latest two releases of DMD and LDC under Ubuntu and Windows Server.

After the build is successfully finished, you can, for example, collect test coverage analysis data using Codecov (don’t forget to build in unittest-cov mode):

- name: 'Build & Test'
run: |
dub build
dub test --build=unittest-cov
- name: 'Run code coverage'
if: success()
run: |
curl https://codecov.io/bash > codecov.sh
bash codecov.sh

Full documentation on GitHub Actions can be found here.

You can learn YAML syntax here.

Hope the article was helpful. Happy testing!

3D game engine developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store