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:

Tl;dr: setup, result.

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:

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:

Pages config in the repository

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”.

  1. barely an inconvenience, really

  2. As I have done in the post.

  3. Hipsters ^W Cool kids call this CI/CD, right? Bring forth the avolattes!

  4. henceforth Pages

  5. henceforth Actions

  6. Don’t ask me how that actions/checkout repo describes the commands to run. Didn’t care enough to find out.

  7. Because Pages seem to be only deployed after commit to the configured branch. Which makes sense.