-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
define & apply binary compatibility strategy #1565
Conversation
s"please upgrade to ${dependency.getVersion} or later" | ||
) | ||
case Unknown => | ||
args.out.println( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sbt-scalafix sets the printstream very late, so this gets dumped on plain stdout. It would be possible to wire a fallback sbt logger from the beginning.
I'd really like your view on this @olafurpg (and I cannot assign you), thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @bjaglin for adding this!
I suggest also declaring the versioning scheme in your build definition (on the projects that are published, and for which you do perform binary compatibility checks):
versionScheme := Some("pvp")
That may help build tools (at least sbt) to correctly resolve conflicting versions of scalafix artifacts.
docs/developers/api.md
Outdated
[`scalafix-core`](https://index.scala-lang.org/scalacenter/scalafix/scalafix-core) makes the packages | ||
below available to built-in and external rules. | ||
|
||
Its A.B.C scheme follows [PVP](https://pvp.haskell.org/) for syntactic and semantic binary compatiblity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the wording a bit confusing. It seems that you talk about “semantic binary compatibility” and “syntactic binary compatibility”. Although I guess you really talk about the binary compatibility of the API for syntactic and semantic rules?
Its A.B.C scheme follows [PVP](https://pvp.haskell.org/) for syntactic and semantic binary compatiblity | |
Its A.B.C version scheme follows [PVP](https://pvp.haskell.org/) for binary compatiblity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this was confusing, particularly in the context of scalafix where we have syntactic and semantic rules - I'll amend with your wording.
For the record, what I meant was that a major version will be bumped even though no linkage error may happen, but just because the behavior/semantics changed. Binary compatibility, as described in https://docs.scala-lang.org/overviews/core/binary-compatibility-for-library-authors.html for example, seems to focus on link guarantees, so I wanted to highlight the silent functional changes as a factor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a major version will be bumped even though no linkage error may happen, but just because the behavior/semantics changed
In such a case, would it be possible to not change the semantics of the existing methods but to add new methods instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what we aim for, but we cannot control dependencies that are part of the API: scalameta/scalameta#2601 is what resulted in a (silent) breaking change, identified by the community build.
@@ -179,6 +180,11 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys { | |||
private val PreviousScalaVersion: Map[String, String] = Map( | |||
) | |||
|
|||
override def buildSettings: Seq[Setting[_]] = List( | |||
versionScheme := Some("pvp"), | |||
versionPolicyIntention := Compatibility.None // TODO: harden after 0.10.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I verified that with Compatibility.BinaryCompatible
, we get
[error] Incompatibilities with dependencies of scalafix-core:0.9.34
[error] com.geirsson:metaconfig-core_2.13: incompatible version change from 0.9.15 to 0.10.0 (compatibility: package versioning policy)
[error] com.geirsson:metaconfig-typesafe-config_2.13: incompatible version change from 0.9.15 to 0.10.0 (compatibility: package versioning policy)
[error] com.lihaoyi:fansi_2.13: incompatible version change from 0.2.14 to 0.3.0 (compatibility: package versioning policy)
[error] com.lihaoyi:pprint_2.13: missing dependency
[error] org.scalameta:common_2.13: incompatible version change from 4.4.32 to 4.5.0 (compatibility: package versioning policy)
[error] org.scalameta:parsers_2.13: incompatible version change from 4.4.32 to 4.5.0 (compatibility: package versioning policy)
[error] org.scalameta:scalameta_2.13: incompatible version change from 4.4.32 to 4.5.0 (compatibility: package versioning policy)
[error] org.scalameta:trees_2.13: incompatible version change from 4.4.32 to 4.5.0 (compatibility: package versioning policy)
[error] Dependencies of module scalafix-core:0.9.34+56-5a4c18d3+20220319-2243-SNAPSHOT break the intended compatibility guarantees 'Compatibility.BinaryCompatible' (see messages above). You have to relax your compatibility intention by changing the value of versionPolicyIntention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opened https://github.com/scalacenter/scalafix/pull/1568/commits as draft for a reminder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably also want to add:
versionPolicyIgnoredInternalDependencyVersions := Some("^\\d+\\.\\d+\\.\\d+\\+\\d+".r)
See https://github.com/scalacenter/sbt-version-policy#how-to-integrate-with-sbt-dynver
@@ -11,6 +11,9 @@ jobs: | |||
- uses: olafurpg/setup-scala@v13 | |||
- uses: olafurpg/setup-gpg@v3 | |||
- run: git fetch --unshallow | |||
- name: Check that major was bumped if bin compat was broken | |||
if: startsWith(github.ref, 'refs/tags/v') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't block publishing of snapshots 🤞
@julienrf thanks for your feedback. I have just added sbt-version-policy in a second commit, your review is very much welcome on that one too. |
Unfortunately, sbt-version-policy expects |
I had a quick look at the code, and it looks like the early-semver assumption is only in
I guess I could also go for that if the fix above is not trivial. I had picked pvp over early-semver mostly of out laziness when (re)implementing bjaglin@5a4c18d#diff-d96ec3acf34c2b31f8eefeb8bdd342bb1365fb47091c75b69298b7b49c928aafR14 (since I couldn't find a versioning lib cross-published for 2.11). |
That might be the case, but using sbt-version-policy with anything else than early-semver is undertested. I recommend using early-semver, but I am willing to re-consider supporting other versioning schemes in sbt-version-policy (since you are not the only one asking for it). |
@julienrf I amended to advertize/honor |
@@ -179,6 +180,11 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys { | |||
private val PreviousScalaVersion: Map[String, String] = Map( | |||
) | |||
|
|||
override def buildSettings: Seq[Setting[_]] = List( | |||
versionScheme := Some("pvp"), | |||
versionPolicyIntention := Compatibility.None // TODO: harden after 0.10.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably also want to add:
versionPolicyIgnoredInternalDependencyVersions := Some("^\\d+\\.\\d+\\.\\d+\\+\\d+".r)
See https://github.com/scalacenter/sbt-version-policy#how-to-integrate-with-sbt-dynver
I guess the defensive strategy would be to always bump the minor version number of scalafix. I don’t know if this is much an issue. Also, why do you say that scalameta is on PVP? According to https://github.com/scalameta/scalameta/blob/main/COMPATIBILITY.md it seems to use semantic versioning. |
4a476c6
to
06866f1
Compare
Indeed, my only concern was that there is no tooling to enforce that (since sbt-version-policy's
Thanks for the pointer, I hadn't seen this. Thanks for your insights! |
Now that you say it, |
In the last few weeks, 2 dependency bumps broke backward compatibility of nightlies
Since these changes haven't made it to a release yet, that seems like a good moment to either
This PR takes the path of (1).