diff --git a/.scala-steward.conf b/.scala-steward.conf
new file mode 100644
index 00000000..aeb233b6
--- /dev/null
+++ b/.scala-steward.conf
@@ -0,0 +1,3 @@
+pullRequests.frequency = "@monthly"
+
+commits.message = "bump: ${artifactName} ${nextVersion} (was ${currentVersion})"
diff --git a/RELEASING.md b/RELEASING.md
index 591fdb4e..5d9f532a 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -1,6 +1,6 @@
# Releasing
-1. Wait until all running [Travis CI jobs](https://travis-ci.com/github/lightbend/paradox/builds) complete, if any.
+1. Wait until all running [GitHub Continuous Integration workflow](https://github.com/lightbend/paradox/actions/workflows/ci.yml) is complete, if any.
1. Publish the [draft release](https://github.com/lightbend/paradox/releases) with a 'v0.x.y' tag
-1. Travis CI will start a [CI build](https://travis-ci.org/lightbend/paradox/builds) for the new tag and publish artifacts to Bintray and Sonatype.
+1. Have someone bake the release...
1. Announce the new release in the [lightbend/paradox](https://gitter.im/lightbend/paradox) Gitter channel.
diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala
index 9e24ff47..3ebc10ea 100644
--- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala
+++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala
@@ -1056,6 +1056,107 @@ case class DependencyDirective(ctx: Writer.Context) extends LeafBlockDirective("
def dotted(symbol: String): String = symbol.replaceAll("(.)([A-Z])", "$1.$2").toLowerCase
}
+/**
+ * Repository directive.
+ */
+case class RepositoryDirective(ctx: Writer.Context) extends LeafBlockDirective("repository") {
+ val variables: Map[String, String] = ctx.properties
+
+ def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit =
+ node.contentsNode.getChildren.asScala.headOption match {
+ case Some(text: TextNode) => renderRepository(text.getText, node, printer)
+ case _ => node.contentsNode.accept(visitor)
+ }
+
+ def renderRepository(tools: String, node: DirectiveNode, printer: Printer): Unit = {
+ val classes = Seq("repository", node.attributes.classesString).filter(_.nonEmpty)
+
+ val startDelimiter = node.attributes.value("start-delimiter", "$")
+ val stopDelimiter = node.attributes.value("stop-delimiter", "$")
+
+ val postfixes = node.attributes
+ .keys()
+ .asScala
+ .toSeq
+ .filter(_.startsWith("name"))
+ .sorted
+ .map(_.replace("name", ""))
+
+ def coordinate(name: String): Option[String] =
+ Option(node.attributes.value(name)).map { value =>
+ variables.foldLeft(value) { case (str, (key, value)) =>
+ str.replace(startDelimiter + key + stopDelimiter, value)
+ }
+ }
+
+ def requiredCoordinate(name: String): String =
+ coordinate(name).getOrElse {
+ ctx.error(s"'$name' is not defined", node)
+ ""
+ }
+
+ printer.print(s"""
""")
+ tools.split("[,]").map(_.trim).filter(_.nonEmpty).foreach { tool =>
+ val (lang, code) = tool match {
+ case "sbt" =>
+ val repos = postfixes.map { p =>
+ val name = requiredCoordinate(s"name$p")
+ val url = requiredCoordinate(s"url$p")
+ s""""$name".at("$url")"""
+ }
+
+ val repoStrings = repos match {
+ case Seq(r) => s"repositories += $r\n"
+ case rs =>
+ Seq("repositories ++= Seq(\n", rs.map(a => s" $a").mkString(",\n"), "\n)\n").mkString
+ }
+
+ ("scala", repoStrings)
+
+ case "gradle" | "Gradle" =>
+ val repos = postfixes.map { p =>
+ val url = requiredCoordinate(s"url$p")
+ s""" maven {
+ | url "$url"
+ | }\n""".stripMargin
+ }
+
+ (
+ "gradle",
+ "repositories {\n mavenCentral()\n" +
+ repos.mkString +
+ "}\n"
+ )
+
+ case "maven" | "Maven" | "mvn" =>
+ val artifacts = postfixes.map { dp =>
+ val id = requiredCoordinate(s"id$dp")
+ val name = requiredCoordinate(s"name$dp")
+ val url = requiredCoordinate(s"url$dp")
+ s""" <repository>
+ | <id>$id</id>
+ | <name>$name</name>
+ | <url>$url</url>
+ | </repository>\n""".stripMargin
+ }
+
+ (
+ "xml",
+ "<project>\n ...\n <repositories>\n" +
+ artifacts.mkString +
+ " </repositories>\n</project>\n"
+ )
+ }
+ printer.print(s"""- $tool
""")
+ printer.print(s"""- """)
+ printer.print(s"""
$code
""")
+ printer.print(s""" """)
+ }
+ printer.print("""
""")
+ }
+
+}
+
case class IncludeDirective(ctx: Writer.Context) extends LeafBlockDirective("include") with SourceDirective {
override def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit =
diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala
index d39a600f..e36df44b 100644
--- a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala
+++ b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala
@@ -158,6 +158,7 @@ object Writer {
_ => InlineWrapDirective("span"),
(context: Context) => InlineGroupDirective(context.groups.values.flatten.map(_.toLowerCase).toSeq),
DependencyDirective.apply,
+ RepositoryDirective.apply,
IncludeDirective.apply
)
diff --git a/docs/src/main/paradox/directives/index.md b/docs/src/main/paradox/directives/index.md
index c426e8c3..1380233c 100644
--- a/docs/src/main/paradox/directives/index.md
+++ b/docs/src/main/paradox/directives/index.md
@@ -13,6 +13,7 @@ More directives are available via @ref[extensions](../customization/extensions.m
* [Index and Table Of Contents Directives](organizing-pages.md)
* [Linking Directives](linking.md)
* [dependencies](dependencies.md)
+ * [repositories](repositories.md)
* [Snippet Directives](snippets.md)
* [Include Directives](includes.md)
* [Fiddle Directives](fiddles.md)
diff --git a/docs/src/main/paradox/directives/repositories.md b/docs/src/main/paradox/directives/repositories.md
new file mode 100644
index 00000000..d43f94d1
--- /dev/null
+++ b/docs/src/main/paradox/directives/repositories.md
@@ -0,0 +1,21 @@
+Library repositories
+--------------------
+
+The `@@repository` block is used to show example code for how to configure a
+library repository in a build tool, such as sbt.
+
+```markdown
+@@repository[sbt,Maven,Gradle] {
+ id="company-repo"
+ name="Company repository"
+ url="http://jars.acme.com"
+}
+```
+
+Which will render as:
+
+@@repository[sbt,Maven,Gradle] {
+ id="company-repo"
+ name="Company repository"
+ url="http://jars.acme.com"
+}
diff --git a/tests/src/test/scala/com/lightbend/paradox/markdown/RepositoryDirectiveSpec.scala b/tests/src/test/scala/com/lightbend/paradox/markdown/RepositoryDirectiveSpec.scala
new file mode 100644
index 00000000..5f074d7a
--- /dev/null
+++ b/tests/src/test/scala/com/lightbend/paradox/markdown/RepositoryDirectiveSpec.scala
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2015 - 2019 Lightbend, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.lightbend.paradox.markdown
+
+import com.lightbend.paradox.tree.Tree.Location
+
+class RepositoryDirectiveSpec extends MarkdownBaseSpec {
+
+ val testProperties = Map(
+ "project.version" -> "10.0.10",
+ "scala.version" -> "2.12.3",
+ "scala.binary.version" -> "2.12"
+ )
+
+ implicit val context: Location[Page] => Writer.Context = { loc =>
+ writerContext(loc).copy(properties = testProperties)
+ }
+
+ "Repository directive" should "render single repo" in {
+ markdown("""
+ |@@repository[sbt,Maven,gradle] {
+ | id="id1"
+ | name="Company repository"
+ | url="http://jars.acme.com"
+ |}""") shouldEqual html(s"""
+ |
+ |- sbt
+ |-
+ |
+ |
+ |repositories += "Company repository".at("http://jars.acme.com")
+ |
+ |
+ |
+ |- Maven
+ |-
+ |
+ |
+ |<project>
+ | ...
+ | <repositories>
+ | <repository>
+ | <id>id1</id>
+ | <name>Company repository</name>
+ | <url>http://jars.acme.com</url>
+ | </repository>
+ | </repositories>
+ |</project>
+ |
+ |
+ |- gradle
+ |-
+ |
+ |
+ |repositories {
+ | mavenCentral()
+ | maven {
+ | url "http://jars.acme.com"
+ | }
+ |}
+ |
+ |
+ |
""")
+ }
+
+ "Repository directive" should "render two repos" in {
+ markdown("""
+ |@@repository[sbt,Maven,gradle] {
+ | id1="id1"
+ | name1="Company repository"
+ | url1="http://jars.acme.com"
+ | id2="id-2"
+ | name2="Company repository 2"
+ | url2="http://uberjars.acme.com"
+ |}""") shouldEqual html(s"""
+ |
+ |- sbt
+ |-
+ |
+ |
+ |repositories ++= Seq(
+ | "Company repository".at("http://jars.acme.com"),
+ | "Company repository 2".at("http://uberjars.acme.com")
+ |)
+ |
+ |
+ |
+ |- Maven
+ |-
+ |
+ |
+ |<project>
+ | ...
+ | <repositories>
+ | <repository>
+ | <id>id1</id>
+ | <name>Company repository</name>
+ | <url>http://jars.acme.com</url>
+ | </repository>
+ | <repository>
+ | <id>id-2</id>
+ | <name>Company repository 2</name>
+ | <url>http://uberjars.acme.com</url>
+ | </repository>
+ | </repositories>
+ |</project>
+ |
+ |
+ |- gradle
+ |-
+ |
+ |
+ |repositories {
+ | mavenCentral()
+ | maven {
+ | url "http://jars.acme.com"
+ | }
+ | maven {
+ | url "http://uberjars.acme.com"
+ | }
+ |}
+ |
+ |
+ |
""")
+ }
+
+}