If you've written a Deno 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 repository to store your code then you are in luck! You can use GitHub Actions to automate all of your CI/CD needs for your GitHub project π
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:
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 π
name: Test Deno Module
First we add a 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.
on:
push:
branches: [main]
pull_request:
branches: [main]
Next we set the 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:
on: push
Or if you wanted it to trigger on every push and pull request no matter what branch is used, you could do:
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:
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 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 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 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.
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.
Here we define a list of steps, each with an optional name to make it clear what the step does, and then some other keys to provide instructions on what to run in that step:
First we use the official
actions/checkout@v2action for performing agit checkoutof our git repository onto the GitHub Action build server so we are able to test our module. This is defined using theusesparameter.-
Next we use the
denolib/setup-deno@v2action to install and configure Deno on the GitHub Action build server.Here we also use the additional
withproperty to specify the variabledeno-version, which thesetup-denoaction 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 and it will evaluate to the value inside the double curly braces, in this case, thedeno-versionwhich is taken from thematrixlist we provided earlier. -
Finally we define three more steps: one to lint, one to build and one to test our Deno module. Here we use the
runproperty which allows us to run any command we like using the build server's shell.For linting we use the
deno fmt --checkcommand 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 thedeno fmtcommand (without any flags).For building our module we run
deno run --reload mod.ts, wheremod.tsis the main entypoint / starting point of our code (change the file depending on your repository setup). Here we are using the--reloadflag 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-nonecommand which will run all tests available in your repository. The--allow-noneflag 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! π π
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.
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!
Top comments (1)
Thanks for the detailed writeup! I didn't know about the version matrix option, might use it in the future.
With two years passed since this post, some parts here are oudated:
actions/checkout@v2, now has a new v3 versiondenolib/setup-deno@v2has moved to denoland/setup-deno@v1Deno also has official docs now for setting up a Github worfklow.
I also believe the
deno run --reloadstep is both unnecessary and outdated. Unnecessary, because by default Github Action runners don't cache dependencies. And outdated, because if you would want to cache deps across runner sections, you should useactions/cacheas described in the Deno docs. Also,deno cache --reloadseems preferable here over thedeno run --reloadcommand. By usingrun, you run your actual code in preparation of running tests, which might not be desirable (in my case, my code runs a server).With those changes, I got the following single-version workflow for my project, without cache reloading: