Trying out GitHub Actions (Beta)
Github is developing a new workflow automation feature called Actions. This allows you to run a sequence of operations in response to an event occurring on Github. Whilst the CI/CD features are the main selling point, I actually find some of the other potential use cases more interesting. Just to note, I’ve gotten access to Github Actions limited public beta, so the details of this post could potentially be out of date when the feature becomes generally available on November 13th. With that disclaimer out of the way, let’s dive in!
The main benefit Github Actions brings over existing CI and automation systems is its simplicity. It doesn’t offer any incredibly novel features, just a good UX that takes full advantage of being built directly into the Github platform. Whilst you could make any automation you wanted using Jenkins or Github App integrations, the principle of least resistance means Actions could become a very popular option in the future. Why go to the effort of setting up a separate automation platform when you could just use what Github provides you directly?
As each workflow is entirely source code based and tracked in git, it makes it very easy to collaborate on and reuse pre-existing actions. If there’s no existing action that does what you need, it’s only a small bit of yaml and maybe a Dockerfile away from being created. Before we get to that though, I should clarify some of the terminology I’ll be using in the rest of the post:
- Tasks: A task is a single command or operation, and it’s the smallest building block used by Actions. Examples could be
npm test
or./deploy.sh
. - Actions: Each action is a yaml file defining a series of tasks and the environment to run them in. They’re a higher-level concept than tasks and the smallest portable building block of a workflow. Examples could be
maven verify
ornotify slack on build failure
. - Workflows: These are the highest-level concept in Github Actions. Each workflow is a yaml file that specifies what actions to run and when (on commit, on PR merge to master etc.).
In most cases, a project will define its workflows and these will re-use shared actions. The workflow file would look something like:
name: Test changes
on: [push] # on what events should this action be triggered
jobs: # stages inside the workflow,
unit-tests:
runs-on: ubuntu-latest
steps: # the list of actions your workflow runs and their configuration
- uses: actions/checkout@v1 # checks out the commit that triggered this run
- uses: actions/npm@master # uses the Github Action's NPM action
args: test # and configures it to run the test command
If you wanted to run a custom action, you’d create a folder for the action (e.g. .github/actions/your-custom-action
). This would contain a yaml file, describing the action, potentially as simple as this:
name: My custom action
description: Runs our custom Docker container as an action
runs:
using: 'docker' # It can run in either Docker or a JavaScript environment
image: 'Dockerfile'
The action.yaml
in this example would have a Dockerfile in the same directory, which installs and runs whatever we want. The process’ exit code is then used to determine whether the action passed or failed. To run it as part of your workflow, all you’d need to include in the workflow file is - uses ./.github/actions/your-custom-action
.
That example probably covers the majority of use cases, which shows how little is involved in setting up in Github Actions. Of course, there’s a lot more configuration available that I didn’t cover, such as sequential stages and matrix builds, but the docs detail everything I’ve skipped over.
I said at the start that the CI/CD features weren’t the most exciting possible use-cases, and I stand by that statement. I think the potential of easily setting up other kinds of automation will result in a lot more innovation. Things that previously weren’t worth the effort of setting up are now just a few minutes work. As an example, have you ever been annoyed at having to manually delete the branch after merging a PR[1]? Since Actions can easily provide a Github API token, it’d be fairly trivial to set up a workflow that sends a delete request for the branch on PR merge. Another use case I’ve actually set up is an action that diffs the built version of this blog against the previous version on every change, and comments the result back to Github[2]. It allows me simply to see what effects a change has, without having to open my browser and try compare the 2 sites. It’s nothing groundbreaking, just a nice quality of life improvement that simplifies my workflow. It’s in small automations like this, that become feasible to implement thanks to Actions, where I think we’ll see the real value-add of the feature.
[1] - There’s now a setting to automatically delete the head branch of a pull request once it has merged, but if Github Actions was released before this change I think it’d have been a great use case.
[2] - I’ve since moved this Action out into its own repo here, since it could be useful for most Jekyll sites.