Skip to content

Commit 36e44a3

Browse files
Support publishing snapshots to central sonatype (#5489)
Sonatype Central has an API for publishing artifact releases. However, that API does not accept snapshots. Instead, they have a Maven API compatible endpoint where SNAPSHOT artifacts should be sent. This PR adds support for publishing SNAPSHOT releases to the Sonatype Central snapshots repository. To do that, it uses [Apache Maven Artifact Resolver](https://maven.apache.org/resolver/) (ex-Eclipse Aether) library. To prevent classpath issues with code that supports `mill init` from Maven repositories (that also uses Maven Artifact Resolver, but a different version of it), a `maven-worker` is introduced. A test has been added, however, because Sonatype API can be flaky and/or incur network errors, it is not run by default. It can be run with `./mill integration.feature[publish-sonatype-central-snapshots]`. You will have to provide your own namespace to publish to, as well as your Sonatype username and password. Resolves #4421 --- This is #5425 without any of the refactoring. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 8b12ce2 commit 36e44a3

File tree

23 files changed

+494
-127
lines changed

23 files changed

+494
-127
lines changed

contrib/artifactory/src/mill/contrib/artifactory/ArtifactoryPublishModule.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ trait ArtifactoryPublishModule extends PublishModule {
2828
readTimeout: Int = 60000,
2929
connectTimeout: Int = 5000
3030
): Command[Unit] = Task.Command {
31-
val PublishModule.PublishData(artifactInfo, artifacts) = publishArtifacts()
31+
val (artifacts, artifactInfo) = publishArtifacts().withConcretePath
3232
new ArtifactoryPublisher(
3333
artifactoryUri,
3434
artifactorySnapshotUri,
3535
checkArtifactoryCreds(credentials)(),
3636
readTimeout,
3737
connectTimeout,
3838
Task.log
39-
).publish(artifacts.map { case (a, b) => (a.path, b) }, artifactInfo)
39+
).publish(artifacts, artifactInfo)
4040
}
4141
}
4242

contrib/codeartifact/src/mill/contrib/codeartifact/CodeartifactPublishModule.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ trait CodeartifactPublishModule extends PublishModule {
1818
connectTimeout: Int = 5000
1919
): Command[Unit] =
2020
Task.Command {
21-
val PublishModule.PublishData(artifactInfo, artifacts) =
22-
publishArtifacts()
21+
val (artifacts, artifactInfo) = publishArtifacts().withConcretePath
2322

2423
new CodeartifactPublisher(
2524
codeartifactUri,
@@ -28,7 +27,7 @@ trait CodeartifactPublishModule extends PublishModule {
2827
readTimeout,
2928
connectTimeout,
3029
Task.log
31-
).publish(artifacts.map { case (a, b) => (a.path, b) }, artifactInfo)
30+
).publish(artifacts, artifactInfo)
3231
}
3332
}
3433

@@ -42,9 +41,7 @@ object CodeartifactPublishModule extends ExternalModule {
4241
connectTimeout: Int = 5000
4342
) =
4443
Task.Command {
45-
val artifacts = Task.sequence(publishArtifacts.value)().map {
46-
case data @ PublishModule.PublishData(_, _) => data.withConcretePath
47-
}
44+
val artifacts = Task.sequence(publishArtifacts.value)().map(_.withConcretePath)
4845
new CodeartifactPublisher(
4946
codeartifactUri,
5047
codeartifactSnapshotUri,

contrib/gitlab/src/mill/contrib/gitlab/GitlabPublishModule.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ trait GitlabPublishModule extends PublishModule { outer =>
3535

3636
val gitlabRepo = publishRepository
3737

38-
val PublishModule.PublishData(artifactInfo, artifacts) = publishArtifacts()
38+
val (artifacts, artifactInfo) = publishArtifacts().withConcretePath
3939
if (skipPublish) {
4040
Task.log.info(s"SkipPublish = true, skipping publishing of $artifactInfo")
4141
} else {
@@ -44,7 +44,7 @@ trait GitlabPublishModule extends PublishModule { outer =>
4444
uploader.upload,
4545
gitlabRepo,
4646
Task.log
47-
).publish(artifacts.map { case (a, b) => (a.path, b) }, artifactInfo)
47+
).publish(artifacts, artifactInfo)
4848
}
4949

5050
}

example/javalib/publishing/9-publish-module-sonatype/build.mill

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,11 @@ object foo extends JavaModule, SonatypeCentralPublishModule {
1818
developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi"))
1919
)
2020
}
21+
22+
// If the `publishVersion` ends with `SNAPSHOT`, then the artifacts will NOT be signed and will be
23+
// published as a snapshot, which allows overwriting it at a later date. Mill takes care of timestamping
24+
// the snapshots and updating the appropriate `maven-metadata.xml` file to point to the latest snapshot version.
25+
//
26+
// **Note that for this to work you MUST
27+
// https://central.sonatype.org/publish/publish-portal-snapshots/#enabling-snapshot-releases-for-your-namespace[
28+
// enable SNAPSHOTs for your namespace in Sonatype Central].**
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package build
2+
3+
import mill._, scalalib._, publish._
4+
5+
object testProject extends ScalaModule with SonatypeCentralPublishModule {
6+
def scalaVersion = "3.3.6"
7+
def publishVersion = "0.0.1-SNAPSHOT"
8+
9+
def publishOrganization = Task.Input {
10+
sys.env.get("MILL_TESTS_PUBLISH_ORG").getOrElse(
11+
throw new Exception("MILL_TESTS_PUBLISH_ORG is not set")
12+
)
13+
}
14+
15+
def pomSettings = Task {
16+
PomSettings(
17+
description = "Hello",
18+
organization = publishOrganization(),
19+
url = "https://github.com/lihaoyi/example",
20+
licenses = Seq(License.MIT),
21+
versionControl = VersionControl.github("lihaoyi", "example"),
22+
developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi"))
23+
)
24+
}
25+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package foo
2+
3+
object Foo {
4+
def main(args: Array[String]): Unit = {
5+
println("Hello World")
6+
}
7+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import mill.javalib.publish.SonatypeHelpers
2+
import mill.testkit.UtestIntegrationTestSuite
3+
import utest._
4+
import SonatypeHelpers.{USERNAME_ENV_VARIABLE_NAME, PASSWORD_ENV_VARIABLE_NAME}
5+
6+
object PublishSonatypeCentralSnapshotTests extends UtestIntegrationTestSuite {
7+
val tests: Tests = Tests {
8+
test("publish") - integrationTest { tester =>
9+
import tester.*
10+
11+
val PUBLISH_ORG_ENV_VARIABLE_NAME = "MILL_TESTS_PUBLISH_ORG"
12+
13+
val env = sys.env
14+
val maybePublishOrg = env.get(PUBLISH_ORG_ENV_VARIABLE_NAME)
15+
val maybePublishUsername = env.get(USERNAME_ENV_VARIABLE_NAME)
16+
val maybePublishPassword = env.get(PASSWORD_ENV_VARIABLE_NAME)
17+
18+
(maybePublishOrg, maybePublishUsername, maybePublishPassword) match {
19+
case (Some(publishOrg), Some(publishUsername), Some(publishPassword)) =>
20+
val res = eval(
21+
"testProject.publishSonatypeCentral",
22+
env = Map(
23+
PUBLISH_ORG_ENV_VARIABLE_NAME -> publishOrg,
24+
USERNAME_ENV_VARIABLE_NAME -> publishUsername,
25+
PASSWORD_ENV_VARIABLE_NAME -> publishPassword
26+
)
27+
)
28+
println(
29+
s"""Success: ${res.isSuccess}
30+
|
31+
|stdout:
32+
|${res.out}
33+
|
34+
|stderr:
35+
|${res.err}
36+
|""".stripMargin
37+
)
38+
// Extract the values so that `assert` macro would print them out nicely if the test fails
39+
// instead of printing `res` twice.
40+
val isSuccess = res.isSuccess
41+
val err = res.err
42+
assert(isSuccess && err.contains("finished with result:"))
43+
44+
case _ =>
45+
case class WithName[A](name: String, description: String, value: A)
46+
val missingEnvVars = Vector(
47+
WithName(
48+
PUBLISH_ORG_ENV_VARIABLE_NAME,
49+
"The organization to publish to",
50+
maybePublishOrg
51+
),
52+
WithName(USERNAME_ENV_VARIABLE_NAME, "Sonatype Central username", maybePublishUsername),
53+
WithName(PASSWORD_ENV_VARIABLE_NAME, "Sonatype Central password", maybePublishPassword)
54+
).filter(_.value.isEmpty).map(v => s"${v.name} (${v.description})")
55+
56+
println(
57+
s"""Test is disabled because the following environment variables are not set:
58+
|${missingEnvVars.mkString("\n")}""".stripMargin
59+
)
60+
}
61+
}
62+
}
63+
}

integration/ide/gen-idea/resources/extended/idea/mill_modules/mill-build.iml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<orderEntry type="library" name="hamcrest-core-1.3.jar" level="project"/>
3838
<orderEntry type="library" name="io_2.13-4.13.4.jar" level="project"/>
3939
<orderEntry type="library" scope="RUNTIME" name="is-terminal-0.1.2.jar" level="project"/>
40-
<orderEntry type="library" scope="RUNTIME" name="jansi-2.4.1.jar" level="project"/>
40+
<orderEntry type="library" scope="RUNTIME" name="jansi<!-- IGNORE -->.jar" level="project"/>
4141
<orderEntry type="library" name="java-diff-utils-4.12.jar" level="project"/>
4242
<orderEntry type="library" scope="RUNTIME" name="javax.inject-1.jar" level="project"/>
4343
<orderEntry type="library" scope="RUNTIME" name="jcl-over-slf4j-1.7.30.jar" level="project"/>
@@ -113,9 +113,9 @@
113113
<orderEntry type="library" name="semanticdb-shared_2.13-4.13.4.jar" level="project"/>
114114
<orderEntry type="library" scope="RUNTIME" name="slf4j-api-2.0.17.jar" level="project"/>
115115
<orderEntry type="library" scope="RUNTIME" name="snakeyaml-engine-2.9.jar" level="project"/>
116-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-core_3-0.3.0.jar" level="project"/>
117-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-requests_3-0.3.0.jar" level="project"/>
118-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-upickle_3-0.3.0.jar" level="project"/>
116+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-core_3-0.5.0.jar" level="project"/>
117+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-requests_3-0.5.0.jar" level="project"/>
118+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-upickle_3-0.5.0.jar" level="project"/>
119119
<orderEntry type="library" name="sourcecode_2.13-0.4.2.jar" level="project"/>
120120
<orderEntry type="library" name="sourcecode_3-0.4.3-M5.jar" level="project"/>
121121
<orderEntry type="library" scope="RUNTIME" name="specification-level_2.13-1.1.3.jar" level="project"/>

integration/ide/gen-idea/resources/extended/idea/mill_modules/mill-build.mill-build.iml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<orderEntry type="library" scope="RUNTIME" name="graphviz-java-min-deps-0.18.1.jar" level="project"/>
4141
<orderEntry type="library" name="io_2.13-4.13.4.jar" level="project"/>
4242
<orderEntry type="library" scope="RUNTIME" name="is-terminal-0.1.2.jar" level="project"/>
43-
<orderEntry type="library" scope="RUNTIME" name="jansi-2.4.1.jar" level="project"/>
43+
<orderEntry type="library" scope="RUNTIME" name="jansi<!-- IGNORE -->.jar" level="project"/>
4444
<orderEntry type="library" name="java-diff-utils-4.12.jar" level="project"/>
4545
<orderEntry type="library" scope="RUNTIME" name="javax.inject-1.jar" level="project"/>
4646
<orderEntry type="library" scope="RUNTIME" name="jcl-over-slf4j-1.7.30.jar" level="project"/>
@@ -115,9 +115,9 @@
115115
<orderEntry type="library" name="semanticdb-shared_2.13-4.13.4.jar" level="project"/>
116116
<orderEntry type="library" scope="RUNTIME" name="slf4j-api-2.0.17.jar" level="project"/>
117117
<orderEntry type="library" name="snakeyaml-engine-2.9.jar" level="project"/>
118-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-core_3-0.3.0.jar" level="project"/>
119-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-requests_3-0.3.0.jar" level="project"/>
120-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-upickle_3-0.3.0.jar" level="project"/>
118+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-core_3-0.5.0.jar" level="project"/>
119+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-requests_3-0.5.0.jar" level="project"/>
120+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-upickle_3-0.5.0.jar" level="project"/>
121121
<orderEntry type="library" name="sourcecode_2.13-0.4.2.jar" level="project"/>
122122
<orderEntry type="library" name="sourcecode_3-0.4.3-M5.jar" level="project"/>
123123
<orderEntry type="library" scope="RUNTIME" name="specification-level_2.13-1.1.3.jar" level="project"/>

integration/ide/gen-idea/resources/hello-idea/idea/mill_modules/mill-build.iml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<orderEntry type="library" scope="RUNTIME" name="graphviz-java-min-deps-0.18.1.jar" level="project"/>
3737
<orderEntry type="library" name="io_2.13-4.13.4.jar" level="project"/>
3838
<orderEntry type="library" scope="RUNTIME" name="is-terminal-0.1.2.jar" level="project"/>
39-
<orderEntry type="library" scope="RUNTIME" name="jansi-2.4.1.jar" level="project"/>
39+
<orderEntry type="library" scope="RUNTIME" name="jansi<!-- IGNORE -->.jar" level="project"/>
4040
<orderEntry type="library" name="java-diff-utils-4.12.jar" level="project"/>
4141
<orderEntry type="library" scope="RUNTIME" name="javax.inject-1.jar" level="project"/>
4242
<orderEntry type="library" scope="RUNTIME" name="jcl-over-slf4j-1.7.30.jar" level="project"/>
@@ -109,9 +109,9 @@
109109
<orderEntry type="library" name="semanticdb-shared_2.13-4.13.4.jar" level="project"/>
110110
<orderEntry type="library" scope="RUNTIME" name="slf4j-api-2.0.17.jar" level="project"/>
111111
<orderEntry type="library" scope="RUNTIME" name="snakeyaml-engine-2.9.jar" level="project"/>
112-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-core_3-0.3.0.jar" level="project"/>
113-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-requests_3-0.3.0.jar" level="project"/>
114-
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-upickle_3-0.3.0.jar" level="project"/>
112+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-core_3-0.5.0.jar" level="project"/>
113+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-requests_3-0.5.0.jar" level="project"/>
114+
<orderEntry type="library" scope="RUNTIME" name="sonatype-central-client-upickle_3-0.5.0.jar" level="project"/>
115115
<orderEntry type="library" name="sourcecode_2.13-0.4.2.jar" level="project"/>
116116
<orderEntry type="library" name="sourcecode_3-0.4.3-M5.jar" level="project"/>
117117
<orderEntry type="library" scope="RUNTIME" name="specification-level_2.13-1.1.3.jar" level="project"/>

0 commit comments

Comments
 (0)