Scala Project Guardrails
Enforce Scala-specific project standards including build manifest presence, Scala version pinning, sbt version pinning, dependency lockfile commit, test source layout, and scalafmt configuration. Supports sbt, Mill, and Maven (via scala-maven-plugin).
scala to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/scala@v1.0.5
Included Guardrails
This policy includes 8 guardrails that enforce standards for your devex build and ci.
build-tool-manifest-exists
Ensures the project has a recognised Scala build manifest:
build.sbt (sbt), build.sc (Mill), or pom.xml with the
scala-maven-plugin. Required for any Scala project so that the
build is reproducible and tooling-discoverable.
scala-version-pinned
Ensures the Scala compiler version is declared (scalaVersion := "..."
in build.sbt, the equivalent in build.sc, or <scala.version> /
<scala.binary.version> in pom.xml). Pinning the compiler version
prevents drift between developers and CI.
min-scala-version
Ensures the declared Scala compiler version meets the configured
minimum (default: "2.12"). Reads .lang.scala.version (parsed from
scalaVersion / <scala.version> / Mill def scalaVersion). Skips
when the version is not detected — pair with scala-version-pinned
if you want presence to be enforced too.
sbt-version-set
Ensures project/build.properties pins the sbt version (e.g.
sbt.version=1.9.7) when sbt is the build tool. Skips for Mill-only
and Maven-only projects.
min-sbt-version
Ensures the sbt version pinned in project/build.properties meets
the configured minimum (default: "1.9"). Reads .lang.scala.sbt_version.
Skips for Mill-only and Maven-only projects, and when the sbt version
is not detected — pair with sbt-version-set if you want presence to
be enforced too.
dependencies-locked
Ensures dependencies are locked for reproducible builds — either via
build.sbt.lock (sbt-lock plugin) or an equivalent Mill/Maven lock
mechanism. Informational by default — most Scala projects do not
lock dependencies, but doing so produces reproducible CI builds.
test-module-exists
Ensures a src/test/scala directory (or a cross-version variant
such as src/test/scala-2.13 / src/test/scala-3) exists with
test sources. Skips on non-Scala projects.
scalafmt-configured
Ensures .scalafmt.conf is committed at the repo root. scalafmt
enforces consistent code formatting and is the de facto standard
for Scala. Informational.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
min_scala_version
|
Optional |
2.12
|
Minimum required Scala compiler version (e.g., "2.12", "2.13", "3.3.1"). Compared with semantic-version semantics — "2.13" matches 2.13.x and 3.x, but rejects 2.11.x. |
min_sbt_version
|
Optional |
1.9
|
Minimum required sbt version (e.g., "1.9", "1.10.0"). Compared with semantic-version semantics. Skipped when the project does not use sbt. |
Documentation
View on GitHubScala Project Guardrails
Enforce Scala-specific project standards including build manifest presence, version pinning, dependency locking, test layout, and scalafmt configuration.
Overview
This policy validates Scala projects against best practices for build configuration, version pinning, dependency reproducibility, testing conventions, and code formatting. All checks skip gracefully on non-Scala projects (i.e., .lang.scala missing). Supports sbt, Mill, and Maven (with scala-maven-plugin) build systems.
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
build-tool-manifest-exists |
Validates build.sbt, build.sc, or pom.xml exists |
Project lacks a recognised Scala build manifest |
scala-version-pinned |
Validates Scala compiler version is declared | Missing scalaVersion declaration |
min-scala-version |
Validates declared Scala version meets min_scala_version (default 2.12) |
Scala version below the configured minimum |
sbt-version-set |
Validates project/build.properties pins sbt version |
Missing or empty sbt.version (sbt projects only) |
min-sbt-version |
Validates pinned sbt version meets min_sbt_version (default 1.9) |
sbt version below the configured minimum (sbt projects only) |
dependencies-locked |
Validates lockfile is present (sbt-lock or equivalent) | No lockfile committed (informational) |
test-module-exists |
Validates src/test/scala (or cross-version variant) exists |
No test sources detected |
scalafmt-configured |
Validates .scalafmt.conf is committed |
scalafmt not configured (informational) |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.lang.scala |
object | scala collector |
.lang.scala.build_sbt_exists |
boolean | scala collector |
.lang.scala.build_sc_exists |
boolean | scala collector |
.lang.scala.pom_xml_exists |
boolean | scala collector |
.lang.scala.version |
string | scala collector |
.lang.scala.sbt_version |
string | scala collector |
.lang.scala.build_systems |
array | scala collector |
.lang.scala.lockfile_exists |
boolean | scala collector |
.lang.scala.test_directory_exists |
boolean | scala collector |
.lang.scala.scalafmt_configured |
boolean | scala collector |
Installation
Add to your lunar-config.yml:
policies:
- uses: github://earthly/lunar-lib/policies/scala@main
on: ["domain:your-domain"] # replace with your own domain or tags
enforcement: report-pr
# include: [build-tool-manifest-exists, scala-version-pinned] # Only run specific checks
Examples
Passing Example
{
"lang": {
"scala": {
"build_sbt_exists": true,
"build_properties_exists": true,
"version": "2.13.12",
"sbt_version": "1.9.7",
"build_systems": ["sbt"],
"lockfile_exists": true,
"test_directory_exists": true,
"scalafmt_configured": true
}
}
}
Failing Example
{
"lang": {
"scala": {
"build_sbt_exists": false,
"build_sc_exists": false,
"pom_xml_exists": false,
"version": "",
"sbt_version": "",
"build_systems": [],
"lockfile_exists": false,
"test_directory_exists": false,
"scalafmt_configured": false
}
}
}
Failure messages:
"No Scala build manifest found. Add build.sbt (sbt), build.sc (Mill), or pom.xml with scala-maven-plugin.""Scala compiler version not declared. Add 'scalaVersion := \"2.13.12\"' to build.sbt or set <scala.version> in pom.xml.""Scala version 2.11.12 is below minimum 2.12. Update scalaVersion in build.sbt.""sbt version not pinned. Create project/build.properties with 'sbt.version=1.9.7'.""sbt version 1.6.2 is below minimum 1.9. Update project/build.properties.""No dependency lockfile found. Run 'sbt lock' (with sbt-lock) or commit build.sbt.lock for reproducible builds.""No test sources found. Create src/test/scala/ and add ScalaTest, MUnit, or Specs2 tests.""scalafmt not configured. Add .scalafmt.conf at the repo root for consistent formatting."
Remediation
build-tool-manifest-exists
- For sbt:
sbt new scala/scala-seed.g8to scaffold a new project, or createbuild.sbtat the repo root - For Mill: install Mill and create
build.scat the repo root - For Maven: add
pom.xmlwith thescala-maven-pluginplugin in<plugins>
scala-version-pinned
- In
build.sbt, add at the top:scalaVersion := "2.13.12"(or your target version) - In
build.sc(Mill): setdef scalaVersion = "2.13.12"on your module - In
pom.xml: set<scala.version>2.13.12</scala.version>and use it in the scala-maven-plugin config
min-scala-version
- Update
scalaVersioninbuild.sbt(or the equivalent inbuild.sc/pom.xml) to a version at or abovemin_scala_version - Run
sbt clean test(or your equivalent) to verify the project still builds and passes tests on the new version - For cross-builds, ensure every entry in
crossScalaVersionsalso meets the minimum
sbt-version-set
- Create
project/build.properties - Add
sbt.version=1.9.7(or the desired version) - Commit the file
min-sbt-version
- Update
sbt.versioninproject/build.propertiesto a version at or abovemin_sbt_version - Run
sbt --versionlocally to confirm the launcher resolves the new version - Re-run CI to confirm reproducibility
dependencies-locked
- Add the sbt-lock plugin to
project/plugins.sbt:addSbtPlugin("software.purpledragon" % "sbt-dependency-lock" % "1.5.1") - Run
sbt lockto generatebuild.sbt.lock - Commit
build.sbt.lockto version control
test-module-exists
- Create
src/test/scala/ - Add a test framework dependency (ScalaTest, MUnit, or Specs2)
- Add at least one test file under
src/test/scala/
scalafmt-configured
- Add
.scalafmt.confat the repo root with at least:version = "3.7.17" runner.dialect = scala213 - Add the scalafmt plugin to
project/plugins.sbt:addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") - Run
sbt scalafmtAllto format the codebase
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.