Using GitHub Actions
After attending a lecture about continuous integration and testing methods at university, I decide to put what I learned into practice and try to use GitHub Actions for an Elm based project.
It’s the lecture I’ve been waiting for since the moment I heard it was announced - Testing and continuous integration. For me, continuous integration is just this buzz word that I have seen on various projects, but don’t quite understand. Nonetheless, this is all about to change.
The lecturer proceeds to fully explain what continuous integration is, what its various use cases are and includes multiple demonstrations where they set up continuous integration with Microsoft’s Azure for a basic test repository on GitHub. They add branch protection rules to prevent merging into the master branch if the current state of the branch is failing the tests (which allows you to ensure that all of the code is working as intended before code is merged). I learn that continuous integration allows you to build your code in the cloud and run tests (such as unit tests for example) to ensure your code works. The lecture ends and I go home to try it out for myself.
Using GitHub Actions
Since I don’t plan to use Microsoft’s Azure for continuous integration, I decide to use something… “closer to home” - GitHub Actions. GitHub Actions is basically GitHub’s continuous integration environment that allows you to perform cloud-based operations when certain events occur. For example, you can have GitHub automatically compile a project, run tests, enforce coding standards, apply code formatting, deploy your project to a repository, you name it. For my case, I want to create a GitHub Action that would be able to compile my code and check if it was in a suitable runnable state.
Firstly, I have to create a workflow. These are basically the steps of instructions that are executed by GitHub when an event occurs. Luckily, GitHub has a selection of pre-built workflows that allows you to set up an environment with very little effort. I search through the list of pre-built workflows and unfortunately, I am unable to find anything relating to Elm. That’s fine, Elm is a rather niche programming language and thus, it’s unlikely that GitHub would create such a workflow template. I decide to search in the GitHub Marketplace - a small repository where developers can create, share and download workflows. Unfortunately, I am unable to find anything for Elm.
So, I do what any regular developer would do, and search for it on the web. I search for something generic, such as “Elm GitHub Actions” and find a result to a GitHub repository elm-actions. Upon close inspection, I find that the repository includes a simple Dockerfile based off of an Elm environment. Although this is useful, the repository is not in fact a suitable GitHub Action. So, I begin to follow the tutorial of creating a docker container action which describes how to create a docker environment as a GitHub workflow.
After many hours, learning the bare bones of what docker is and how to create a docker container, I succeed and am able to build my Elm project! Everything is wonderful, I succeed in creating a simple GitHub workflow using GitHub Actions and as far as I am concerned, my primary task is complete.
If you’ve been following my blog closely, you can probably guess that this blog post is in fact, far from complete. I continue working on my Elm project, knowing that every push includes a lovely build report saying whether :the project compiles or fails to complete.
In the process of building this application, I discover that Elm has “Time Travel Debugging”. This basically allows you to revert changes in a program whilst in a debugging mode. For example, say I have a textbox and add some text. I could “go back in time” to a state where the textbox is empty and see how the insertion of that text affected the state of the application. Since such an idea seems completely bizarre and intriguing, I decide to try it out. I compile my Elm project using the regular
elm make command, and add the
--debug flag to enable debugging mode. However, in Elm 0.19.0, the time travelling debug mode does not work. At all.
No problem, all I have to do is upgrade to Elm 0.19.1. I install the latest version of Elm on my computer, and run
elm make. It points out various issues with my project that have changed in the new Elm specification, such as how file names must begin with a capital letter and how I have to update my
elm.json file to use version 0.19.1.
And of course, I push this to GitHub, the GitHub workflow kicks into action and… fails. It so happens that the Docker container was not compatible with Elm 0.19.1. Obviously, I do further research and find out how to upgrade the Elm environment in the docker container and eventually manage to get Elm to compile in the cloud as it did before I updated to 0.19.1. In the process of doing this, I discover that there’s an easier way to install Elm: Using the Node Package Manager! Luckily, GitHub Actions includes a pre-built template for node based projects! I create a new workflow that uses the node pre-built template and manage to shave off precious seconds from my continuous integration system.
And of course, the following message is displayed in the report:
NOTE: You can avoid npm entirely by downloading directly from: https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz All this package does is download that file and put it somewhere.
I decide to create a different GitHub workflow that simply installs Elm using the following simple commands:
curl -L -o elm.gz https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz gunzip elm.gz chmod +x elm mv elm /usr/local/bin
And that’s it! Since GitHub Actions already allows you to set up a Linux machine (Ubuntu), it includes the basic Linux commands (such as
gunzip) and surprisingly allows you to create such an environment with ease. Surprisingly, using this method as opposed to the Docker or Node Package Manager is significantly faster (About 6-7 times faster).
Making a GitHub Action
So that’s all well and good. I am now able to set up an Elm environment, except my workflow file is rather long and complicated. Having to run all of these commands one after another and having to change the entire setup when a new version of Elm comes out - it’s a hassle. I decide to create a custom GitHub Action that lets you set up an Elm environment really easily.
I follow the basic tutorials online for creating a GitHub Action, read around the subject and everything is pretty well documented, but can be a little content heavy. It’s a lot easier to create a GitHub Action than it seems, and it basically comes down to these few steps:
- Clone the template repository
- Edit the
action.ymlfile to suit your needs. Basically, set and inputs or outputs that your action needs and any other dependencies (such as node).
@action/execmethod and execute the commands in sequence.
- Publish it!
I decide to publish my Elm setup to the GitHub Marketplace so that any future developers that want to use Elm with GitHub Actions, can do so with ease.
Overall, the process was a little complicated - it was difficult to figure out exactly how I wanted to set things up (Docker, NPM, None of the above…), but after creating a GitHub Action, it makes future Elm projects a breeze to test. I was able to publish it to the GitHub Marketplace here and allow it to be version independent by allowing users to select a version of Elm when they add it to their workflow.