Seeing the forest for the trees
I have set up GitHub Actions for a Node.js project for the first time. I’ll use this as exercise as an example on how bogged down in details one can get and how a seemingly simple task can raise a myriad of questions, ultimately leaving one unable to see the forest for the trees.
Our first stop is GitHub Help on Using Node.js with GitHub Actions. Right at the start, you’ll see the following template1:
name: Node.js CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [8.x, 10.x, 12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build --if-present
- run: npm test
env:
CI: true
Some might take this template and be done with it. However, I wouldn’t be writing this blog post if my journey ended here. For my part, this template raises a few questions—mostly why? Why does only one step have a name
? Why npm install
as opposed to npm ci
? Why do we need to specify the CI
environment variable ourselves? On a smaller scale, I’m also wondering whether Node.js’s version should be prefixed with a “v” and why there’s a blank line after build:
.
Digging deeper, right above the template, the documentation links to the Node.js workflow template. There, you’ll find this slightly different template2:
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
env:
CI: true
Why does this template define different on
events? Why does this template actually use npm ci
over npm install
?
We haven’t even peeked at GitHub Action’s actual reference documentation and are already curious about a number of things.
Typically, in such cases, I turn to open-source projects where their maintainers care more about such things than usual. GitHub Actions aren’t that widespread yet, however, I did find both AVA and Refined GitHub using GitHub Actions. Looking at their workflow configuration, there’s definitely the one or other line to be inspired by.
Jumping ahead, my template might look like this:
name: Node.js CI
on: push
jobs:
Test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
on
GitHub’s reference documentation lists a few more examples such as on: push
and on: [push, pull_request]
. I do wonder why the first template uses [push]
while the second template considers both pushes and pull requests but only on the master
branch. To keep it simple, push
(without brackets) seems like a good choice.
jobs.build
tojobs.Test
While build
is simply the job’s ID, this identifier actually seems to be used as the job’s name (in absence of an explicit name
) and will therefore be displayed on GitHub. In that case, let’s use a proper title.
Furthermore, Test seems more appropriate than Build because we are actually running npm test
.
- Job names
We could give every job a custom name but this might be unnecessarily elaborate. Therefore, let’s just remove the name
from that single step.
npm run build
While --if-present
is nice, we don’t need this step if we don’t actually have a build script. Furthermore, even if we’d have one, we might just as well specify a prepare
script so it’s automatically ran on npm install
.
CI
environment variable
Looking at GitHub Actions’s default environment variables, CI
is always set to true
. Therefore, there seems to be no good reason for defining it again.
There’s still room for improvement (nothing is so perfect that it can’t be complained about) but it’s an improvement compared to the original starter template, especially when asking the question: How much yak shaving could we eliminate by lowering the number of questions being raised?