Quite often, iOS Software Engineers need to encapsulate some logic to Swift packages and share it between different apps. To control the version of the code, Swift packages follow Semantic Versioning conventions. Here is a version number format of this convention:
MAJORversion when you make incompatible API changes;
MINORversion when you add functionality in a backwards-compatible manner;
PATCHversion when you make backwards compatible bug fixes.
Even though this convention is very simple to understand, there might be situations when a developer forgets about some modified parts of public code that affect the API of the framework and sets a new version of the package that doesn’t represent the real changes in the framework.
What if there might be a solution that helps to automate this routine? 🤔 In this article, I will introduce you to a little tool capable of determining if changes in the Swift package are API-breaking.
Luckily Swift toolchain already contains such an experimental tool that can do exactly what we need. It is called API Digester. API Digester can work in two regimes. In the first regime, it builds and dumps the package module into a JSON file. In another, it compares two dumps and outputs the difference between them. Let’s try it out!
First of all, you need to download and install Xcode 13 (beta). At the moment of writing of this article, the stable version of Xcode 12 doesn’t contain this tool, but it was available before though.
Create two identical Swift packages in two directories:
Remove the code from Package.swift file in the new package:
Compile the packages with the Swift compiler shipped with Xcode 13:
Dump the packages’ modules:
Compare the dumps:
You will get such output:
You see that the tool has detected that we deleted a public declaration of the
Package struct in the new package.
Swift Package API Diff
In order to simplify the work with the API digester, I created a small wrapper around it called swift-package-api-diff. The wrapper also has two commands:
api-changes-type(default): get majority of API changes: breaking or non-breaking;
api-changes-description: get API changes description.
Let’s download and install it:
To check if the changes are breaking you can call the following command:
and the result will be
If you want to know what exactly has changed, you can call:
As a result, you will see:
The wrapper sanitizes the API Digester’s output and shows only non-empty types changes.
If you modify
new_package in another way, for example, by adding a new declaration:
you will get the following result:
Let’s continue and replace the
struct keyword with
In this case you will get:
And, finally, if you replace the value of
text with a number literal:
the tool will output:
You can continue playing with swift-package-api-diff with your own packages. But you need to keep in mind that the current Xcode 13’s API digester is still experimental and might not detect some changes in the packages. Another limitation of the tool is that it can work only with packages with macOS targets.
I think it’s good to be familiar with such a tool and keep your eye on the ball. Someday, Apple will release Xcode with a fully working and stable API digester. Until then, you can experiment with
swift-package-api-diff and contribute to the Swift compiler to improve the tool. Thank you for reading 🙂.