Bookish Development Diary, episode 8.
They’re fairly easy to set up - you make a yaml file called something like
Tests.yml, add it to the
.github/workflows/ directory at the root of your repository, and commit.
The yaml file can contain a vast range of things, but for testing Swift what it usually boils down to some fairly standard steps.
First you select which system and tool versions to build on. For the mac, the
macOS-latest image gives you the latest releases of macOS and Xcode. For Linux, there are Docker images available for Swift 5.0 and 5.1, as well as nightly builds of the latest Swift.
Then you clone your package with git.
Next you perform a build, using either
swift build or
xcodebuild build, depending on the platform you’re on.
Next you run some tests with
swift test or
There are plenty of other things you can also do (for example posting notifications, uploading files), but a simple file that just builds & tests on the Mac might look something like this:
name: tests on: [push, pull_request] jobs: macos: name: MacOS runs-on: macOS-latest steps: - name: Checkout uses: actions/checkout@v1 - name: Build run: swift build -v - name: Test run: swift test -v -c release
So far so good…
It’s pretty simple, and it’s free for open source projects, and has a reasonable allowance of free time for private projects if you’re on a paid Github tier.
Previously I was using Travis-CI to do something similar, but couldn’t justify the fees for the paid tier, so I decided to standardise on GH Actions instead, which meant moving over a whole bunch of my Swift packages.
One thing started annoying me a bit though. For Travis I was using CCMenu to monitor the test status. It doesn’t work for GH Actions. I figured out a way to get the actions to post notifications to a channel on Slack, but still…
I decided that it couldn’t be that hard to create a tool to address these problems, and off down another rabbit-hole I went.
Initially it started as a simple app, which just shows a list of repos in a window, with a tick or a cross to indicate success or failure.
This seemed like a good excuse to use SwiftUI, and I also figured that it might be handy to have it work on a mobile device, or even a tv, so I used Catalyst to target all three platforms at once.
Cunningly, I realised that Github Actions already spits out a status SVG for each action. So if I limited myself to public repos (to avoid authentication), I didn’t even need to use proper Github API - I could just parse that to figure out the status.
Thus Action Status was born.
I fairly quickly had the basic app up & running, but to really work like CCMenu does, the Mac version needed to have a funky status item in the menubar, warning me if something was failing.
Adding these items is pretty simple, but requires access to AppKit API that Catalyst can’t use.
To work round this I needed to get a bridging plugin working.
Didn’t take long, and looked really neat!
This was a bit of a detour admittedly, but loading plugins to bridge to AppKit was something I was going to need to do for Bookish anyway - because Catalyst’s scanner support doesn’t work on macOS :(
Now I know that I can do it, so it was definitely worth the bother.
In fact, figuring out the plugin thing proved doubly useful, as I soon realised that I needed to use the same approach if I wanted to integrate Sparkle (see my previous post…). This was another thing I needed for Bookish (which is also Catalyst-based), so all good…
Once I had all this working, I figured that I should get round to moving over all of my open source Swift Packages.
It turns out that I have rather a lot. Adding them all to Action Status one by one was tedious.
Worse still, some of them work on all platforms, some work on just the Apple platforms, some just work on the Mac. Some need to run tests, some just to check that a build works.
That’s a lot of YAML files. All follow the same basic pattern, all need some steps (like the Slack notification), but all need slightly different permutations of other standard steps in them.
Surely I could get Action Status to help with this?
Of course I could.
So I added a couple of abilities.
The first is the ability to scan a local directory (on the Mac), to look for repositories to add. Anything that looks like a git repository is checked to see if it is based in Github. If it is, and doesn’t already have an entry in Action Status’ list of repos, one is added.
The second is the ability to generate a
Tests.yml file for a repository, from within Action Status. Selecting this option displays a list of options to choose from. You can select platforms, configurations, and which actions to perform.
This turns out to be really handy. Getting the exact syntax of the steps right is a bit fiddly, and having something to do it for you really helps. Action Status remembers the choices you made, too, so if you want to tweak them and regenerate the workflow file later, you can.
This was all a bit of a distraction, but it’s proven to be useful enough a tool that I’m planning to make it available in the App Store(s).
I plan to expand it to work with private repos, and also have a bunch of other features that I’d like to add.
Once you have an app which has a list of your code repositories in the cloud, and also knows their locations on your local disk, all sorts of interesting opportunities present themselves.
Maybe Action Status can perform other regular tasks locally (such as fetching, committing backups, etc)? Maybe it can also generate other standard entries in your repos (.gitignore files, README headers, licenses, standard folder layouts). It could certainly support a much richer range of templates, for use with other languages or situations.
Also, whilst it’s focussed on Github Actions at the moment, there’s no reason in theory why Action Status couldn’t also support Travis, or Gitlab, or something else.
Please let me know if you thing it’s worth me bothering with any of this, or if I’ve lost the plot!
Meanwhile, I really will get back to Bookish soon. Honest.