Question

I'm attempting to run sbt test:doc and I'm seeing a number of warnings similar to below:

[warn] /Users/tleese/code/my/stuff/src/test/scala/com/my/stuff/common/tests/util/NumberExtractorsSpecs.scala:9: Could not find any member to link for "com.my.stuff.common.util.IntExtractor".

The problem appears to be that Scaladoc references from test sources to main sources are not able to link correctly. Any idea what I might be doing wrong or need to configure?

Below are the relevant sections of my Build.scala:

val docScalacOptions = Seq("-groups", "-implicits", "-external-urls:[urls]")

scalacOptions in (Compile, doc) ++= docScalacOptions
scalacOptions in (Test, doc) ++= docScalacOptions
autoAPIMappings := true
Was it helpful?

Solution

Not sure if this is a satisfactory solution, but...

Scaladoc currently expects pairs of jar and URL to get the external linking to work. You can force sbt to link internal dependencies using JARs using exportJars. Compare the value of

$ show test:fullClasspath

before and after setting exportJars. Next, grab the name of the JAR that's being used and link it to the URL you'll be uploading it to.

scalaVersion := "2.11.0"

autoAPIMappings := true

exportJars := true

scalacOptions in (Test, doc) ++= Opts.doc.externalAPI((
  file(s"${(packageBin in Compile).value}") -> url("http://example.com/")) :: Nil)

Now I see that test:doc a Scaladoc with links to http://example.com/index.html#foo.IntExtractor from my foo.IntExtractor.

OTHER TIPS

Using ideas from Eugene's answer I made a following snippet. It uses apiMapping sbt variable as adviced in sbt manual. Unfortunately it doesn't tell how to deal with managed dependencies, even the subsection title says so.

// External documentation

/* You can print computed classpath by `show compile:fullClassPath`.
 * From that list you can check jar name (that is not so obvious with play dependencies etc).
 */
val documentationSettings = Seq(
  autoAPIMappings := true,
  apiMappings ++= {
    // Lookup the path to jar (it's probably somewhere under ~/.ivy/cache) from computed classpath
    val classpath = (fullClasspath in Compile).value
    def findJar(name: String): File = {
      val regex = ("/" + name + "[^/]*.jar$").r
      classpath.find { jar => regex.findFirstIn(jar.data.toString).nonEmpty }.get.data // fail hard if not found
    }

    // Define external documentation paths
    Map(
      findJar("scala-library") -> url("http://scala-lang.org/api/" + currentScalaVersion + "/"),
      findJar("play-json") -> url("https://playframework.com/documentation/2.3.x/api/scala/index.html")
    )
  }
)

This is a modification of the answer by @phadej. Unfortunately, that answer only works on Unix/Linux because it assumes that the path separator is a /. On Windows, the path separator is \.

The following works on all platforms, and is slightly more idiomatic IMHO:

/* You can print the classpath with `show compile:fullClassPath` in the SBT REPL.
 * From that list you can find the name of the jar for the managed dependency.
 */
lazy val documentationSettings = Seq(
  autoAPIMappings := true,
  apiMappings ++= {
    // Lookup the path to jar from the classpath
    val classpath = (fullClasspath in Compile).value
    def findJar(nameBeginsWith: String): File = {
      classpath.find { attributed: Attributed[java.io.File] => (attributed.data ** s"$nameBeginsWith*.jar").get.nonEmpty }.get.data // fail hard if not found
    }
    // Define external documentation paths
    Map(
      findJar("scala-library") -> url("http://scala-lang.org/api/" + currentScalaVersion + "/"),
      findJar("play-json") -> url("https://playframework.com/documentation/2.3.x/api/scala/index.html")
    )
  }
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top