Why does publishing plugin project fail with RuntimeException: Repository for publishing is not specified? - sbt

I am trying to publish an SBT plugin to a repository. I'm not sure if this has any relevance, but our plugin loads the sbt-twirl plugin - Googling around, it seems like publishConfiguration might be overriden:
new PublishConfiguration(None, "dotM2", arts, Seq(), level)
When I run the publish task, artifacts are deployed to the repo, but the sbt task then fails:
sbt (my-sbt-plugin)> publish
[info] Loading global plugins from ...
...
[info] Done packaging.
[info] published sbt-my-sbt-plugin to http://my.repo.com/.../sbt-my-sbt-plugin-0.1-SNAPSHOT.jar
java.lang.RuntimeException: Repository for publishing is not specified.
.... stack trace here ....
[error] (my-sbt-plugin/*:publishConfiguration) Repository for publishing is not specified.
What is causing the error, and what could I do to stop the publishing from failing?
** Update ** Here is inspect publish
sbt (my-sbt-plugin)> inspect publish
[info] Task: Unit
[info] Description:
[info] Publishes artifacts to a repository.
[info] Provided by:
[info] {file:/path/to/my-sbt-plugin/}my-sbt-plugin/*:publish
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:988
[info] Dependencies:
[info] my-sbt-plugin/*:ivyModule
[info] my-sbt-plugin/*:publishConfiguration
[info] my-sbt-plugin/*:publish::streams
[info] Delegates:
[info] my-sbt-plugin/*:publish
[info] {.}/*:publish
[info] */*:publish
[info] Related:
[info] plugin/*:publish
Here's how I've configured publishing (with some of the plugin settings, excluding libraryDependencies and 1 or 2 other settings)
lazy val plugin = project
.settings(publishSbtPlugin: _*)
.settings(
name := "my-sbt-plugin",
sbtPlugin := true,
addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.0.2")
)
def publishSbtPlugin = Seq(
publishMavenStyle := true,
publishTo := {
val myrepo = "http://myrepo.tld/"
if (isSnapshot.value) Some("The Realm" at myrepo + "snapshots")
else Some("The Realm" at myrepo + "releases")
},
credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
)

tl;dr Don't use lazy val plugin = project to define a project (for unknown yet reasons)
After few comments it turned out that the issue was that the name of the project plugin as defined using lazy val plugin = project. It seems that the name is somehow reserved. Change the project's name to any other name than plugin and start over.

Specifying a project name other than "plugin" resolved the issue. I simplified the build definition a bit by removing a redundant build.sbt in 1 of the projects and am just using a full build definition in project directory. The root project that hosts the multi-project build is also reconfigured for no publishing:
lazy val root =
Project("sbt-my-plugin-root", file("."))
.settings(noPublishing: _*)
.aggregate(sbtMyPluginModule)
lazy val sbtMyPluginModule =
Project("sbt-my-plugin-module", file("sbt-my-plugin-module"))
.settings(publishSbtPlugin: _*)
.settings(
name := "sbt-my-plugin-module",
organization := "com.my.org",
sbtPlugin := true
)
lazy val noPublishing = seq(
publish := (),
publishLocal := ()
)
lazy val publishSbtPlugin = Seq(
publishMavenStyle := true,
publishArtifact in Test := false,
publishTo := {
val myrepo = "http://myrepo.tld/"
if (isSnapshot.value) Some("The Realm" at myrepo + "snapshots")
else Some("The Realm" at myrepo + "releases")
},
credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
)

if you trying this on your local then use publishLocal (not publish) as follows:
sbt clean compile publish-local

Related

sbt says "not a valid command" but plugin enabled

I have a plugin called sonar, which is developed and published as an AutoPlugin:
object Sonar extends AutoPlugin {
object autoImport {
lazy val sonar = taskKey[Unit]("sonar")
}
import autoImport._
override def trigger = allRequirements
lazy val sonarTask = Def.task {
<snip task code here which runs sonarqube scanner>
}
}
We then have a project which uses that plugin, with plugins.sbt that looks like this:
resolvers ++= Seq(
"Nexus Snapshot repo" at "url here"
)
credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
addSbtPlugin("packagename" % "sonar" % "1.0-SNAPSHOT")
And build.sbt like this:
name := "hashing-library"
organization := "org name here"
scalaVersion := "2.12.6"
autoScalaLibrary := false
crossPaths := false
resolvers += "Nexus Release repo" at "https://nexusurl/content/repositories/releases/"
resolvers += "nexus Snapshot repo" at "https://nexusurl/content/repositories/snapshots/"
credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
// Publishing options:
publishMavenStyle := true
publishArtifact in Test := false
pomIncludeRepository := { x => false }
publishTo := {
val nexus = "nexus url here"
if (isSnapshot.value)
Some("sonatype-snapshots" at nexus + "content/repositories/snapshots")
else
Some("sonatype-releases" at nexus + "content/repositories/releases")
}
When I try to run sbt plugins, it says the plugin is enabled:
<snip output>
packagename.sonar.Sonar: enabled in hashingLibrary
So why is it that my plugin is enabled, but I cannot run sbt sonar? When I do, it says:
[info] Set current project to hashing-library (in build file:/home/work/hashing-library/)
[error] Not a valid command: sonar
[error] Not a valid project ID: sonar
[error] Expected ':'
[error] Not a valid key: sonar
[error] sonar
[error]
(Obviously org names and url's have been removed to protect confidentiality of my client, but hopefully that doesn't impact my question!)
The missing part of your plugin is the connection between the sonar task key and the sonarTask task implementation, i.e. you need to say somewhere that the key is set to the value of the implementation. You normally do it by overriding project settings in the plugin:
override def projectSettings = Seq(
sonar := sonarTask.value
)

Unresolved dependency in published assembly package in SBT

In my project there are 3 sub projects under root. build.sbt is as below.
proj_C depends on proj_A and proj_B.
If I created the assembly proj_C package with below command. It success and the assembly package could be imported in other projects.
sbt "project proj_C" assembly
If I publish with "sbt publish", as I defined addArtifact in proj_C settings, an assembly jar package is also generated and then published. But when I try to compile another project which imports this assembly jar, it will below error
[error] unresolved dependency: proj_A;1.0.0: not found
part of build.sbt is as below. Could anyone point me what I made wrong in my way?
Many thanks!
artifact in (Compile, assembly) := {
val art = (artifact in (Compile, assembly)).value
art.withClassifier(Some("assembly"))
}
lazy val assemblySettings = Seq(
assemblyMergeStrategy in assembly := {
{
case PathList("META-INF", xs # _*) => MergeStrategy.discard
case _ => MergeStrategy.first
}
}
)
lazy val root = Project(base = file("."))
.disablePlugins(sbtassembly.AssemblyPlugin)
.aggregate(proj_A, proj_B, proj_C)
.settings(
commonSettings,
skip in publish := true,
name := "proj_root"
)
lazy val proj_A= (project in file("proj_A"))
.disablePlugins(sbtassembly.AssemblyPlugin)
.settings(
commonSettings,
skip in publish := true,
name := "proj_A"
)
lazy val proj_B= (project in file("proj_B"))
.disablePlugins(sbtassembly.AssemblyPlugin)
.settings(
commonSettings,
skip in publish := true,
name := "proj_B"
)
lazy val proj_C= (project in file("proj_C"))
.settings(
commonSettings,
assemblySettings,
addArtifact(artifact in (Compile, assembly), assembly),
name := "proj_C"
) dependsOn(proj_A, proj_B)
First of all, I hope you know that the publishing of the fat jar is not recommended. And to be honest, in your case I really see no benefit in doing so.
If you simply publish A, B, C separately and then add the dependency in your other project it will all be automatically downloaded (along with dependencies of those projects). And the dependency management will be much easier...
But, since you want to add the A-assembly dependency, by the error I guess that you are actually adding the wrong jar. My guess would be that you publish both C.jar and C-assembly.jar, and you added the dependency like:
"your.organisation" %% "C" % "version"
but you should have:
"your.organisation" %% "C" % "version" classifier "assembly"

how to define multi-project build with sbt-native-packager that creates an RPM for each sub-project

In all of the examples I've seen regarding multi-module builds and sbt-native-packager, they all aggregate the sub-projects into a single package. I have sub-projects that each provide a micro-service. I believe that each of these should have it's own native package, but I don't see how to do that and have a one command build for all of the sub-projects.
This turns out be straightforward. Simply provide native-packager settings for each of the sub-projects that you want to package and don't provide any on the aggregating project.
I tested by modifying https://github.com/muuki88/sbt-native-packager-examples/tree/master/multi-module-build accordingly:
import NativePackagerKeys._
name := "mukis-fullstack"
// used like the groupId in maven
organization in ThisBuild := "de.mukis"
// all sub projects have the same version
version in ThisBuild := "1.0"
scalaVersion in ThisBuild := "2.11.2"
// common dependencies
libraryDependencies in ThisBuild ++= Seq(
"com.typesafe" % "config" % "1.2.0"
)
// this is the root project, aggregating all sub projects
lazy val root = Project(
id = "root",
base = file("."),
// configure your native packaging settings here
// settings = packageArchetype.java_server++ Seq(
// maintainer := "John Smith <john.smith#example.com>",
// packageDescription := "Fullstack Application",
// packageSummary := "Fullstack Application",
// entrypoint
// mainClass in Compile := Some("de.mukis.frontend.ProductionServer")
// ),
// always run all commands on each sub project
aggregate = Seq(frontend, backend, api)
) dependsOn(frontend, backend, api) // this does the actual aggregation
// --------- Project Frontend ------------------
lazy val frontend = Project(
id = "frontend",
base = file("frontend"),
settings = packageArchetype.java_server++ Seq(
maintainer := "John Smith <john.smith#example.com>",
packageDescription := "Frontend appplication",
mainClass in Compile := Some("de.mukis.frontend.ProductionServer")
)
) dependsOn(api)
// --------- Project Backend ----------------
lazy val backend = Project(
id = "backend",
base = file("backend"),
settings = packageArchetype.java_server++ Seq(
maintainer := "John Smith <john.smith#example.com>",
packageDescription := "Fullstack Application",
packageSummary := "Fullstack Application",
// entrypoint
mainClass in Compile := Some("de.mukis.frontend.ProductionServer")
)
) dependsOn(api)
// --------- Project API ------------------
lazy val api = Project(
id = "api",
base = file("api")
Results:
debian:packageBin
...misc messages elided...
[info] dpkg-deb: building package `frontend' in `../frontend_1.0_all.deb'.
[info] dpkg-deb: building package `backend' in `../backend_1.0_all.deb'.
For whom just ended up here, a more up-to-date answer could look like:
lazy val root = (project in file("."))
.aggregate(common, frontend, backend)
lazy val common = (project in file("common"))
lazy val frontend = (project in file("frontend"))
.enablePlugins(JavaServerAppPackaging)
lazy val backend = (project in file("backend"))
.dependsOn(common)
.enablePlugins(JavaAppPackaging)
.settings(javaPackagingSettings)
lazy val javaPackagingSettings = Seq(
// follow sbt-native-packager to identify settings you need
)
Description
Here is the scenario supporting the above configuration
Project root is the parent and we don't want to package it. It aggregates other subprojects.
Project common is a sort of library and also we don't want to package it
Project backend depends on common for the libraries.
Project frontend is a standalone project packaged as a Java server app with default configuration

How to publish to Sonatype using publishSigned from sbt-pgp?

I want to publish a Scala library with sbt using sbt-pgp 0.8. I've registered groupId org.bitbucket.sergey_kozlov at Sonatype.
My build.sbt:
organization := "org.bitbucket.sergey_kozlov"
name := "playingcards"
version := "0.1-SNAPSHOT"
publishMavenStyle := true
publishTo := {
val nexus = "https://oss.sonatype.org/"
if (isSnapshot.value)
Some("snapshots" at nexus + "content/repositories/snapshots")
else
Some("releases" at nexus + "service/local/staging/deploy/maven2")
}
publishArtifact in Test := false
pomIncludeRepository := { _ => false }
pomExtra :=
<url>https://bitbucket.org/sergey_kozlov/playingcards</url>
<licenses>
<license>
<name>The MIT License</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://bitbucket.org/sergey_kozlov/playingcards.git</url>
<connection>scm:git:ssh://git#bitbucket.org/sergey_kozlov/playingcards.git</connection>
</scm>
<developers>
<developer>
<id>skozlov</id>
<name>Sergey Kozlov</name>
<email>mail.sergey.kozlov#gmail.com</email>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
</developer>
</developers>
libraryDependencies += "junit" % "junit" % "4.11"
libraryDependencies += "org.scalatest" % "scalatest_2.10" % "2.0" % "test"
There's also ~/.sbt/0.13/plugins/gpg.sbt:
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8")
No other files are under project/ directory that contribute to the build definition.
When I enter publishSigned in sbt console, I get the following error:
[error] (*:publishSigned) java.io.IOException: Access to URL https://oss.sonatype.org/content/repositories/snapshots/playingcards/playingcards_2.10/0.1-SNAPSHOT/playingcards_2.10-0.1-SNAPSHOT-sources.jar was refused by the server: Forbidden
Note that the URL does not contain organization.
How can I publish my artifact correctly?
As you pointed out your URL is missing organization property this is why you get this error. Try to run show organization in sbt console to be sure that your organization property is correct. If it doesn't help try to specify your project explicitly in sbt and set organization property there.
lazy val core = (project in file(".")).settings(
organization := "org.bitbucket.sergey_kozlov"
//other properties here
)

Add task to Build.scala

The document http://www.scala-sbt.org/0.13.0/docs/Detailed-Topics/Tasks.html explains how to add a task to build.sbt, but how do you add one to build.scala? Thanks
The part where you declare the TaskKey is the same in either format: val myTask = taskKey....
The part where you write out your Initialize[Task[T]] is the same: myTask := ....
The only difference is the context in which the latter thing appears.
In the .sbt format, it appears by itself, separated from other things by blank lines.
In the .scala format, you have to add the setting to the project. That's documented at http://www.scala-sbt.org/release/docs/Getting-Started/Full-Def.html and is the same regardless of whether we're talking about a task or a regular setting.
Here's a complete working example:
import sbt._
object MyBuild extends Build {
val myTask = taskKey[Unit]("...")
lazy val root =
Project(id = "MyProject", base = file("."))
.settings(
myTask := { println("hello") }
)
}
When defining a task in one project of a multi project build and using a "root" project to aggregate other projects, the aggregation means that any tasks in subprojects can be run from the root project as well, in fact this will run the tasks in all subprojects - see Multi-project builds. This is generally useful, for example to compile all subprojects when the compile task is run from the root project. However in this case it is a little confusing.
So the task is not accessible in all projects, but is accessible in both the subproject where you define the task, and the aggregating (root) project. The task is still running in the project where it is defined, it can just be called when in the root project.
To demonstrate this, we can have the same "hello" task defined in multiple sub projects, which are aggregated in a root project:
import sbt._
import Keys._
object Build extends Build {
val hwsettings = Defaults.defaultSettings ++ Seq(
organization := "organization",
version := "0.1",
scalaVersion := "2.10.4"
)
val hello = TaskKey[Unit]("hello", "Prints hello.")
lazy val projectA = Project(
"a",
file("a"),
settings = hwsettings ++ Seq(
hello := {println("Hello from project A!")}
))
lazy val projectB = Project(
"b",
file("b"),
settings = hwsettings ++ Seq(
hello := {println("Hello from project B!")}
))
lazy val projectC = Project(
"c",
file("c"),
settings = hwsettings
)
lazy val root = Project (
"root",
file ("."),
settings = hwsettings
) aggregate (projectA, projectB, projectC)
}
Note that projects a and b have "hello" tasks, and c does not. When we use "hello" from the root project, the aggregation causes the task to run in projects a AND b:
> project root
[info] Set current project to root (in build file:/Users/trepidacious/temp/multiProjectTasks/)
> hello
Hello from project A!
Hello from project B!
[success] Total time: 0 s, completed 24-Dec-2014 23:00:23
We can also switch to project a or b, and running hello will only run the task in the project we are in:
> project a
[info] Set current project to a (in build file:/Users/trepidacious/temp/multiProjectTasks/)
> hello
Hello from project A!
[success] Total time: 0 s, completed 24-Dec-2014 23:00:27
> project b
[info] Set current project to b (in build file:/Users/trepidacious/temp/multiProjectTasks/)
> hello
Hello from project B!
[success] Total time: 0 s, completed 24-Dec-2014 23:00:30
Finally, if we switch to project c, hello is not defined:
> project c
[info] Set current project to c (in build file:/Users/trepidacious/temp/multiProjectTasks/)
> hello
[error] Not a valid command: hello (similar: shell, help, reload)
[error] No such setting/task
[error] hello
[error] ^
>
This aggregation can be disabled, as described here.

Resources