Caddy is great! But am I the only one who gets frustrated seeing breaking changes in a minor version release? I know semver isn't "the one true way", but it sure does solve a problem for me. I've had too many applications FTBFS or start up on minor (or even patch!) version bumps because they included breaking changes.
Semver is great for libraries. Caddy is a project which has so many dimensions of "surface area" that it's hard to boil down the implications of changes into a single decimal-separated number. Presumably this is why a lot of larger projects use year-month versioning or just bump the major version every release. I'm actually considering doing the latter, except ... Go modules are very opinionated about major version bumps because it was designed with libraries, not commands (main funcs) in mind... and bumping the major version each release would be also be a major inconvenience to dozens of plugin authors.
Caddy has a Go API, a configuration surface (two built-in: JSON and Caddyfile); a config API; HTTP, TLS, TCP, and UDP behavior; a command-line interface; etc... the list goes on and on in ways that can break a deployment. Which of those does the one and only semver version apply to? Go has opinionated tooling around semver for the Go package stuff, so we kind of have to cater to that, but end users don't really care about that. We could split the project into multiple smaller sub-projects, each with their own versions, but then it gets confusing and tedious to build and maintain. It's also inconvenient for people to contribute to that. And we'd have to ship Caddy with several versions, one for each "surface area dimension."
We've settled on mediocrity with our current version scheming which I admit is not my favorite, but I haven't really found anything better yet. Year-month versions are nice except that it implies either a regular release cadence (which we don't have) or that a larger span between two releases is more significant than more frequent releases (maybe true, but maybe not); it doesn't really tell you anything about the build... just approximately when it was made, but not even exactly when it was made (a month is a big window!) - I guess if you do multiple releases per month you just tack another number on the end? Maybe it should just be a timestamp. Or we could invent an N-dimension decimal number or some sort of string that has to be split and parsed...
Anyway. We do try to be gentle with breaking changes. Most of these have been documented as deprecated for years as well as printing warnings in logs. But we try to minimize the number of these, for sure.
Your versioning system honestly doesn't sound that bad. If you took the major version out of the picture, you could consider the minor and patch versions to line up with the major and minor versioning scheme of Compatible Versioning (ComVer) [1]. I think if you were to explain your versioning system around ComVer, including the inconveniences which currently come from major version updates of Go modules, it would be quite clear. If Go were to improve upon the major version inconveniences down the road, you could then migrate your major / minor ComVer versions from the minor / patch SemVer versions to the major / minor SemVer versions. Great work, by the way.
Interesting timing for me since I was just reading the semver.org site just last week. I know that their proposal is to only include breaking changes in the major version, but in my experience lots of products use major versions for marketing purposes, and minor versions for functional changes including both breaking and non-breaking changes.
The important thing is to be clear in your docs about your versioning strategy. And from a quick search of the Caddy website, I couldn't find anything that explains this. Their install guide doesn't really mention versions at all, giving people no clues that a minor version change could break their sites.
We could improve that for sure. I am hoping to redo the website docs later this year... and will try to include some information about our development and release process.
Basically we try to put the bigger changes in the "minor" version bump (because bumping the major version introduces a lot of friction in the Go ecosystem) and encourage people to read release notes. We are open to suggestions though!
> in my experience lots of products use major versions for marketing purposes
This is what people are desperately hoping to change. The industry is tired of updating from 4.7.1 to 4.7.2 and having everything break. Please bring sanity to versioning, so people can have a reasonable expectation that x.y to x.z isn’t going to require days of rewriting stuff.
> I know that their proposal is to only include breaking changes in the major version, but in my experience lots of products use major versions for marketing purposes, and minor versions for functional changes including both breaking and non-breaking changes.
The solution is one more number: Marketing.Breaking.Feature.Bugfix
It's not clear to me that trying to assign semver semantics to a command line interface is going to work well; trying to define the "interface" for command line tools seems too challenging. Perhaps one might suggest that caddy should have used a different versioning pattern, but I have to admit that the x.y.z pattern is so prevalent these days, I have a hard time faulting someone for using it.