Running SwiftFormat on CI
Introduction
In case you haven’t heard of swiftformat yet, you’ve either been living under a rock, or just have been living your life wrong. It’s a tremendous tool to keep your codebase clean and consistent, and it’s the first thing I add to any project I’m working on. However, having it run on your machine is one thing, but having it run on your CI is a whole different ball game. The easiest way I found to get it done, is by adding a script to download it (if needed), and run it as a step in your CI provider.
Prerequisites
So there are a few small things that we need to do before we run the script. Firstly, we need to actually install SwiftFormat. This can be done very easily using something like Homebrew, or by downloading the binary from the releases page. I prefer the Homebrew way, as it’s easier to keep up to date, and it’s easier to install on a CI provider.
brew install swiftformat
Secondly, and this is an optional step, we need to have a .swiftformat.yaml
file in our project. this is the file where we specify the rules we want SwiftFormat to use / ignore.
You don’t have to do this, if you don’t, SwiftFormat will use the default rules.
If there’s interest, I can do a post explaining the rules, what they do, and how to set them up. Let me know!
Setting up the script
So we’re going to use Bash to run this script. the reason we’re using Bash is that it’s available on almost all CI providers, and it’s easy to write. Here’s the script I use:
#!/bin/bash
set -e
# Function to commit changes if any Swift files were changed
commit_changes() {
echo "SwiftFormat has performed some changes, committing them."
# These two are optional, if you need to set specific user / email for Git. these can be stored in an environment variable,
# or are provided by the CI provider.
# git config user.email "${DEPLOYMENT_EMAIL}"
# git config user.name "${DEPLOYMENT_USER}"
git add ./\*.swift
git commit -m "Automatic: Committing SwiftFormat changes"
# Push changes, setting upstream if needed
git push origin HEAD || git push --set-upstream origin HEAD
}
# Run SwiftFormat
echo "Running SwiftFormat..."
swiftformat .
# Check for changed Swift files and commit them if any
if git status --porcelain | grep -q '\.swift'; then
echo "Changed Swift files found, preparing to commit..."
commit_changes
else
echo "No changes to .swift files to commit."
fi
Explanation
Bash scripts run from top to bottom, so we need to write our code accordingly. We first define the functions we’re going to use, then run SwiftFormat itself, and after that we can invoke the function to commit the changes.
commit_changes()
If you’ve never written / read a Bash script before, this might look a bit daunting. But don’t worry, I’ll explain what’s happening here.
Firstly, we’re using the systems Bash with what is known as a Shebang
. After that, we’re setting the -e
flag, which tells Bash to exit the script if any command returns a non-zero exit code. This is useful to prevent the script from continuing if something goes wrong.
Next, we’re writing a method. This is exactly the same as a method you’d write in Swift or any other programming language.
What this method does, is firstly it prints out that we’re starting to commit, then (commented out) if we need to - we’re setting up the git config
with the email and username we want to use for the commit.
After that, we’re adding all the modified .swift
files that have been changed, committing them with a message, and then pushing them to the remote repository.
We don’t want to add any temp files or anything else that have been changed, so we’re using git add ./\*.swift
to only add modified .swift files.
Running SwiftFormat
At this step, we’re printing out that we’re running SwiftFormat, and then we’re running it with the swiftformat .
command. This will run SwiftFormat on all the .swift
files in the current directory.
The command will look for a local .swiftformat.yaml
file, and if it doesn’t find one, it will use the default rules.
Checking for changes
After running SwiftFormat, we’re checking if there are any changes to the .swift
files. If there are, we’re printing out that we’re preparing to commit, and then we’re calling the commit_changes
function.
The way we’re doing this is with a simple if
statement, firstly we’re using the git status --porcelain
command to get the status of the repository. The --porcelain
flag is used to get the status in a machine-readable format. We’re then piping this output to grep
to search for any .swift
files that have been changed.
We’re adding the -q
flag to grep
to make it quiet, and only return a non-zero exit code if it finds a match. If it does, we’re printing out that we’re preparing
to commit, and then we’re calling the commit_changes
function. This is because we don’t really care about which files have been changed, we just care that there are files that have been changed.
If no files have been found, there’s nothing to commit, congratulations!
If there are files found, we’re going to the commit_changes()
method, which we explained above.
Conclusion
And that’s it! it really was that easy to write a script that:
- Run SwiftFormat
- Checks if there are any files changed
- Commits the changes if there are any
You can now plop this script into your CI provider. Depending on your provider, you may need to make it into an executable, using something like chmod +x /path/to/your/script.sh
. However, with a lot of providers like CircleCI, scripts can run as executables out of the box, so check with your providers docs.
I hope you find this useful!