Added support for providing basic SCM info

Sonatype OSS repo (where many libraries are expected to migrate) requires
populating SCM info in additional to what is already provisioned for
populating in SBT.

We now support populating the basic SCM info as thus:
```
// Usual <scm><url/><connection/></scm>
scmInfo := Some(ScmInfo(url("https://github.com/foo/project"), "scm:git:https://github.com/foo/project.git"))

// Also add <developerConnection/>
scmInfo := Some(ScmInfo(url("https://github.com/foo/project"), "scm:git:https://github.com/foo/project.git", Some("dev_connection")))
```
For anything more esoteric than the basic info, there is always `pomPostProcess` :)
This commit is contained in:
Indrajit Raychaudhuri 2012-02-28 15:18:46 +05:30
parent 45eacbad4c
commit ea08f86520
4 changed files with 29 additions and 9 deletions

View File

@ -17,9 +17,9 @@ final case class ModuleID(organization: String, name: String, revision: String,
(if(extraAttributes.isEmpty) "" else " " + extraString)
def extraString = extraAttributes.map { case (k,v) => k + "=" + v } mkString("(",", ",")")
@deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0")
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
def cross(v: Boolean): ModuleID = cross(if(v) CrossVersion.binary else CrossVersion.Disabled)
@deprecated("Use the variant accepting a CrossVersion value constructed by a member of the CrossVersion object.", "0.12.0")
@deprecated("Use `cross(CrossVersion)`, the variant accepting a CrossVersion value constructed by a member of the CrossVersion object instead.", "0.12.0")
def cross(v: Boolean, verRemap: String => String): ModuleID = cross(if(v) CrossVersion.binaryMapped(verRemap) else CrossVersion.Disabled)
def cross(v: CrossVersion): ModuleID = copy(crossVersion = v)
@ -49,13 +49,15 @@ object ModuleID
if(key.startsWith("e:")) (key, value) else ("e:" + key, value)
}
/** Additional information about a project module */
case class ModuleInfo(nameFormal: String, description: String = "", homepage: Option[URL] = None, startYear: Option[Int] = None, licenses: Seq[(String, URL)] = Nil, organizationName: String = "", organizationHomepage: Option[URL] = None)
case class ModuleInfo(nameFormal: String, description: String = "", homepage: Option[URL] = None, startYear: Option[Int] = None, licenses: Seq[(String, URL)] = Nil, organizationName: String = "", organizationHomepage: Option[URL] = None, scmInfo: Option[ScmInfo] = None)
{
def formally(name: String) = copy(nameFormal = name)
def describing(desc: String, home: Option[URL]) = copy(description = desc, homepage = home)
def licensed(lics: (String, URL)*) = copy(licenses = lics)
def organization(name: String, home: Option[URL]) = copy(organizationName = name, organizationHomepage = home)
}
/** Basic SCM information for a project module */
case class ScmInfo(browseUrl: URL, connection: String, devConnection: Option[String] = None)
/** Rule to exclude unwanted dependencies pulled in transitively by a module. */
case class ExclusionRule(organization: String = "*", name: String = "*", artifact: String = "*", configurations: Seq[String] = Nil)
sealed trait Resolver
@ -428,7 +430,7 @@ object Artifact
}
def artifactName(scalaVersion: ScalaVersion, module: ModuleID, artifact: Artifact): String =
{
import artifact._
import artifact._
val classifierStr = classifier match { case None => ""; case Some(c) => "-" + c }
val cross = CrossVersion(module.crossVersion, scalaVersion.full, scalaVersion.binary)
val base = CrossVersion.applyCross(artifact.name, cross)

View File

@ -44,6 +44,7 @@ class MakePom(val log: Logger)
<name>{moduleInfo.nameFormal}</name>
{ makeStartYear(moduleInfo) }
{ makeOrganization(moduleInfo) }
{ makeScmInfo(moduleInfo) }
{ extra }
{
val deps = depsInConfs(module, configurations)
@ -83,6 +84,21 @@ class MakePom(val log: Logger)
}}
</organization>
}
def makeScmInfo(moduleInfo: ModuleInfo): NodeSeq =
{
moduleInfo.scmInfo match {
case Some(s) =>
<scm>
<url>{s.browseUrl}</url>
<connection>{s.connection}</connection>
{s.devConnection match {
case Some(d) => <developerConnection>{d}</developerConnection>
case _ => NodeSeq.Empty
}}
</scm>
case _ => NodeSeq.Empty
}
}
def makeProperties(module: ModuleDescriptor, dependencies: Seq[DependencyDescriptor]): NodeSeq =
{
val extra = IvySbt.getExtraAttributes(module)

View File

@ -715,7 +715,8 @@ object Classpaths
organization <<= organization or normalizedName,
organizationName <<= organizationName or organization,
organizationHomepage <<= organizationHomepage or homepage,
projectInfo <<= (name, description, homepage, startYear, licenses, organizationName, organizationHomepage) apply ModuleInfo,
scmInfo in GlobalScope :== None,
projectInfo <<= (name, description, homepage, startYear, licenses, organizationName, organizationHomepage, scmInfo) apply ModuleInfo,
externalResolvers <<= (externalResolvers.task.?, resolvers) {
case (Some(delegated), Seq()) => delegated
case (_, rs) => task { Resolver.withDefaultResolvers(rs) }

View File

@ -197,10 +197,10 @@ object Keys
val testListeners = TaskKey[Seq[TestReportListener]]("test-listeners", "Defines test listeners.")
val testExecution = TaskKey[Tests.Execution]("test-execution", "Settings controlling test execution")
val isModule = AttributeKey[Boolean]("is-module", "True if the target is a module.")
// Classpath/Dependency Management Keys
type Classpath = Seq[Attributed[File]]
val name = SettingKey[String]("name", "Project name.")
val normalizedName = SettingKey[String]("normalized-name", "Project name transformed from mixed case and spaces to lowercase and dash-separated.")
val description = SettingKey[String]("description", "Project description.")
@ -210,6 +210,7 @@ object Keys
val organization = SettingKey[String]("organization", "Organization/group ID.")
val organizationName = SettingKey[String]("organization-name", "Organization full/formal name.")
val organizationHomepage = SettingKey[Option[URL]]("organization-homepage", "Organization homepage.")
val scmInfo = SettingKey[Option[ScmInfo]]("scm-info", "Basic SCM information for the project.")
val projectInfo = SettingKey[ModuleInfo]("project-info", "Addition project information like formal name, homepage, licenses etc.")
val defaultConfiguration = SettingKey[Option[Configuration]]("default-configuration", "Defines the configuration used when none is specified for a dependency.")
val defaultConfigurationMapping = SettingKey[String]("default-configuration-mapping", "Defines the mapping used for a simple, unmapped configuration definition.")
@ -225,7 +226,7 @@ object Keys
val externalDependencyClasspath = TaskKey[Classpath]("external-dependency-classpath", "The classpath consisting of library dependencies, both managed and unmanaged.")
val dependencyClasspath = TaskKey[Classpath]("dependency-classpath", "The classpath consisting of internal and external, managed and unmanaged dependencies.")
val fullClasspath = TaskKey[Classpath]("full-classpath", "The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies.")
val internalConfigurationMap = SettingKey[Configuration => Configuration]("internal-configuration-map", "Maps configurations to the actual configuration used to define the classpath.")
val classpathConfiguration = TaskKey[Configuration]("classpath-configuration", "The configuration used to define the classpath.")
val ivyConfiguration = TaskKey[IvyConfiguration]("ivy-configuration", "General dependency management (Ivy) settings, such as the resolvers and paths to use.")
@ -240,7 +241,7 @@ object Keys
val updateClassifiers = TaskKey[UpdateReport]("update-classifiers", "Resolves and optionally retrieves classified artifacts, such as javadocs and sources, for dependency definitions, transitively.", update)
val transitiveClassifiers = SettingKey[Seq[String]]("transitive-classifiers", "List of classifiers used for transitively obtaining extra artifacts for sbt or declared dependencies.")
val updateSbtClassifiers = TaskKey[UpdateReport]("update-sbt-classifiers", "Resolves and optionally retrieves classifiers, such as javadocs and sources, for sbt, transitively.", updateClassifiers)
val publishConfiguration = TaskKey[PublishConfiguration]("publish-configuration", "Configuration for publishing to a repository.")
val publishLocalConfiguration = TaskKey[PublishConfiguration]("publish-local-configuration", "Configuration for publishing to the local repository.")
val deliverConfiguration = TaskKey[DeliverConfiguration]("deliver-configuration", "Configuration for generating the finished Ivy file for publishing.")