From a6bd3dbe0f9f6d58326f0ffaa0737d07d5a3821f Mon Sep 17 00:00:00 2001 From: Guillaume Massé Date: Thu, 1 Mar 2018 05:28:48 +0100 Subject: Add dsl for SCM (now called VersionControl) (#168) The scm url syntax is a source of confusion for developper. I added VersionControl.github() to simplify this process. We can add other common VersionControl url scheme like Bazar, etc. --- .../src/mill/scalalib/publish/JsonFormatters.scala | 2 +- scalalib/src/mill/scalalib/publish/Pom.scala | 26 +++- scalalib/src/mill/scalalib/publish/settings.scala | 140 ++++++++++++++++++++- .../test/src/mill/scalalib/HelloWorldTests.scala | 6 +- 4 files changed, 165 insertions(+), 9 deletions(-) (limited to 'scalalib') diff --git a/scalalib/src/mill/scalalib/publish/JsonFormatters.scala b/scalalib/src/mill/scalalib/publish/JsonFormatters.scala index cf1af557..8fc90632 100644 --- a/scalalib/src/mill/scalalib/publish/JsonFormatters.scala +++ b/scalalib/src/mill/scalalib/publish/JsonFormatters.scala @@ -6,6 +6,6 @@ trait JsonFormatters { implicit lazy val artifactFormat: RW[Artifact] = upickle.default.macroRW implicit lazy val developerFormat: RW[Developer] = upickle.default.macroRW implicit lazy val licenseFormat: RW[License] = upickle.default.macroRW - implicit lazy val scmFormat: RW[SCM] = upickle.default.macroRW + implicit lazy val versionControlFormat: RW[VersionControl] = upickle.default.macroRW implicit lazy val pomSettingsFormat: RW[PomSettings] = upickle.default.macroRW } diff --git a/scalalib/src/mill/scalalib/publish/Pom.scala b/scalalib/src/mill/scalalib/publish/Pom.scala index 895e1686..382db56a 100644 --- a/scalalib/src/mill/scalalib/publish/Pom.scala +++ b/scalalib/src/mill/scalalib/publish/Pom.scala @@ -2,7 +2,7 @@ package mill.scalalib.publish import mill.util.Loose.Agg -import scala.xml.{Elem, NodeSeq, PrettyPrinter} +import scala.xml.{Atom, Elem, NodeSeq, PrettyPrinter} object Pom { @@ -13,6 +13,24 @@ object Pom { dependencies: Agg[Dependency], name: String, pomSettings: PomSettings): String = { + + // source: https://stackoverflow.com/a/5254068/449071 + implicit def optionElem(e: Elem) = new { + def optionnal : NodeSeq = { + require(e.child.length == 1) + e.child.head match { + case atom: Atom[Option[_]] => atom.data match { + case None => NodeSeq.Empty + case Some(x) => e.copy(child = x match { + case n: NodeSeq => n + case x => new Atom(x) + }) + } + case _ => e + } + } + } + val xml = - {pomSettings.scm.url} - {pomSettings.scm.connection} + {pomSettings.versionControl.connection}.optionnal + {pomSettings.versionControl.developerConnection}.optionnal + {pomSettings.versionControl.tag}.optionnal + {pomSettings.versionControl.browsableRepository}.optionnal {pomSettings.developers.map(renderDeveloper)} diff --git a/scalalib/src/mill/scalalib/publish/settings.scala b/scalalib/src/mill/scalalib/publish/settings.scala index 0327b132..665e0ed6 100644 --- a/scalalib/src/mill/scalalib/publish/settings.scala +++ b/scalalib/src/mill/scalalib/publish/settings.scala @@ -52,11 +52,125 @@ case class Dependency( scope: Scope ) +// https://maven.apache.org/pom.html#SCM +/* + * @param browsableRepository: a publicly browsable repository + * (example: https://github.com/lihaoyi/mill) + * @param connection: read-only connection to repository + * (example: scm:git:git://github.com/lihaoyi/mill.git) + * @param developerConnection: read-write connection to repository + * (example: scm:git:git@github.com:lihaoyi/mill.git) + * @param tag: tag that was created for this release. This is useful for + * git and mercurial since it's not possible to include the tag in + * the connection url. + * (example: v2.12.4, HEAD, my-branch, fd8a2567ad32c11bcf8adbaca85bdba72bb4f935, ...) + */ +case class VersionControl( + browsableRepository: Option[String] = None, + connection: Option[String] = None, + developerConnection: Option[String] = None, + tag: Option[String] = None +) + +@deprecated("use VersionControl", "0.1.3") case class SCM( url: String, connection: String ) +object VersionControl { + def github(owner: String, repo: String, tag: Option[String] = None): VersionControl = + VersionControl( + browsableRepository = Some(s"https://github.com/$owner/$repo"), + connection = Some(VersionControlConnection.gitGit("github.com", "$owner/$repo.git")), + developerConnection = Some(VersionControlConnection.gitSsh("github.com", "$owner/$repo.git")), + tag = tag + ) +} + +object VersionControlConnection { + def network(scm: String, + protocol: String, + hostname: String, + path: String, + username: Option[String] = None, + password: Option[String] = None, + port: Option[Int] = None): String = { + val portPart = port.map(":" + _).getOrElse("") + val credentials = + username match { + case Some(user) => + val pass = password.map(":" + _).getOrElse("") + s"${user}${pass}" + case None => + password match { + case Some(p) => sys.error(s"no username set for password: $p") + case _ => "" + } + } + + s"${scm}:${protocol}://${credentials}${hostname}${portPart}/$path" + } + + def file(scm: String, hostname: Option[String], path: String): String = { + val hostnamePart = hostname.getOrElse("") + "scm:$scm:file://${hostnamePart}/$path" + } + + def gitGit(hostname: String, + path: String, + port: Option[Int] = None): String = + network("git", "git", hostname, path, port = port) + + def gitHttp(hostname: String, + path: String, + port: Option[Int] = None): String = + network("git", "http", hostname, path, port = port) + + def gitHttps(hostname: String, + path: String, + port: Option[Int] = None): String = + network("git", "https", hostname, path, port = port) + + def gitSsh(hostname: String, + path: String, + port: Option[Int] = None): String = + network("git", "ssh", hostname, path, port = port) + + def gitFile(hostname: Option[String], path: String): String = + file("git", hostname, path) + + def svnSsh(hostname: String, + path: String, + username: Option[String], + port: Option[Int]): String = + network("svn", "svn+ssh", hostname, path, username, None, port) + + def svnHttp(hostname: String, + path: String, + port: Option[Int], + username: Option[String], + password: Option[String]): String = + network("svn", "http", hostname, path, username, password) + + def svnHttps(hostname: String, + path: String, + port: Option[Int], + username: Option[String], + password: Option[String]): String = + network("svn", "https", hostname, path, username, password) + + def svnSvn(username: Option[String], + password: Option[String], + hostname: String, + port: Option[Int], + path: String): String = + network("svn", "svn", hostname, path, username, password) + + def svnFile(hostname: Option[String], path: String): String = + file("svn", hostname, path) +} + case class Developer( id: String, name: String, @@ -70,6 +184,30 @@ case class PomSettings( organization: String, url: String, licenses: Seq[License], - scm: SCM, + versionControl: VersionControl, developers: Seq[Developer] ) + +object PomSettings { + @deprecated("use VersionControl instead of SCM", "0.1.3") + def apply(description: String, + organization: String, + url: String, + licenses: Seq[License], + scm: SCM, + developers: Seq[Developer]): PomSettings = { + PomSettings( + description = description, + organization = organization, + url = url, + licenses = licenses, + versionControl = VersionControl( + browsableRepository = Some(scm.url), + connection = Some(scm.connection), + developerConnection = None, + tag = None + ), + developers = developers + ) + } +} diff --git a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala index 2bb51ad6..4fb5f5a5 100644 --- a/scalalib/test/src/mill/scalalib/HelloWorldTests.scala +++ b/scalalib/test/src/mill/scalalib/HelloWorldTests.scala @@ -9,6 +9,7 @@ import mill.define.{Discover, Target} import mill.eval.{Evaluator, Result} import mill.scalalib.publish._ import mill.util.{TestEvaluator, TestUtil} +import mill.scalalib.publish.VersionControl import utest._ import utest.framework.TestPath @@ -86,10 +87,7 @@ object HelloWorldTests extends TestSuite { description = "hello world ready for real world publishing", url = "https://github.com/lihaoyi/hello-world-publish", licenses = Seq(License.Common.Apache2), - scm = SCM( - "https://github.com/lihaoyi/hello-world-publish", - "scm:git:https://github.com/lihaoyi/hello-world-publish" - ), + versionControl = VersionControl.github("lihaoyi", "hello-world-publish"), developers = Seq(Developer("lihaoyi", "Li Haoyi", "https://github.com/lihaoyi")) ) -- cgit v1.2.3