Scalafmt with Docker
Scalafmt is a popular formatter for Scala. The formatting it produces is not always identical across versions, even with the same configuration file. To ensure all developers on a team format the code in the same way, I’ll show you how to roll your own Scalafmt action container with Docker.
All of my Scala projects have a .scalafmt.conf
file in the root to ensure consistent formatting:
style = "IntelliJ"
version = "2.4.2"
maxColumn = 100
newlines.alwaysBeforeTopLevelStatements = true
newlines.penalizeSingleSelectMultiArgList = false
rewrite.rules = [
"RedundantBraces"
"RedundantParens"
"SortImports"
"PreferCurlyFors" ]
rewrite.redundantBraces.stringInterpolation = truene
danglingParentheses = false
spaces.afterTripleEquals = true
align.openParenDefnSite = true
align.openParenCallSite = false
literals.long = Upper
literals.float = Lower
literals.double = Upper
Although it lists a specific version
, I have noticed that different Scalafmt versions can produce different results; version
is as of this writing not used anywhere.
There is now an edition
option, but that has not always been there.
So, let’s build a Docker image instead.
Dockerfile
The following Docker configuration can be used to create an action container for the scalafmt
command:
FROM alpine:3.11.3
RUN apk --no-cache add curl openjdk11-jre-headless
WORKDIR /scripts
RUN curl -Lo coursier https://git.io/coursier-cli && chmod +x /scripts/coursier
RUN /scripts/coursier bootstrap org.scalameta:scalafmt-cli_2.12:2.4.2 \
-r sonatype:snapshots \
-o /usr/local/bin/scalafmt \
--standalone \
--main org.scalafmt.cli.Cli
RUN rm -f /scripts/coursier
ENTRYPOINT ["scalafmt"]
It uses a small Linux base image and follows the installation instructions.
The headless JRE is installed because scalafmt
is a command-line tool, so it does not need any graphical components.
There is no need to grab the JDK either.
To build the image, execute docker build -t scalafmt:2.4.2 $(pwd)
.
Please note that the tag matches the Scalafmt version.
Alias
For development on your own machine, I recommend an alias:
alias scalafmt='docker run --rm -w $(pwd) -v $(pwd):$(pwd) scalafmt:2.4.2 --exclude target'
That way, you can run scalafmt
from a project’s root, as if you had Scalafmt installed locally.
It automatically excludes the target
directory.
If, however, you want to exclude more or different directories, add those to the alias itself or leave off --exclude target
altogether.
Whenever the team decides to upgrade to a newer Scalafmt version, you can
- Rebuild the image;
- Push it to a container registry;
- Have everyone update their aliases.
That way, everyone is guaranteed to produce the same formatting.
You may wonder why I do not suggest the native image instead. Unfortunately, it does not yet work on Windows, so it’s not portable. More importantly, I never got it to work on my machine. Docker (almost) always works.