From 00c4ffb4cef60c15873b23fcd3ccd68c6e9300ad Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 20 Jun 2024 21:08:08 +0200 Subject: [PATCH 1/2] Support "pom" packaging type in `PublishModule` Added new `PublishModuleTests` test suite and moved all publish test there. Fix https://github.com/com-lihaoyi/mill/issues/3206 --- .../src/mill/scalalib/PublishModule.scala | 49 ++-- scalalib/src/mill/scalalib/publish/Pom.scala | 19 +- .../src/mill/scalalib/publish/settings.scala | 8 +- .../publish/core/resources/dummy.txt | 1 + .../src/mill/scalalib/HelloWorldTests.scala | 113 --------- .../mill/scalalib/PublishModuleTests.scala | 215 ++++++++++++++++++ .../src/mill/scalalib/publish/PomTests.scala | 2 +- 7 files changed, 278 insertions(+), 129 deletions(-) create mode 100644 scalalib/test/resources/publish/core/resources/dummy.txt create mode 100644 scalalib/test/src/mill/scalalib/PublishModuleTests.scala diff --git a/scalalib/src/mill/scalalib/PublishModule.scala b/scalalib/src/mill/scalalib/PublishModule.scala index 38cc609616b..cf5a943bee8 100644 --- a/scalalib/src/mill/scalalib/PublishModule.scala +++ b/scalalib/src/mill/scalalib/PublishModule.scala @@ -25,6 +25,11 @@ trait PublishModule extends JavaModule { outer => ) } + /** + * The packaging type. See [[PackagingType]] for specially handled values. + */ + def pomPackagingType: String = PackagingType.Jar + /** * Configuration for the `pom.xml` metadata file published with this module */ @@ -76,8 +81,14 @@ trait PublishModule extends JavaModule { outer => } def pom: Target[PathRef] = T { - val pom = - Pom(artifactMetadata(), publishXmlDeps(), artifactId(), pomSettings(), publishProperties()) + val pom = Pom( + artifactMetadata(), + publishXmlDeps(), + artifactId(), + pomSettings(), + publishProperties(), + packagingType = pomPackagingType + ) val pomPath = T.dest / s"${artifactId()}-${publishVersion()}.pom" os.write.over(pomPath, pom) PathRef(pomPath) @@ -182,17 +193,29 @@ trait PublishModule extends JavaModule { outer => def sonatypeSnapshotUri: String = "https://oss.sonatype.org/content/repositories/snapshots" - def publishArtifacts = T { - val baseName = s"${artifactId()}-${publishVersion()}" - PublishModule.PublishData( - artifactMetadata(), - Seq( - jar() -> s"$baseName.jar", - sourceJar() -> s"$baseName-sources.jar", - docJar() -> s"$baseName-javadoc.jar", - pom() -> s"$baseName.pom" - ) ++ extraPublish().map(p => (p.file, s"$baseName${p.classifierPart}.${p.ext}")) - ) + def publishArtifacts: T[PublishModule.PublishData] = { + val baseNameTask: Task[String] = T.task { s"${artifactId()}-${publishVersion()}" } + val defaultPayloadTask: Task[Seq[(PathRef, String)]] = pomPackagingType match { + case PackagingType.Pom => T.task { Seq.empty[(PathRef, String)] } + case PackagingType.Jar | _ => T.task { + val baseName = baseNameTask() + Seq( + jar() -> s"$baseName.jar", + sourceJar() -> s"$baseName-sources.jar", + docJar() -> s"$baseName-javadoc.jar", + pom() -> s"$baseName.pom" + ) + } + } + T { + val baseName = baseNameTask() + PublishModule.PublishData( + meta = artifactMetadata(), + payload = defaultPayloadTask() ++ extraPublish().map(p => + (p.file, s"$baseName${p.classifierPart}.${p.ext}") + ) + ) + } } /** diff --git a/scalalib/src/mill/scalalib/publish/Pom.scala b/scalalib/src/mill/scalalib/publish/Pom.scala index 9e7fd2c51b1..ab39a88b81f 100644 --- a/scalalib/src/mill/scalalib/publish/Pom.scala +++ b/scalalib/src/mill/scalalib/publish/Pom.scala @@ -25,12 +25,29 @@ object Pom { } } + @deprecated("Use overload with packagingType parameter instead", "Mill 0.11.8") def apply( artifact: Artifact, dependencies: Agg[Dependency], name: String, pomSettings: PomSettings, properties: Map[String, String] + ): String = apply( + artifact = artifact, + dependencies = dependencies, + name = name, + pomSettings = pomSettings, + properties = properties, + packagingType = pomSettings.packaging + ) + + def apply( + artifact: Artifact, + dependencies: Agg[Dependency], + name: String, + pomSettings: PomSettings, + properties: Map[String, String], + packagingType: String ): String = { val xml = {name} {artifact.group} {artifact.id} - {pomSettings.packaging} + {packagingType} {pomSettings.description} {artifact.version} diff --git a/scalalib/src/mill/scalalib/publish/settings.scala b/scalalib/src/mill/scalalib/publish/settings.scala index 98f2fe4fa6f..6448f047e69 100644 --- a/scalalib/src/mill/scalalib/publish/settings.scala +++ b/scalalib/src/mill/scalalib/publish/settings.scala @@ -69,5 +69,11 @@ case class PomSettings( licenses: Seq[License], versionControl: VersionControl, developers: Seq[Developer], - packaging: String = "jar" + @deprecated("Value will be ignored. Use PublishModule.pomPackageingType instead", "Mill 0.11.8") + packaging: String = PackagingType.Jar ) + +object PackagingType { + val Pom = "pom" + val Jar = "jar" +} diff --git a/scalalib/test/resources/publish/core/resources/dummy.txt b/scalalib/test/resources/publish/core/resources/dummy.txt new file mode 100644 index 00000000000..2995a4d0e74 --- /dev/null +++ b/scalalib/test/resources/publish/core/resources/dummy.txt @@ -0,0 +1 @@ +dummy \ No newline at end of file diff --git a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index e268b9580c7..115091819be 100644 --- a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -4,12 +4,10 @@ import java.io.{ByteArrayOutputStream, PrintStream} import java.util.jar.JarFile import scala.jdk.CollectionConverters._ import scala.util.{Properties, Using} -import scala.xml.NodeSeq import mill._ import mill.api.Result import mill.define.NamedTask import mill.eval.{Evaluator, EvaluatorPaths} -import mill.scalalib.publish.{VersionControl, _} import mill.util.{TestEvaluator, TestUtil} import utest._ import utest.framework.TestPath @@ -213,27 +211,6 @@ object HelloWorldTests extends TestSuite { } } - object HelloWorldWithPublish extends HelloBase { - object core extends HelloWorldModule with PublishModule { - override def artifactName = "hello-world" - override def publishVersion = "0.0.1" - override def pomSettings = PomSettings( - organization = "com.lihaoyi", - description = "hello world ready for real world publishing", - url = "https://github.com/lihaoyi/hello-world-publish", - licenses = Seq(License.Common.Apache2), - versionControl = VersionControl.github("lihaoyi", "hello-world-publish"), - developers = - Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi")) - ) - override def versionScheme = Some(VersionScheme.EarlySemVer) - - def checkSonatypeCreds(sonatypeCreds: String) = T.command { - PublishModule.checkSonatypeCreds(sonatypeCreds) - } - } - } - object HelloWorldScalaOverride extends HelloBase { object core extends HelloWorldModule { override def scalaVersion: Target[String] = scala213Version @@ -1340,97 +1317,7 @@ object HelloWorldTests extends TestSuite { assert(evalCount > 0) } - "pom" - { - "should include scala-library dependency" - workspaceTest(HelloWorldWithPublish) { eval => - val Right((result, evalCount)) = eval.apply(HelloWorldWithPublish.core.pom) - - assert( - os.exists(result.path), - evalCount > 0 - ) - val pomXml = scala.xml.XML.loadFile(result.path.toString) - val scalaLibrary = pomXml \ "dependencies" \ "dependency" - assert( - (scalaLibrary \ "artifactId").text == "scala-library", - (scalaLibrary \ "groupId").text == "org.scala-lang" - ) - } - "versionScheme" - workspaceTest(HelloWorldWithPublish) { eval => - val Right((result, evalCount)) = eval.apply(HelloWorldWithPublish.core.pom) - - assert( - os.exists(result.path), - evalCount > 0 - ) - - val pomXml = scala.xml.XML.loadFile(result.path.toString) - val versionScheme = pomXml \ "properties" \ "info.versionScheme" - assert(versionScheme.text == "early-semver") - } - } - - "publish" - { - "should retrieve credentials from environment variables if direct argument is empty" - workspaceTest( - HelloWorldWithPublish, - env = Evaluator.defaultEnv ++ Seq( - "SONATYPE_USERNAME" -> "user", - "SONATYPE_PASSWORD" -> "password" - ) - ) { eval => - val Right((credentials, evalCount)) = - eval.apply(HelloWorldWithPublish.core.checkSonatypeCreds("")) - - assert( - credentials == "user:password", - evalCount > 0 - ) - } - "should prefer direct argument as credentials over environment variables" - workspaceTest( - HelloWorldWithPublish, - env = Evaluator.defaultEnv ++ Seq( - "SONATYPE_USERNAME" -> "user", - "SONATYPE_PASSWORD" -> "password" - ) - ) { eval => - val directValue = "direct:value" - val Right((credentials, evalCount)) = - eval.apply(HelloWorldWithPublish.core.checkSonatypeCreds(directValue)) - - assert( - credentials == directValue, - evalCount > 0 - ) - } - "should throw exception if neither environment variables or direct argument were not passed" - workspaceTest( - HelloWorldWithPublish - ) { eval => - val Left(Result.Failure(msg, None)) = - eval.apply(HelloWorldWithPublish.core.checkSonatypeCreds("")) - - assert( - msg.contains("Consider using SONATYPE_USERNAME/SONATYPE_PASSWORD environment variables") - ) - } - } - - "ivy" - { - "should include scala-library dependency" - workspaceTest(HelloWorldWithPublish) { eval => - val Right((result, evalCount)) = eval.apply(HelloWorldWithPublish.core.ivy) - - assert( - os.exists(result.path), - evalCount > 0 - ) - - val ivyXml = scala.xml.XML.loadFile(result.path.toString) - val deps: NodeSeq = (ivyXml \ "dependencies" \ "dependency") - assert(deps.exists(n => - (n \ "@conf").text == "compile->default(compile)" && - (n \ "@name").text == "scala-library" && (n \ "@org").text == "org.scala-lang" - )) - } - } "replAmmoniteMainClass" - workspaceTest(AmmoniteReplMainClass) { eval => val Right((oldResult, _)) = eval.apply(AmmoniteReplMainClass.oldAmmonite.ammoniteMainClass) diff --git a/scalalib/test/src/mill/scalalib/PublishModuleTests.scala b/scalalib/test/src/mill/scalalib/PublishModuleTests.scala new file mode 100644 index 00000000000..50961ecf539 --- /dev/null +++ b/scalalib/test/src/mill/scalalib/PublishModuleTests.scala @@ -0,0 +1,215 @@ +package mill.scalalib + +import mill.{Agg, T} +import mill.api.{PathRef, Result} +import mill.eval.Evaluator +import mill.scalalib.publish.{ + Developer, + License, + PackagingType, + PomSettings, + VersionControl, + VersionScheme +} +import mill.util.{TestEvaluator, TestUtil} +import utest._ +import utest.framework.TestPath + +import java.io.PrintStream +import scala.xml.NodeSeq + +object PublishModuleTests extends TestSuite { + + val scala212Version = sys.props.getOrElse("TEST_SCALA_2_12_VERSION", ???) + + trait PublishBase extends TestUtil.BaseModule { + override def millSourcePath: os.Path = + TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.') + } + + trait HelloScalaModule extends ScalaModule { + def scalaVersion = scala212Version + override def semanticDbVersion: T[String] = T { + // The latest semanticDB release for Scala 2.12.6 + "4.1.9" + } + } + + object HelloWorldWithPublish extends PublishBase { + object core extends HelloScalaModule with PublishModule { + override def artifactName = "hello-world" + override def publishVersion = "0.0.1" + override def pomSettings = PomSettings( + organization = "com.lihaoyi", + description = "hello world ready for real world publishing", + url = "https://github.com/lihaoyi/hello-world-publish", + licenses = Seq(License.Common.Apache2), + versionControl = VersionControl.github("lihaoyi", "hello-world-publish"), + developers = + Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi")) + ) + override def versionScheme = Some(VersionScheme.EarlySemVer) + + def checkSonatypeCreds(sonatypeCreds: String) = T.command { + PublishModule.checkSonatypeCreds(sonatypeCreds) + } + } + } + + object PomOnly extends PublishBase { + object core extends JavaModule with PublishModule { + override def pomPackagingType: String = PackagingType.Pom + override def artifactName = "pom-only" + override def publishVersion = "0.0.1" + override def pomSettings = PomSettings( + organization = "com.lihaoyi", + description = "pom-only artifacts ready for real world publishing", + url = "https://github.com/lihaoyi/hello-world-publish", + licenses = Seq(License.Common.Apache2), + versionControl = VersionControl.github("lihaoyi", "hello-world-publish"), + developers = + Seq(Developer("lefou", "Tobias Roeser", "https://github.com/lefou")) + ) + override def versionScheme = Some(VersionScheme.EarlySemVer) + override def ivyDeps = Agg( + ivy"org.slf4j:slf4j-api:2.0.7" + ) + // ensure, these target wont be called + override def jar: T[PathRef] = T { ???.asInstanceOf[PathRef] } + override def docJar: T[PathRef] = T { ???.asInstanceOf[PathRef] } + override def sourceJar: T[PathRef] = T { ???.asInstanceOf[PathRef] } + } + } + + val resourcePath = os.pwd / "scalalib" / "test" / "resources" / "publish" + + def workspaceTest[T]( + m: TestUtil.BaseModule, + resourcePath: os.Path = resourcePath, + env: Map[String, String] = Evaluator.defaultEnv, + debug: Boolean = false, + errStream: PrintStream = System.err + )(t: TestEvaluator => T)(implicit tp: TestPath): T = { + val eval = new TestEvaluator(m, env = env, debugEnabled = debug, errStream = errStream) + os.remove.all(m.millSourcePath) + os.remove.all(eval.outPath) + os.makeDir.all(m.millSourcePath / os.up) + os.copy(resourcePath, m.millSourcePath) + t(eval) + } + + def tests: Tests = Tests { + "pom" - { + "should include scala-library dependency" - workspaceTest(HelloWorldWithPublish) { eval => + val Right((result, evalCount)) = eval.apply(HelloWorldWithPublish.core.pom) + + assert( + os.exists(result.path), + evalCount > 0 + ) + + val pomXml = scala.xml.XML.loadFile(result.path.toString) + val scalaLibrary = pomXml \ "dependencies" \ "dependency" + assert( + (pomXml \ "packaging").text == PackagingType.Jar, + (scalaLibrary \ "artifactId").text == "scala-library", + (scalaLibrary \ "groupId").text == "org.scala-lang" + ) + } + "versionScheme" - workspaceTest(HelloWorldWithPublish) { eval => + val Right((result, evalCount)) = eval.apply(HelloWorldWithPublish.core.pom) + + assert( + os.exists(result.path), + evalCount > 0 + ) + + val pomXml = scala.xml.XML.loadFile(result.path.toString) + val versionScheme = pomXml \ "properties" \ "info.versionScheme" + assert(versionScheme.text == "early-semver") + } + } + + "publish" - { + "should retrieve credentials from environment variables if direct argument is empty" - workspaceTest( + HelloWorldWithPublish, + env = Evaluator.defaultEnv ++ Seq( + "SONATYPE_USERNAME" -> "user", + "SONATYPE_PASSWORD" -> "password" + ) + ) { eval => + val Right((credentials, evalCount)) = + eval.apply(HelloWorldWithPublish.core.checkSonatypeCreds("")) + + assert( + credentials == "user:password", + evalCount > 0 + ) + } + "should prefer direct argument as credentials over environment variables" - workspaceTest( + HelloWorldWithPublish, + env = Evaluator.defaultEnv ++ Seq( + "SONATYPE_USERNAME" -> "user", + "SONATYPE_PASSWORD" -> "password" + ) + ) { eval => + val directValue = "direct:value" + val Right((credentials, evalCount)) = + eval.apply(HelloWorldWithPublish.core.checkSonatypeCreds(directValue)) + + assert( + credentials == directValue, + evalCount > 0 + ) + } + "should throw exception if neither environment variables or direct argument were not passed" - workspaceTest( + HelloWorldWithPublish + ) { eval => + val Left(Result.Failure(msg, None)) = + eval.apply(HelloWorldWithPublish.core.checkSonatypeCreds("")) + + assert( + msg.contains("Consider using SONATYPE_USERNAME/SONATYPE_PASSWORD environment variables") + ) + } + } + + "ivy" - { + "should include scala-library dependency" - workspaceTest(HelloWorldWithPublish) { eval => + val Right((result, evalCount)) = eval.apply(HelloWorldWithPublish.core.ivy) + + assert( + os.exists(result.path), + evalCount > 0 + ) + + val ivyXml = scala.xml.XML.loadFile(result.path.toString) + val deps: NodeSeq = (ivyXml \ "dependencies" \ "dependency") + assert(deps.exists(n => + (n \ "@conf").text == "compile->default(compile)" && + (n \ "@name").text == "scala-library" && (n \ "@org").text == "org.scala-lang" + )) + } + } + + test("pom-packaging-type") - { + test("pom") - workspaceTest(PomOnly) { eval => + val Right((result, evalCount)) = eval.apply(PomOnly.core.pom) +// +// assert( +// os.exists(result.path), +// evalCount > 0 +// ) +// +// val pomXml = scala.xml.XML.loadFile(result.path.toString) +// val scalaLibrary = pomXml \ "dependencies" \ "dependency" +// assert( +// (pomXml \ "packaging").text == PackagingType.Pom, +// (scalaLibrary \ "artifactId").text == "slf4j-api", +// (scalaLibrary \ "groupId").text == "org.slf4j" +// ) + } + } + } + +} diff --git a/scalalib/test/src/mill/scalalib/publish/PomTests.scala b/scalalib/test/src/mill/scalalib/publish/PomTests.scala index dec0ae60d6b..e8abed981db 100644 --- a/scalalib/test/src/mill/scalalib/publish/PomTests.scala +++ b/scalalib/test/src/mill/scalalib/publish/PomTests.scala @@ -216,7 +216,7 @@ object PomTests extends TestSuite { pomSettings: PomSettings, properties: Map[String, String] ) = - XML.loadString(Pom(artifact, dependencies, artifactId, pomSettings, properties)) + XML.loadString(Pom(artifact, dependencies, artifactId, pomSettings, properties, PackagingType.Jar)) def singleText(seq: NodeSeq) = seq From b39f57216adfbded6ced8ee7344f0eae0579a557 Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 20 Jun 2024 21:18:06 +0200 Subject: [PATCH 2/2] scalafmt --- scalalib/test/src/mill/scalalib/HelloWorldTests.scala | 2 -- scalalib/test/src/mill/scalalib/publish/PomTests.scala | 9 ++++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index 115091819be..f752590c28e 100644 --- a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -1317,8 +1317,6 @@ object HelloWorldTests extends TestSuite { assert(evalCount > 0) } - - "replAmmoniteMainClass" - workspaceTest(AmmoniteReplMainClass) { eval => val Right((oldResult, _)) = eval.apply(AmmoniteReplMainClass.oldAmmonite.ammoniteMainClass) assert(oldResult == "ammonite.Main") diff --git a/scalalib/test/src/mill/scalalib/publish/PomTests.scala b/scalalib/test/src/mill/scalalib/publish/PomTests.scala index e8abed981db..d1b52b602aa 100644 --- a/scalalib/test/src/mill/scalalib/publish/PomTests.scala +++ b/scalalib/test/src/mill/scalalib/publish/PomTests.scala @@ -216,7 +216,14 @@ object PomTests extends TestSuite { pomSettings: PomSettings, properties: Map[String, String] ) = - XML.loadString(Pom(artifact, dependencies, artifactId, pomSettings, properties, PackagingType.Jar)) + XML.loadString(Pom( + artifact, + dependencies, + artifactId, + pomSettings, + properties, + PackagingType.Jar + )) def singleText(seq: NodeSeq) = seq