lightbend-labs / mima

A tool for catching binary incompatibility in Scala
Apache License 2.0
459 stars 71 forks source link

Broken compatibility with SBT 1.2.8 #417

Closed nigredo-tori closed 5 years ago

nigredo-tori commented 5 years ago

I've updated sbt-mima-plugin from 0.3.0 to 0.6.1 in one of my projects, and got the following:

[error] java.lang.NoSuchMethodError: 'sjsonnew.JsonFormat sbt.package$.singleFileJsonFormatter()'
[error]     at com.typesafe.tools.mima.plugin.MimaKeys.<init>(MimaKeys.scala:23)
[error]     at com.typesafe.tools.mima.plugin.MimaKeys$.<init>(MimaKeys.scala:7)
[error]     at com.typesafe.tools.mima.plugin.MimaKeys$.<clinit>(MimaKeys.scala)
[error]     at sbteldis.EldisVersionPlugin$.<init>(EldisVersionPlugin.scala:38)
[error]     at sbteldis.EldisVersionPlugin$.<clinit>(EldisVersionPlugin.scala)
[error]     at java.base/java.lang.Class.forName0(Native Method)
[error]     at java.base/java.lang.Class.forName(Class.java:398)
[error]     at sbt.internal.inc.ModuleUtilities$.getObject(ModuleUtilities.scala:20)
[error]     at sbt.internal.inc.ModuleUtilities$.getCheckedObject(ModuleUtilities.scala:27)
[error]     at sbt.internal.inc.ModuleUtilities$.$anonfun$getCheckedObjects$1(ModuleUtilities.scala:31)
[error]     at scala.collection.immutable.Stream.$anonfun$map$1(Stream.scala:414)
[error]     at scala.collection.immutable.Stream$Cons.tail(Stream.scala:1167)
[error]     at scala.collection.immutable.Stream$Cons.tail(Stream.scala:1157)
[error]     at scala.collection.generic.Growable.loop$1(Growable.scala:53)
[error]     at scala.collection.generic.Growable.$plus$plus$eq(Growable.scala:57)
[error]     at scala.collection.generic.Growable.$plus$plus$eq$(Growable.scala:49)
[error]     at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:185)
[error]     at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:43)
[error]     at scala.collection.TraversableLike.$plus$plus(TraversableLike.scala:146)
[error]     at scala.collection.TraversableLike.$plus$plus$(TraversableLike.scala:142)
[error]     at scala.collection.immutable.List.$plus$plus(List.scala:206)
[error]     at sbt.internal.PluginDiscovery$.discoverAll(PluginDiscovery.scala:56)
[error]     at sbt.internal.Load$.loadPlugins(Load.scala:1318)
[error]     at sbt.internal.Load$.loadPluginDefinition(Load.scala:1263)
[error]     at sbt.internal.Load$.buildPlugins(Load.scala:1242)
[error]     at sbt.internal.Load$.plugins(Load.scala:1225)
[error]     at sbt.internal.Load$.$anonfun$loadUnit$2(Load.scala:694)
[error]     at sbt.internal.Load$.timed(Load.scala:1395)
[error]     at sbt.internal.Load$.$anonfun$loadUnit$1(Load.scala:694)
[error]     at sbt.internal.Load$.timed(Load.scala:1395)
[error]     at sbt.internal.Load$.loadUnit(Load.scala:688)
[error]     at sbt.internal.Load$.$anonfun$builtinLoader$4(Load.scala:484)
[error]     at sbt.internal.BuildLoader$.$anonfun$componentLoader$5(BuildLoader.scala:176)
[error]     at sbt.internal.BuildLoader.apply(BuildLoader.scala:241)
[error]     at sbt.internal.Load$.loadURI$1(Load.scala:546)
[error]     at sbt.internal.Load$.loadAll(Load.scala:562)
[error]     at sbt.internal.Load$.loadURI(Load.scala:492)
[error]     at sbt.internal.Load$.load(Load.scala:471)
[error]     at sbt.internal.Load$.$anonfun$apply$1(Load.scala:251)
[error]     at sbt.internal.Load$.timed(Load.scala:1395)
[error]     at sbt.internal.Load$.apply(Load.scala:251)
[error]     at sbt.internal.Load$.defaultLoad(Load.scala:69)
[error]     at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:829)
[error]     at sbt.BuiltinCommands$.doLoadProject(Main.scala:829)
[error]     at sbt.BuiltinCommands$.$anonfun$loadProjectImpl$2(Main.scala:800)
[error]     at sbt.Command$.$anonfun$applyEffect$4(Command.scala:142)
[error]     at sbt.Command$.$anonfun$applyEffect$2(Command.scala:137)
[error]     at sbt.Command$.process(Command.scala:181)
[error]     at sbt.MainLoop$.processCommand(MainLoop.scala:151)
[error]     at sbt.MainLoop$.$anonfun$next$2(MainLoop.scala:139)
[error]     at sbt.State$$anon$1.runCmd$1(State.scala:246)
[error]     at sbt.State$$anon$1.process(State.scala:250)
[error]     at sbt.MainLoop$.$anonfun$next$1(MainLoop.scala:139)
[error]     at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error]     at sbt.MainLoop$.next(MainLoop.scala:139)
[error]     at sbt.MainLoop$.run(MainLoop.scala:132)
[error]     at sbt.MainLoop$.$anonfun$runWithNewLog$1(MainLoop.scala:110)
[error]     at sbt.io.Using.apply(Using.scala:22)
[error]     at sbt.MainLoop$.runWithNewLog(MainLoop.scala:104)
[error]     at sbt.MainLoop$.runAndClearLast(MainLoop.scala:59)
[error]     at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:44)
[error]     at sbt.MainLoop$.runLogged(MainLoop.scala:35)
[error]     at sbt.StandardMain$.runManaged(Main.scala:138)
[error]     at sbt.xMain.run(Main.scala:89)
[error]     at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
[error]     at xsbt.boot.Launch$.withContextLoader(Launch.scala:128)
[error]     at xsbt.boot.Launch$.run(Launch.scala:109)
[error]     at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
[error]     at xsbt.boot.Launch$.launch(Launch.scala:117)
[error]     at xsbt.boot.Launch$.apply(Launch.scala:18)
[error]     at xsbt.boot.Boot$.runImpl(Boot.scala:56)
[error]     at xsbt.boot.Boot$.main(Boot.scala:18)
[error]     at xsbt.boot.Boot.main(Boot.scala)

The reason for this is that SBT broke binary compatibility in 1.3.x, so any plugins built against SBT 1.3.x are not compatible with SBT 1.2.8 and older. See https://github.com/sbt/sbt/issues/5049 for further discussion. The recommended workaround is to build everything against SBT 1.2.8.

For the users of this plugin the workaround would be to switch to an older plugin version. E.g. 0.6.0 seems to be built against SBT 1.2.8.

dwijnand commented 5 years ago

(Reported earlier in https://github.com/lightbend/mima/pull/382.)

Yes, MiMa v0.6.1 was built with sbt v1.3.0, which means (with no workarounds having been applied) that 1.3.0 is the minimum required sbt version for the build that uses the plugin.

Until it becomes clear that upgrading to sbt 1.3.0 is an issue, I'm going to leave this as is.


As an aside, you mention "SBT broke binary compatibility in 1.3.x". That's technically true but in a misleading way. "Binary compatibility" generally refers to backwards binary compatibility, that is new versions of sbt will continue to work with existing plugins.

sbt 1.3.x is and continues to be backwards binary compatible with sbt 1.0.0. But sbt 1.3.x isn't forwards binary compatible with the rest of sbt 1.x because it introduced new APIs (and, in this particular case, new API in a way that is super-easy to depend on: implicits on the top package object.)

nigredo-tori commented 5 years ago

"Binary compatibility" generally refers to backwards binary compatibility, that is new versions of sbt will continue to work with existing plugins.

Yes, I was talking about forward compatibility. Thank you for setting this straight :smile:.

Until it becomes clear that upgrading to sbt 1.3.0 is an issue, I'm going to leave this as is.

The main issue I see here is that this complicates upgrades for projects that use this plugin. E.g. for a build using SBT 1.2.8 and mima 0.6.0 we have to upgrade both at once. And it's not immediately obvious what plugin versions support what SBT versions beyond the 0.3/1.0 distinction.

Anyway, it is your right to drop SBT 1.2.x compatibility. However, I think that in this case the readme file should say:

MiMa's sbt plugin is released for sbt 1.3+ only (use 0.6.0 for sbt 1.2.x and older, and 0.3.0 for sbt 0.13).

dwijnand commented 5 years ago

Is there a reason you can't upgrade to sbt 1.3.2 first and then MiMa 0.6.1 after?

I agree with you the readme should be amended. Will do.

nigredo-tori commented 5 years ago

Is there a reason you can't upgrade to sbt 1.3.2 first and then MiMa 0.6.1 after?

For me personally - probably not. It'll be messy (there are a lot of projects, and there are helper plugins that bring in this one), but since I already know where the problem is, it is at least doable.

UPD: Actually, bumping everything together seems easier, so I'll do that.