I'm maintaining a library/package that's distributed via a package manager (NuGet, Maven, NPM, etc ...it doesn't matter) and there has been too many times where my new package accidentally broke backwards compatibility.
For example, one time I mindlessly added a parameter to a method without realizing that it breaks backwards compatibility.
How do you ensure that your package is backwards compatibility? Do you have any automated tests? If so, what kind? Or do you just rely on code reviewers? Answers for .Net would be great but an answer for any language is highly appreciated as well.
Thanks
CodePudding user response:
The Roslyn team created a code analyzer that helps. There are instructions on GitHub on how to use it.
Basically you add the Microsoft.CodeAnalysis.PublicApiAnalyzers package to your project. If you manually edit your project file/msbuild files, be sure to add PrivateAssets="all"
to the PackageReference
, to avoid this package becoming a dependency of your package and forcing your package consumers to use the analyzer by accident).
Then, when you build your project, the analyzer will complain if any public API isn't defined in a PublicAPI.Shipped.txt
or PublicAPI.Unshipped.txt
file. This helps you detect when someone adds a new API, so code reviewers can decide if that's an API the support should support. There's also a rule to complain if an API defined in one of the text files was not found in the code. This tells everyone than an API was broken. There are some other analyzers/rules in the package, which help in keeping APIs stable and increasing the quality of APIs for package consumers.
When a new API is added, there's a code fix to add the new API to the PublicAPI.Unshipped.txt
file. How you use PublicAPI.Unshipped.txt
and PublicAPI.Shipped.txt
is up to you, but our team moves all contents from unshipped to shipped after we publish our packages to nuget.org. This means if a pull request removes or changes an API in PublicAPI.Unshipped.txt
, it's not a breaking change because that API was never available in a package on nuget.org.
My team hasn't yet implemented any automation around public API changes in pull requests. But depending on how sophisticated your CI pipeline is, you can also enforce a stricter policy regarding public API changes. For example, using GitHub webhooks, you can:
- When a PR gets a "PublicAPI:changed" label, use the GitHub Checks API to block the PR from being merged. If label is removed, then unblock the PR from being merged.
- When a PR with the "PublicAPI:changed" label gets the "PublicAPI:approved" label, use GitHub Checks to unblock the PR from being merged. Similarly, if the approved label is removed, but the chaned label stays, again block the PR from being merged.
- When a PR is created, or a new commit is added, check the diff between the PR target branch, and if there are any
PublicAPI.[Unshipped|Shipped].txt
files changed, then automatically add the "PublicApi:changed" label. If the PR already had the "PublicAPI:changed" label, but the PR no longer contains anyPublicAPI.*.txt
changes, then remove the "PublicAPI:changed" label.- It's up to you whether or not to remove the "PublicAPI:approved" label when new commits are pushed. It depends how often/likely someone with a PR with approved API makes another public API change and tries to sneak it in without another public API approval. On the other hand, if the PR needs a minor fix unrelated to public APIs, it can be annoying to request someone approve the public APIs again.
Anyway, all that's just an idea. So far we just manually notice when a PR contains a public API txt file change, and ping other people in the team for reviews as needed.