Semver enforcement

Hi there :slight_smile:

Is there any check in place, that goes further than checking the type signature, in order to determine the API changes?

What are you looking for? Not sure I understand what else would impact semver.

@wolfadex type signature could be the same but logic inside the function behaves differently, e.g. the withDefault logic was True but is now False

@ShalokShalom no there isn’t :pensive:

@choonkeat that’s exactly what semver covers, which is why I asked. That would constitute a patch change.

So yes, Elm has enforced semver.

If String.append a b was returning a ++ b but now returns b ++ a.

While no type signature had changed, all user code compiles after upgrade but would be an incompatible change and as far as semver itself is concerned, should bump major version.

But elm publish doesn’t catch that and would only be a patch change.

Elm has no way to detect those breaking changes, it will see this as a patch version. All you can do is force Elm to think it is a breaking change by introducing a made up type signature change somewhere.

When making a breaking change that doesn’t cause compilation errors (which as said won’t count as a breaking change by Elm), consider actually causing compilation errors. Rename the function or something. Then users of your package get help finding all the places they need to account for the new behavior.

3 Likes

I’ve been thinking about this since I first learned about Elm’s enforced semver.

I THINK it would be possible to create a tool that will run one version of the code against another version’s tests. This would make sure that version 1.1.1 or 1.2.0 still passes all the tests from 1.1.0.

Obviously, that only gives you as much guarantee as the tests in the previous version.

1 Like

I always found this semver enforcement a little silly. I mean Elm libraries are consumed inside Elm code so everything that changed and caused major version bump will error nicely in my code.

And because semver lacks granularity, just version number change doesn’t tell me much.

As someone said - Patch or minor change? Don’t care. Major change? Dunno, we’re probably fucked.

So after major version bump I still need to run compiler and see what changed and how it impacts my code.

I see what you are saying - it would break anyway regardless of what the version number says. But the point is…

You can put version ranges in your packages elm.json, for example “elm-community/json-extra”: “4.2.0 <= v < 5.0.0”. This protects the package from ever using the next major version which will break it, so any consumer of the package with this dependency can be certain that their build will always work. Without this 1:1 mapping between breaking changes and the major version number, things could break without warning and we would not have such a robust and reliable package system - it would be more like the wild west npm system.

The slight problem (and we should definitely build some tooling to address this problem) with that is that the author can put just about any range they want in there. As long as the latest resolved version compiles, the compiler will not complain even if a previous (or later) version would be completely broken…

Thankfully this seems to almost never happen in practice (probably because actually being compatible with multiple major versions is relatively rarely possible and generally packages do not restrict maximum minor version, so consumers tend to always resolve the backwards compatible latest minor version), but the possibility is rather annoying.

Yes, a restriction to ranges of the form “x.y.z <= v < (x+1).0.0” is generally what is most useful and happens in practice. I suppose a hard rule about that might be going too far?

The elm publish tool just checks that it builds correctly locally. To do more sophisticated checking, we would need a package server that checks the builds in a controlled environment on the server-side. And then you have the problem of potentially checking a large number of combinations of versions which potentially makes it all a bit too much to fully check and enforce.

Certainly, I think that at least doing the step of checking a compile against the latest versions of the current state of the package repo in a controlled server-side environment makes sense. For example, there are packages built on Windows or Mac-with-case-inesnsitive-file-system that will not compile on a Unix box due to files having the wrong capitilization on them.

Seems fairly unlikely. As far as I can fathom, the only time you would need to check combinations is the situation where a package depends on 2 or more packages with more than one major version (this is very rare in the Elm ecosystem). These can break for instance if in the package does B.bar A.foo, and this works in version A 1 x B 1 and A 2 x B 2, but not for instance in A 1 x B 2.

Otherwise for minor versions there isn’t really a situation where packages can affect each other, so the total number of builds necessary is just the maximum number of version resolved for any dependency.

For information, elm-test-rs enables you to test against the lowest specified version. There is a small explanation in the readme.

1 Like

Or you can use strict versions for reproducibility and use dependabot for bumping dependencies. That way you won’t get random CI errors because someone published new package. All of deps updates are in separate PRs, so every error is minimal.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.