Dart & semver hygiene

Software developmentFlutter

Dart & semver hygiene

What is semver?

The term semver means “semantic versioning” and is used to describe software releases.
It is defined here.

The essence of this rule-set is to couple the kind of (API) change with the version of the software. If you make a breaking change then you have to increase the major version and for non-breaking changes you have to increase the minor version (simplified).
This rule-set is the recommended way to version dart packages and all the mechanisms to resolve versions of dependencies rely on that.

What is the problem?

In general, I think semver works quite well, but sometimes it happens that a breaking change slips through.
This can have dramatic consequences.
If a package releases a new version and only increases the minor version or the patch version while still containing breaking changes then builds of dependent projects will fail without the developer specifying a new version.
This is because it is considered best practice (even a requirement) for packages to not depend on an exact version but on a compatible version range. This is done by assuming that any newer version that doesn’t increase the major version is backwards compatible.
But even if you don’t have a direct dependency on that package you might have a transitive dependency (e.g. if a package you depend on depends on that package) and you get your build broken as a result.

Is there something I can do about it?

At least soon™️.

We were facing such a transitive dependency build breakage and I wondered if there is an easy way to integrate a semver check into a CI pipeline and why package maintainers don’t check that automatically.
After some research I was not able to find a utility that could be used to do such a check, so I decided to create one myself.

Welcome dart_apitool

I named the tool “dart_apitool” (I know. Such an inventive name 😉).
It can create a model of the public API of a given package and diff two public API models while checking the version regarding semver.

The package reference can be

  • a model stored in a file (dart_apitool allows you to extract that)
  • a copy of the old package on disk
  • a pub-reference (dart_apitool will download the specified version of the package and extract the API model)

So the only thing a package maintainer has to do is to tweak the release process so that a reference is stored (can be just the released version number) which allows the CI pipeline to use that stored reference to check if the next version is still semver compliant.

I tried to cover all the different parts that make up a public API, but I’m sure I missed something. So please feel free to try it out and report any issues you have with it.

This is how a dart_apitool output can look like if it detects a problematic version:
dart_apitool in action

Let’s improve semver hygiene of the dart package ecosystem!