GitHub Actions With Deno
Tags: deno, github, tutorial, devops
Published: 2020-05-28 18:22:08

If you've written a [Deno](https://deno.land/) module recently, you most likely will want to ensure that you can lint, test and build it in an automated process!

If you are using a public [GitHub](https://github.com/) repository to store your code then you are in luck! You can use [GitHub Actions](https://github.com/features/actions) to automate all of your CI/CD needs for your GitHub project :tada:

# Getting started

In your project add the following directory structure and files:

```
.
├── .github/
│    └── workflows/
│        └── test.yml
│
... // other folders and files
```

A `.github` directory in the root of your project containing a `workflows` directory, and finally a `test.yml` files in the `workflows` directory.

This `test.yml` file will contain all of the instructions for our GitHub Action for testing Deno.

# The test file

Add the following to your `test.yml` file:

```yaml
name: Test Deno Module

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        deno-version: [1.2.2, 1.3.0]

    steps:
      - name: Git Checkout Deno Module
        uses: actions/checkout@v2
      - name: Use Deno Version ${{ matrix.deno-version }}
        uses: denolib/setup-deno@v2
        with:
          deno-version: ${{ matrix.deno-version }}
      - name: Lint Deno Module
        run: deno fmt --check
      - name: Build Deno Module
        run: deno run --reload mod.ts
      - name: Test Deno Module
        run: deno test --allow-none
```

There's a lot going on here! So let's break it down :smile:

```yaml
name: Test Deno Module
```

First we add a [`name`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#name) property to the `test.yml` file. You can change this to something relevant to your module. GitHub displays this as the name of your workflow on your repository's actions page.

```yaml
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
```

Next we set the [`on`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#on) property to define what triggers we would like to automatically start our action's workflow. For this example we have opted to trigger this workflow whenever a `git push` is made to the `main` branch, and also whenever there is a Pull Request that wishes to merge changes into the `main` branch.

If instead you wanted the action to trigger on every push no matter what branch is used, you could do something like:

```yaml
on: push
```

Or if you wanted it to trigger on every push and pull request no matter what branch is used, you could do:

```yaml
on: [push, pull_request]
```

You can also specify multiple branches, or a different branch to the `main` branch.

Finally we define the main part of our GitHub Action workflow, the `jobs` section:

```yaml
jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        deno-version: [1.2.2, 1.3.0]

    // ... remainder of workflow file
```

Here we define the a [`jobs`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobs) property and add a single job called `test`. This job is what we will be using to run our lint, test and build.

In the `test` object we define a [`runs-on`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on) property which let's GitHub know what machine OS we want to use, in this case `ubuntu-latest`, but there is also `windows-latest`, `macos-latest` and others to choose from.

Next we define a [`strategy`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategy) object which allows us to define a list of Deno versions that we want this workflow to run against. Each of the subsequent steps are executed for each value in the provided array, in this example we have chosen to test against some of the version 1.x.x releases of Deno.

```yaml
    steps:
      - name: Git Checkout Deno Module
        uses: actions/checkout@v2
      - name: Use Deno Version ${{ matrix.deno-version }}
        uses: denolib/setup-deno@v2
        with:
          deno-version: ${{ matrix.deno-version }}
      - name: Lint Deno Module
        run: deno fmt --check
      - name: Build Deno Module
        run: deno run --reload mod.ts
      - name: Test Deno Module
        run: deno test --allow-none
```

Lastly we define our job's [`steps`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsteps).

Here we define a list of steps, each with an optional [`name`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsname) to make it clear what the step does, and then some other keys to provide instructions on what to run in that step:

1. First we use the official [`actions/checkout@v2`](https://github.com/marketplace/actions/checkout) action for performing a `git checkout` of our git repository onto the GitHub Action build server so we are able to test our module. This is defined using the [`uses`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses) parameter.

2. Next we use the [`denolib/setup-deno@v2`](https://github.com/marketplace/actions/setup-deno-environment) action to install and configure Deno on the GitHub Action build server.

    Here we also use the additional [`with`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepswith) property to specify the variable `deno-version`, which the `setup-deno` action requires in order to know what version of Deno to install.

    Notice here we are using a special syntax `${{ matrix.deno-version }}`. This is called an [expression](https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#about-contexts-and-expressions) and it will evaluate to the value inside the double curly braces, in this case, the `deno-version` which is taken from the `matrix` list we provided earlier.

3. Finally we define three more steps: one to lint, one to build and one to test our Deno module. Here we use the [`run`](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsrun) property which allows us to run any command we like using the build server's shell.

    For linting we use the `deno fmt --check` command and flag which will check if our code is properly formatted, and exit with an error if not. If this errors, you can fix your Deno module's code formatting by running the `deno fmt` command (without any flags).

    For building our module we run `deno run --reload mod.ts`, where `mod.ts` is the main entypoint / starting point of our code (change the file depending on your repository setup). Here we are using the `--reload` flag to ensure that we fully rebuild the module and all of it's third party modules. This is to make sure that we don't accidentally rely on a cached version of the module or any third party dependencies, as this would give us a false impression of whether the module will build properly on a new module user's computer.

    For testing we use the `deno test --allow-none` command which will run all tests available in your repository. The `--allow-none` flag means that the command won't fail if your repository doesn't have any tests. If you want the test to fail if it can't find any tests, just remove the flag.

If any of the above steps fail the GitHub Action workflow will report the failure with the logs messages.

And that's it! :tada: :tada:

This workflow will work with any Deno project straight away so long as it uses the `main` branch as it's main branch. All you need to do is copy the `test.yml` file to the correct place in your repository and `git push` the code to GitHub.

You can then check your actions using the `Actions` page on your GitHub repo, and every Pull Request into the `main` branch and every commit to `main` will get a status check tick or cross depending on success or failure.

If you want to find out more about GitHub Actions, check out their [Workflow Syntax Docs](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions).

That's it peeps! Would love to hear your thoughts and how you're getting on with Deno and if you've done anything cool with GitHub Actions - drop your comments and questions below!