This plugin is considered experimental. Expect frequent breaking changes.
sbt-bazel is an sbt plugin that converts sbt projects to Bazel workspaces. This readme assumes you have basic knowledge of how a Bazel workspace is organized.
This plugin will generate BUILD files for each project along with a WORKSPACE files that handles importing rules_scala and downloading binary artifacts from Maven repos.
readme-example project in the plugin's test directory is a minimal usage example. This section will walk through the settings used.
(TODO: Update this once the plugin artifact is published.)
First you must install the plugin in your project. Currently it can be used as a source dependency by first cloning the repo:
git clone firstname.lastname@example.org:stripe/sbt-bazel.git
Then add the following to your project's
project/plugins.sbt, setting the correct path to
lazy val plugin = ProjectRef(uri("path/to/sbt-bazel"), "plugin") lazy val root = (project in file(".")).dependsOn(plugin)
In your project's
build.sbt file, you must now set the version of
rules_scala. This is done by setting
bazelScalaRulesVersion to the SHA of the
rules_scala commit you'd like to use. For example, to set the version to 0eab80ff0696d419aa54c2ab4b847ce9bdcbb379 add the following to the top of your build file:
ThisBuild / bazelScalaRulesVersion := "0eab80ff0696d419aa54c2ab4b847ce9bdcbb379"
A common sbt pattern is to set up a root project that does not contain any source files itself, but is instead an aggregation all of a repo's sub-projects. This is the pattern the example project follows.
In order to generate one
WORKSPACE file, enable workspace file generation with
bazelWorkspaceGenerate for the root project. Because the root project is just an empty aggregation, it also makes sense to turn off
BUILD file generation with
bazelBuildGenerate. Putting all this together, the root target will look as follows:
lazy val root = project. in(file(".")). aggregate(core, example). settings( bazelWorkspaceGenerate := true, bazelBuildGenerate := false, )
You can now run the
bazelGenerate task against the root project. The result will be
BUILD files generated for all the aggregated projects. These will appear at the base directory of each of the projects. A
WORKSPACE file will also be generated at the root directory of the root project, which will handle downloading binary dependencies and rules_scala.
*.expect files for examples of what the generated files will look like.
For more complicated projects, you may need to customize the behavior of the plugin. Several settings are available to you.
Toggling File Generation
bazelWorkspaceGenerate: When set to
WORKSPACEfile is generated for the current project at the project's base directory. Otherwise, no file is generated. As shown above, this will typically be set to
truefor the root aggregate project.
bazelBuildGenerate: When set to
BUILDfile is generated for the current project. Otherwise, a
BUILDfile is generated for the current project at the project's base directory. As shown above, this will typically be set to
falsefor the root aggregate project.
Customizing Workspace and Build File Generation
bazelCustomWorkspace: This allows customizing how the
WORKSPACEfile is generated using a DSL. By default, the
WORKSPACEfile is made up of two sections:
WorkspacePrelude, which contains the code to load and set up
- And a
MavenBindingssection, which contains code to load and bind any dependency artifacts.
So the default setting is:
bazelCustomWorkspace := WorkspacePrelude +: MavenBindings, where the
+: operator concatenates sections together.
BazelString operand allows you add arbitrary text to the
WORKSPACE file. The following would completely replace the generated
WORKSPACE contents with the string passed to
bazelCustomWorkspace := BazelString("# Custom workspace file")
bazelCustomBuild: This allows customizing how the
BUILDfile is generated using a DSL. By default, the
WORKSPACEfile is made up of two sections:
BuildPrelude, which contains the code to load rules from
- And a
BuildTargetssection, which contains the generated
scala_binarytarget, if applicable.
+: operator concatenates sections and
BazelString allows you to specify arbitrary strings.
Customizing Dependency Generation
The plugin will add dependencies to targets based on sbt's
libraryDependencies setting. If this needs to be overridden for some reason, this can be customized with the
bazelRuleDeps setting. The default setting is
bazelRuleDeps := Deps(Compile), which means each target will include dependencies on any internal project dependencies and all dependencies in
Each operand of the DSL specifies a set of dependencies, and these sets can be used in an expression with the normal set operators:
The operands are:
Deps(config: Configuration): This denotes the set of all internal and external dependencies for a given config.
ModuleDep(moduleId: ModuleID): This denotes the dependency referred to by the given
ModuleId. For example,
ModuleDep("io.circe" %% "circe-parser" % "0.9.3").
StringDep(dep: String): This denotes the dependency referred to by the given string. For example,
BazelDep(path: String, name: String): This denotes the dependency referred to by the combination of the given path and target name. For example,
BazelDep("//core", "core")denotes the Bazel dependency
EmptyDep: This denotes the empty set.
Putting this together, the following would remove the
circe-parser 0.9.2 dependency and substitute it for version 0.9.3:
bazelRuleDeps := Deps(Compile) - ModuleDep("io.circe" %% "circe-parser" % "0.9.2") + ModuleDep("io.circe" %% "circe-parser" % "0.9.3")
Customizing Maven Dependency Resolution in
You can also customize which dependencies are loaded in the
WORKSPACE file with
bazelMavenDeps. The default is
bazelMavenDeps := AllExternalDeps(Compile)
The operators and operands in the Customizing Dependency Generation section can be used here.
bazelScalaRulesVersion: Set the version of
scala_rulesto a specific SHA.
The plugin has the following limitations:
- All dependencies in the
Keys.externalDependencyClasspathare added as compile time dependencies, even if they are only needed at runtime.
- Any additional resolvers added to the
Resolversetting are used as mirrors in the
WORKSPACEfile for all dependencies.
- Only Maven resolvers are supported.
Contributions are welcome. If you have a large contribution in mind, please open an issue to discuss the change first.