-
Notifications
You must be signed in to change notification settings - Fork 950
[1.9.x] Smooth transition to valid Maven pattern of sbt plugins #7096
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
Conversation
e178312
to
550f3d1
Compare
sbt-app/src/sbt-test/dependency-management/sbt-plugin-diamond/test
Outdated
Show resolved
Hide resolved
sbt-app/src/sbt-test/dependency-management/sbt-plugin-publish/build.sbt
Outdated
Show resolved
Hide resolved
sbt-app/src/sbt-test/dependency-management/sbt-plugin-publish/build.sbt
Outdated
Show resolved
Hide resolved
|
||
> testProject / checkUpdate | ||
> set testProject / useCoursier := false | ||
> testProject / checkUpdate |
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.
Do we cover publishing to ivy repositories? (e.g. publishLocal
)
Do we cover resolving a plugin that we just published?
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 a great question; I thought the Ivy pattern and approach is entirely different from that of SBT+Maven?
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 expanded the scripted sbt-plugin-publish to test the publication to .ivy/local
and resolution from it.
For the Ivy publication, there are two cases, depending on the value of publishMavenStyle
.
publishMavenStyle := false
: Strictly no changes, we publish:
org.example/example/scala_2.12/sbt_1.0/0.1.0-SNAPSHOT/
├── docs
│ └── example-javadoc.jar
├── ivys
│ └── ivy.xml
├── jars
│ └── example.jar
└── src
└── example-sources.jar
publishMavenStyle.value := true
: We publish the legacy and new poms, and all the associated artifacts.
org.example/example/scala_2.12/sbt_1.0/0.1.0-SNAPSHOT/
├── docs
│ ├── example_2.12_1.0-javadoc.jar
│ └── example-javadoc.jar
├── ivys
│ └── ivy.xml
├── jars
│ ├── example_2.12_1.0.jar
│ └── example.jar
├── poms
│ ├── example_2.12_1.0.pom
│ └── example.pom
└── src
├── example_2.12_1.0-sources.jar
└── example-sources.jar
In the test, we do a publishLocal
on a project that is configured for Maven, so it is a Maven-style publication to Ivy.
sbt plugins were published to an invalid path with regard to Maven's specifictation. As of sbt 1.9 we produce two POMs, a deprecated one and a new one, that is valid with regard to Maven resolution. When resolving, we first try to resolve the new valid POM and we fallback to the invalid one if needed. In the new POM format, we append the sbt cross-version to all artifactIds of sbt plugins. This is because we want Maven to be able to resolve the plugin and all its dependencies. When parsing it, we remove the cross-version suffix so that the result of parsing the valid POM format is exactly the same as parsing the deprecated POM format. Hence conflict resolution happens as intended. More details can be found at sbt/sbt#7096
b2f1dbe
to
bec0d43
Compare
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 @adpi2 for all the PRs and the detailed explanations. I think this is a good approach.
024e5ac
to
764534a
Compare
@adpi2 was just wondering what those failing tests are, do you have much idea? It seems they would get fixed by stopping the cache upload but then I am not sure if that's what we want. |
@adpi2 is off for a few weeks. There might be some delay here. |
764534a
to
1f61f28
Compare
As of sbt 1.9, we publish deprecated and valid poms. In this test we check that sbt resolve the valid pom of an sbt plugin and fallback to the deprecated pom if the valid pom cannot be found.
For an sbt plugin, we publish two POM files, the legacy one, and the new Maven compatible one. The name of the new POM file contains the sbt cross-version _2.12_1.0. The format of the new POM file is also slightly different, because we append the sbt cross-version to all artifactIds of sbt plugins. Hence Maven can resolve the new sbt plugin POM and its dependencies. When resolving an sbt plugin, we first try to resolve the new Maven POM and if it fails we fallback on the legacy one. When parsing the new POM format, we remove the sbt cross-version from all artifact IDs so that there is no mismatch between old and new format of dependencies.
550933a
to
d05913f
Compare
@eed3si9n I need a release of sbt/librarymanagement#409 to merge this PR, maybe just a milestone version. Let me know if I can help. |
https://github.com/sbt/librarymanagement/releases/tag/v1.9.0-M1 should be on its way to Maven Central. |
@eed3si9n Something may have gone wrong, since I cannot find it: https://repo1.maven.org/maven2/org/scala-sbt/librarymanagement-core_2.12/ |
My bad. I forgot to release it from Sonatype staging. It should be there in 10 ~ 30 min. |
@eed3si9n This PR is ready for a final review. |
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.
Thanks!
sbt 1.9.0-M1 contains the new sbt plugin publishing mechanism. It dual-publishes sbt plugins with Ivy-style paths (invalid in Maven, although it works out when released from sbt) and valid Maven paths. See sbt/sbt#3410 and sbt/sbt#7096.
sbt 1.9.0-RC1 contains the new sbt plugin publishing mechanism. It dual-publishes sbt plugins with Ivy-style paths (invalid in Maven, although it works out when released from sbt) and valid Maven paths. See sbt/sbt#3410 and sbt/sbt#7096.
sbt 1.9.0 contains the new sbt plugin publishing mechanism. It dual-publishes sbt plugins with Ivy-style paths (invalid in Maven, although it works out when released from sbt) and valid Maven paths. See sbt/sbt#3410 and sbt/sbt#7096.
sbt 1.9.0 contains the new sbt plugin publishing mechanism. It dual-publishes sbt plugins with Ivy-style paths (invalid in Maven, although it works out when released from sbt) and valid Maven paths. See sbt/sbt#3410 and sbt/sbt#7096.
sbt 1.9.0 contains the new sbt plugin publishing mechanism. It dual-publishes sbt plugins with Ivy-style paths (invalid in Maven, although it works out when released from sbt) and valid Maven paths. See sbt/sbt#3410 and sbt/sbt#7096.
sbt 1.9.0 contains the new sbt plugin publishing mechanism. It dual-publishes sbt plugins with Ivy-style paths (invalid in Maven, although it works out when released from sbt) and valid Maven paths. See sbt/sbt#3410 and sbt/sbt#7096.
The goal of this PR is to fix #3410 in sbt 1.x without creating a big-bang in the ecosystem of sbt plugins.
Summary
The implemented strategy is:
Thus the migration of plugins can happen in any order:
It is worth noting that the descriptor of an sbt plugin dependency is still the same:
org.example:example:1.0.0
with extra-attributesscalaVersion:2.12
andsbtVersion:1.0
Motivation
From the user perspective almost nothing changes, the dependency to a plugin is still declared as:
The added value is:
mvnrepository.com
starts indexing the sbt pluginsjavadoc.io
can find the scaladoc of sbt pluginsAssociated PRs
In depth
Generating the valid pom file
We consider a pom file is valid if Maven can resolve it and check its consistency. More precisely, the path of the pom file and the declared
artifactId
in the pom file must be consistent.Given module
org.example:example:1.0.0
with extra-attributesscalaVersion:2.12
andsbtVersion:1.0
, its valid Maven path must beorg/example/example_2.12_1.0/1.0.0/example_2.12_1.0-1.0.0.pom
and the corresponding Maven module ID is:Maven must also be able to resolve the sbt plugin dependencies. Thus all declared sbt plugin dependencies in the pom file must contain valid artifact IDs, with the sbt cross-version.
This pom file is generated as if the declared module ID is
org.example:example_2.12_1.0:1.0.0
with no extra attributes. However, in sbt and Coursier, we must maintain the old-style module ID, with extra-attributes, to get the bi-directional compatibilty.Resolving an sbt plugin
Given module
org.example:example:1.0.0
with extra-attributesscalaVersion:2.12
andsbtVersion:1.0
, we first try to resolveorg/example/example_2.12_1.0/1.0.0/example_2.12_1.0-1.0.0.pom
and we fallback toorg/example/example_2.12_1.0/1.0.0/example-1.0.0.pom
.Whenever we parse a pom file, we must make sure to remove the cross-version part if it is redundant with the extra-attributes.
So parsing
example_2.12_1.0-1.0.0.pom
returns the same module ID as parsingexample-1.0.0.pom
. That isorg.example:example:1.0.0
with extra-attributesscalaVersion:2.12
andsbtVersion:1.0
. All dependencies, in the pom file, are also treated the same. The parsed dependencies ofexample_2.12_1.0-1.0.0.pom
are the same as the ones ofexample-1.0.0.pom
. Thus the conflict resolution is working well: sbt can resolve conflicts between old and new poms, old and new dependencies.Tests
To test these changes thoroughly I created a diamond graph of sbt plugins:
I published the artifacts to Maven Central:
Depending on the version of
sbt-plugin-example-diamond
, from0.1.0
to0.5.0
, different parts have migrated to the new pattern, and there can be conflict resolution onsbt-plugin-example-bottom
. See the scripteddependency-management/sbt-plugin-diamond
for more details.sbt-plugin-example-diamond:0.5.0
is fully migrated to the valid Maven pattern. Hence Maven can resolve its full graph of dependencies, and resolve the conflict onsbt-plugin-example-bottom
.The Maven-style publication is tested in the scripted
dependency-management/sbt-plugin-publish
.Next Steps
org.example:example_2.12_1.0:1.0.0
. We probably still want to resolve older plugins though, so it may not be possible to remove the resolution fallback and the extra-attributes mechanism.CrossVersion
mechanism to publish sbt plugin, similarly to Scala.js or Scala Native artifacts. The cross version would then be something like_sbt2_3
.