Add plugin's plugin dependency as plugin dependency of user - plugins

I am creating an SBT plugin to be used in all Scala projects in my company. It is a collection of commonly used SBT plugins and a common configuration that can be shared everywhere. My plugin uses e.g sbt-release: configures credentials, sets a release process, a default publish repository, etc. So I added it as a plugin dependency
project/plugins.sbt:
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.7")
However I'd like to expose this plugin to my users, so they can call sbt release. Currently I have the following code:
build.sbt
sbtPlugin := true
/* common release configuration code */
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.7")
If I remove the last line, my user cannot call sbt release. However I want to avoid declaring the dependency twice. Can I do better?

I went with a different approach, as the configurations didn't even get applied this way, and it also solves the duplication issue. Instead of sbt files, I created Scala files for the plugin and included the required plugin dependencies in build.sbt. This way you don't need to add it to project/plugins.sbt at all.
Example:
build.sbt
sbtPlugin := true
addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.7")
src/main/scala/mycompany/MyReleaseConfigPlugin.scala
package mycompany
import sbt._
import Keys._
object MyReleaseConfigPlugin extends AutoPlugin {
override def trigger: PluginTrigger = allRequirements
override def requires = sbtrelease.ReleasePlugin
/* common release configuration code example */
import sbtrelease.ReleasePlugin.autoImport._
import ReleaseTransformations._
override lazy val projectSettings = Seq(
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runClean,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
publishArtifacts),
releaseIgnoreUntrackedFiles := false,
publishMavenStyle := true,
credentials += Credentials(
"Artifactory Realm",
"artifactory.mycompany.com",
sys.env.get("REPO_USER").getOrElse(""),
sys.env.get("REPO_PASS").getOrElse(""))
)
}

Related

Unable to stub controller components

The method stubControllerComponents in package play.api.test appears to use same package and object name as a separate dependency which is causing a conflict when I attempt to use stubControllerComponents :
play.api.test.Helpers.stubControllerComponents is not found in below code:
import java.io.File
import play.api.test
import play.api.mvc._
import javax.inject._
import play.api.Environment
import play.api.mvc.{AbstractController, ControllerComponents}
class CountController #Inject() (cc: ControllerComponents,
env: Environment) extends AbstractController(cc) {
def getter() = Option(env.classLoader.getResourceAsStream("file.csv"))
}
play.api.Environment(play.api.test.Helpers.stubControllerComponents, Environment.simple())
This Helpers contains the method I require stubControllerComponents :
But this version of the class is being imported with import play.api.test :
Play link for stubbing : https://www.playframework.com/documentation/2.6.x/Highlights26#StubControllerComponents
build.sbt:
name := "ddd"
version := "1.0"
lazy val `ddd` = (project in file(".")).enablePlugins(PlayScala)
resolvers += "scalaz-bintray" at "https://dl.bintray.com/scalaz/releases"
resolvers += "Akka Snapshot Repository" at "https://repo.akka.io/snapshots/"
scalaVersion := "2.12.2"
libraryDependencies ++= Seq( jdbc , ehcache , ws , guice , specs2 % Test)
unmanagedResourceDirectories in Test <+= baseDirectory ( _ /"target/web/public/test" )
Do I need to exclude portions of a dependency, in this case filters-helpers in order to make stubControllerComponents available ?
Update:
play.api.test.Helpers.stubControllerComponents not found:
Update2:
You seem to be using a scratch file. AFAICS, there is no way to also include dependencies from your Test scope into the classpath of your worksheet.
A workaround would be to (temporarily) add the play-test artefact to your libraryDependencies. Or just create a proper test file, which has access to the Test libraries normally.
play.api.test.Helpers.stubControllerComponents is provided by play-test
dependency
libraryDependencies += "com.typesafe.play" %% "play-test" % PlayVersion.current % "test",
which is indirectly imported by Play's sbt plugin specified at project/plugins.sbt
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.1")
after explicitly enablePlugins(PlayScala) within project's build.sbt.
Note how play-test is out-of-the-box scoped to test configuration hence it is provided only on the test classpath. If you wish to reference stubControllerComponents from within IntelliJ Scala Worksheet, then make sure to create the worksheet inside test/ directory and not inside app/ directory. This will make Scala Worksheet use test classpath.

Plugins compile order in SBT

I'm trying to create an SBT plugin that provides common plugins and settings for my organization's projects (something like a Maven parent POM).
Since most of these settings should also be present in the commons project itself, I'm adding the sources as unmanagedSourceDirectories in plugins.sbt so the autoplugins I define for the proper project are also present on the meta-project (a neat trick I took from sbt-release plugin).
Things work just fine, except I still need to duplicate the addSbtPlugin entries when I want a plugin for booth my proper project and meta-project. If I don't do this, my proper-project won't compile since the plugins' classes are not loaded.
I tried moving all the shared plugin dependencies to a separate autoplugin assuming SBT would compile it and add the library dependencies to the meta-project so they would be there when my common plugin is compiled, but it doesn't work.
I would like to understand why this fails and if there is some way to thinker with the compilation order to somehow make it work. If not, I would gladly hear any alternatives you guys know to avoid having to maintain duplicate versions of all my shared plugins.
Here is a simplified version of my code:
project structure
/common
|-build.sbt
|-/project
| |-plugins.sbt
|-/src/main/scala/package
|-Dependencies.scala
|-MyCommonPlugin.scala
build.sbt
sbtPlugin := true
name := "common"
plugins.sbt
unmanagedSourceDirectories in Compile += baseDirectory.value.getParentFile / "src" / "main" / "scala"
Dependencies.scala
import sbt._
import sbt.Keys._
//Plugins I intend to share between build.sbt and plugins.sbt
object Dependencies extends AutoPlugin {
override def trigger = allRequirements
override lazy val projectSettings = super.projectSettings ++ Seq(
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5")
)
}
MyCommonPlugin.scala
import sbt._
import sbt.Keys._
//this import fails! object sbt is not a member of package com.typesafe
import com.typesafe.sbt.GitBranchPrompt.{ projectSettings => gitBranchPromptSettings }
object MyCommonPlugin extends AutoPlugin {
override def trigger = allRequirements
override lazy val projectSettings =
super.projectSettings ++
gitBranchPromptSettings ++
Seq(
// My common settings
)
}
To make this code work I would need to repeat the addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.8.5") on plugins.sbt.

Custom NIO filesystem doesn't load through SBT's test task

For testing, I'm using an in-memory NIO FileSystem implementaion ( memoryfs ). I've taken advantage of it before, and it seems to run fine through e.g. Maven.
However, now, in an SBT project, it's impossible to initialize a new FileSystem.
Here's a minimal SBT configuration to reproduce the problem:
import sbt._
import Keys._
name := "testfs"
organization := "com.example
version := "0.1-SNAPSHOT"
scalaVersion := "2.11.6"
libraryDependencies ++= {
val scalaTestVersion = "2.2.5"
Seq(
"org.scalatest" %% "scalatest" % scalaTestVersion % "test",
"org.mockito" % "mockito-core" % "1.10.19" % "test",
"de.pfabulist.lindwurm" % "memoryfs" % "0.28.3" % "test"
)}
And here's a test:
import de.pfabulist.lindwurm.memory.MemoryFSBuilder
import org.scalatest.{FlatSpec, MustMatchers}
class FsDummySpec extends FlatSpec with MustMatchers {
it must "init the FS" in {
new MemoryFSBuilder().watchService(true).name("testFs").build() //init here
}
}
Running sbt test will result in:
[info] FsDummySpec:
[info] - must init the FS *** FAILED ***
[info] java.nio.file.ProviderNotFoundException: Provider "memoryfs" not found
[info] at java.nio.file.FileSystems.getFileSystem(FileSystems.java:224)
[info] at de.pfabulist.kleinod.paths.Pathss.getOrCreate(Pathss.java:76)
Here's the thing: this should run without any problems. My question is: why, and how to fix it?
Glancing over the custom FS provider docs it looks like SBT borks the classpath somehow, but its hard to say why.
Note: interestingly enough, IntelliJ IDEA's test runner seems to work without a hitch, the problem is only on the command line (in "SBT proper").
The comment by openCage hinted at the solution.
It turns out custom file systems do require an additional element, i.e. a service provider definition file located in META-INF/services.
If you use a custom NIO FileSystem, you need to make that provider definition file available in the test classpath.
The simplest way is probably just to fork the test VM, i.e. add the following to your build.sbt:
fork in Test := true

How to avoid adding a 'root' scala sbt project in IntelliJ when defining github dependencies?

I'm using IntelliJ with SBT plugin and I've added the following lines to build.sbt in order to add a dependency to a private github repository:
lazy val g = RootProject(uri("ssh://git#github.com/XXXX/myrepo.git"))
lazy val root = project in file("myproject") dependsOn g
After running sbt, my referenced project is successfully cloned, but build fails due to output path clashes between my base project and a root project that is automatically added each time I refresh sbt after modifying build.sbt.
I was having this same issue awhile back.
I'm not sure what causes it but I know that if you use the multi-project setup for sbt (root/project/build.scala) instead of the simple one (root/build.sbt) Intellij respects your settings.
Try the multi-project setup like this and see if it solves your problem:
import sbt.Keys._
import sbt._
lazy val g = RootProject(uri("ssh://git#github.com/XXXX/myrepo.git"))
object MyProjectBuild extends Build {
lazy val project = Project("myproject", file(".")) // <-- Make sure to name your project what you want the module to be named
.settings(
name := "myproject", // <-- Same here
version := "1.0",
scalaVersion := "2.11.4",
libraryDependencies ++=Seq(
"org.scalatest" % "scalatest_2.11" % "2.2.0" % "test",
)
).dependsOn(g)
}

How to set up managed dependencies in an SBT 0.11 project having Build.scala

I am building a simple Scala project with SBT 0.11.
All the code files are in ~/MyProject/src/main/scala/
~/MyProject/build.sbt is the following
name := "MyProject"
version := "1.0"
scalaVersion := "2.9.1"
libraryDependencies ++= Seq(
"mysql" % "mysql-connector-java" % "5.1.+",
"c3p0" % "c3p0" % "0.9.1.2",
"org.apache.commons" % "commons-lang3" % "3.0.1",
"commons-lang" % "commons-lang" % "2.6",
"javassist" % "javassist" % "3.12.1.GA"
)
~/MyProject/project/Build.scala is the following
import sbt._
object MyProjectBuild extends Build {
lazy val MyProject = Project("MyProject", file("."))
}
This seems to work almost fine. The project does compile and run. The project name is set correctly (if I don't use Build.scala, then the name seems to appear something like "default-????", despite it being specified in build.sbt).
But the problem is that dependencies do not seem to work - update command doesn't download anything. How to fix this? Do I need to specify my dependencies in Build.scala rather than in build.sbt in this case?
Is it possible that you've already retrieved the project dependencies, but don't realize it because they are stored in the Ivy cache? You can view the managed classpath from the SBT console with the command
show managed-classpath
Recent versions of SBT do not store the managed dependencies in the project directory, unless the project is configured to do so. If you want, you can add the following to your build.sbt file:
retrieveManaged := true
This will create a ~/MyProject/lib_managed/ directory and contents.