Usability of `swiftly` on CI

I was very happy to see the release of swiftly to improve the consistency of toolchains and developer environments. Unfortunately, in adopting it, we've run into considerable headaches with all of our CI environments – especially those running macOS.

To explain the issues with macOS specifically: installing swiftly does not appear to be possible on a restricted (non-admin) user environment. I'm not able to provide much more info than this, other than to say, the installer fails due to permissions issues.

We tried to work around this by symlinking the restricted ci user's ~/Library/Developer/Toolchains to the non-ci user's equivalent, but it doesn't work due to macOS permissions (regardless of any chmodding). swiftly also gets very confused due to toolchains being "installed" but not actually being installed where it expects (it uses different sources of truth for knowing which toolchains are installed, vs. actually using them – seems to be a gotcha in the system).

Instead, the only thing that unblocked us was to symlink ~/Library/Developer/Toolchains from both admin and non-admin users to /Library/Developer/Toolchains – that allows us to run CI runs in the case where the toolchain in question is already installed globally. But it does not allow swiftly to install new toolchains (again, regardless of chmodding of /Library/Developer/Toolchains), which also defeats the point. Now that 6.1.1 has been released, swiftly insists on installing and using 6.1.1 instead of 6.1.0

Basically the whole thing is (unsurprisingly) a mess in this swamp of workarounds. What would probably fix it is to get swiftly installing and updating in a non-admin ci user.

Does anyone have a better solution for this?

Have multiple Xcodes installed and use DEVELOPER_DIR env var to select which one is being used for the current job.

1 Like

Ok, we investigated this again today. Firstly we cleaned up all the mess we'd made ourselves.

I then cloned main from swiftlang/swiftly and built it via swift build -c release, scp'd the resulting swiftly binary to the CI machine, set the relevant environment variables (notably SWIFTLY_TOOLCHAINS_DIR) and ran swiftly init.

Then on GitHub Actions we need to run . ~/.swiftly/env.sh before running swiftly. With that, the setup is now working as we expect.

The SWIFTLY_TOOLCHAINS_DIR info comes from this comment. What confused me about that comment is that it is ineffective while running the latest swiftly release (which was built in March). It would be great to get a new swiftly release to avoid these manual steps.

This mostly works on macOS CI… but there do exist some Swift versions that apparently have no official corresponding Xcode version. It looks like Swift 6.0.1 did not ship with a paired Xcode from Apple. Xcode 16.0 shipped with 6.0.0 and Xcode 16.1 shipped with 6.0.2.

There might also be some ideas you can borrow here from the vapor action.

Interesting approach. Looking at the code it doesn’t seem to support macOS though