Arbitrary workflows with GitHub Actions for fun and pages
Problem statement
After I finished loadtesting a bunch of routers, I stopped the work with an HTML generator in hand.
While it’s super easy1 to run ruby graph.rb *.json
and push the result on
a webserver somewhere2, I wondered (poked by Pim) how hard it would be to
have some sort of html generator run as a post-commit hook, and deploy the
result automatically3.
This post details about the easiest way I have found.
I’m using two GitHub features available to free tier to make it happen:
- GitHub Actions, to run arbitrary workflow (ruby script)
- GitHub Pages, to deploy arbitrary html as a website
Solution
Well aware of the fact that one can host Jekyll blog on GitHub Pages4, I started exploring the idea of using Pages to host the output of the TRex visualizer.
First I added the tree.rb
generator that takes care of generating a website indexes for a given directory hierarchy.
Boring, but necessary.
What I seemed to be missing was a way to run some script post-push that would take care of the actual HTML generation. Similar to the Server-Side Hooks vanilla git supports.
I’ve found a few tutorials that mentioned GitHub Actions5 as an answer. Although the tutorials I’ve found were all rather convoluted.
Poking the docs, together with some experimentation, quickly yielded a relatively minimal Actions config that works. Color me surprised.
One file is all that’s needed to configure the workflow:
# .github/workflows/gh-pages.yml
name: GitHub Pages
on:
push:
branches:
- master
pull_request:
jobs:
deploy:
runs-on: ubuntu-20.04
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
# Checkout data
- name: Checkout
uses: actions/checkout@v2
with:
repository: wejn/trex-loadtest-results
# the following line is redundant (for illustration)
ref: master
path: data
# Fetch Ruby
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
# Checkout the viz script
- name: Checkout viz
uses: actions/checkout@v2
with:
repository: wejn/trex-loadtest-viz
path: viz
# Run the script, outputting to public/ subdir
- name: Make
run: |
mkdir ./public
ruby viz/tree.rb data public /trex-loadtest-results
# Deploy public/ subdir into the gh-pages branch
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: ${{ github.ref == 'refs/heads/master' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
Given that I’m far from being an Actions expert, here’s my mental model of how it works underneath:
Some machinery runs the steps
above in sequence (on a ubuntu-20.04
vm).
Each step is an arbitrary workflow described in a GH repo (for example
actions/checkout that checks out specified
GH repo into the staging area)6.
So my steps
run multiple 3rd party actions that:
- fetch the repo itself
- set up ruby
- fetch the visualizer script
- run the script (hello
tree.rb
)
The Ruby script outputs its result (HTML files) into the public
directory.
So the staging area ends up as follows:
data :: checkout of wejn/trex-loadtest-results (loadtest data)
viz :: checkout of wejn/trex-loadtest-viz (trex visualizer scripts)
public :: output directory, populated by tree.rb
and the last step uses another 3rd party action that pushes the contents of
public
directory into the gh-pages
branch of the original
repo from which the workflow
runs. But only if it’s running on the master
branch.
After this one-file setup all that is left is to configure Pages to use the
generated gh-pages
branch as a source:
and do another commit7.
Et voilà, all done.
Closing words
It still amazes me that I can run an arbitrary commands on 3rd party servers, but hey, it works. And it’s “free”.
-
barely an inconvenience, really ↩
-
As I have done in the post. ↩
-
Hipsters ^W Cool kids call this CI/CD, right? Bring forth the avolattes! ↩
-
henceforth Pages ↩
-
henceforth Actions ↩
-
Don’t ask me how that
actions/checkout
repo describes the commands to run. Didn’t care enough to find out. ↩ -
Because Pages seem to be only deployed after commit to the configured branch. Which makes sense. ↩