Today I’ve been looking at reviving a tool that I built a while ago, which automatically builds a Github Actions workflow file for a Swift package.
The functionality for this was originally part of my Action Status utility, which is a small macOS app for monitoring the status of Github Actions. That app also needs a bit of TLC, but that’s for another day.
Action Status was originally just for monitoring CI jobs (like the old app CCMenu), but at some stage I realised that all the workflow files I was monitoring were pretty repetitive and fiddly to build. I figured that a tool ought to be able to do a better job of writing them, and so a little bit of feature-creep ensued.
Some time later, Swift plugins became a thing, and I realised that having a plugin to build the workflow might be good. Potentially you could even have a Swift Package which automatically built and updated its tests.yml
file whenever it was compiled.
As a result of this, I factored out the workflow generating code from Action Status and moved it into a new ActionBuilderCore package, and then built an ActionBuilderPlugin with it.
The plugin worked, but I hit a few snags along the way, mostly relating to the relative immaturity of the Swift plugin support, plus the fact that adding plugins to a package means adding dependencies, which isn’t always what you want.
I also got distracted by other projects, and so both Action Status and the workflow building plugin have languished a bit. For a while now though I’ve been meaning to revive the basic concept.
I’m not sure about the plugin, but just having a tool that you can point at a Swift package source folder, and which will write a working Github Actions workflow.yml file into it, still seems like a pretty useful thing. Maybe you just run it manually, or from an Xcode build phase?
One refinement I do want to make is to get as close to a zero-configuration tool as I can.
The original implementation offered quite a lot of choice, and the UI was full of switches and selectors allowing you to turn things on and off. You could pick which versions of Swift to build against, which configurations to try, which platforms, whether to run tests, etc, etc.
This doesn’t suit a plugin so well, or even a tool that you invoke manually. I added a config file that you can drop into your source directory, but it would be nice if you rarely needed to do so. Really you just want to be able to point the tool at a package and have it work out that stuff and do The Right Thing™.
Luckily I realised that most of this information can be extracted from the package manifest itself.
Another problems that the tool implementation suffered from is that it needs to be taught which versions of Swift exist, and how to install/select the right one in the Github runner, and which runner environment to use. When testing Apple platforms, it also needs to know whether to use SPM or Xcode to perform the build and testing, since annoyingly SPM cannot easily be persuaded to build for iOS/tvOS/watchOS/visionOS.
Luckily this picture is slowly improving. Swiftly now exists, and can solve some of these issues for me. I can definitely use it to install Swift on the runner instances, but I think with a bit of luck I can also use it for Swift version discovery, which will allow me to simplify my code and remove the need for the tool to be updated when new Swift versions are released.
The tool still needs to do some shenanigans in order to support building and testing on iOS/tvOS/watchOS/visionOS. Apple currently say that they have no plans to support a unified build interface for all platforms, which is sad. That said, a lot of the underpinnings required to support it now seem to be in place, including the fact that Xcode and SPM are moving towards a shared build system, and under the hood most of the tools appear to support specifying a toolchain and/or triple to indicate which platform you’re building for, as opposed to which one you’re building on. For now I think I still need to manually teach the tool about the Xcode versions and their corresponding Swift versions, but I’m hoping that this, too, may eventually be easier (or unnecessary).
Anyway, all of the above are things that I’d quite like to tidy up and roll into a working plugin.
The first step today was to revive the command line tool, which is part of the ActionBuilderCore package.
I’ve kicked the tyres on this, got it working with swiftly, and taught it about Swift 6.0, 6.1 and 6.2-snapshot. There’s more to do, but hopefully I will slowly get it polished up again.