GitLab CI template for sbt¶
This project implements a GitLab CI/CD template to build, test and analyse your sbt-based projects.
Languages supported by this build tool are :
Usage¶
This template can be used both as a CI/CD component
or using the legacy include:project syntax.
Use as a CI/CD component¶
Add the following to your .gitlab-ci.yml:
include:
# 1: include the component
- component: $CI_SERVER_FQDN/to-be-continuous/sbt/gitlab-ci-sbt@1.10.0
# 2: set/override component inputs
inputs:
image: "docker.io/sbtscala/scala-sbt:17.0.2_1.6.2_3.1.3" # ⚠ this is only an example
Use as a CI/CD template (legacy)¶
Add the following to your .gitlab-ci.yml:
include:
# 1: include the template
- project: 'to-be-continuous/sbt'
ref: '1.10.0'
file: '/templates/gitlab-ci-sbt.yml'
variables:
# 2: set/override template variables
SBT_IMAGE: "docker.io/sbtscala/scala-sbt:17.0.2_1.6.2_3.1.3" # ⚠ this is only an example
Project prerequisites¶
dependencies resolution¶
In order to configure your project to use a repository cache/proxy such as artifactory or nexus, add those two files into your project root directory :
.sbtoptswith this content :-Dsbt.override.build.repos=true -Dsbt.repository.config=.sbtrepositories.sbtrepositorieswith such content :[repositories] local mirror_of_central: https://mavenrepo.acme.host/maven-proxy-asis-apache-releases confluent-releases : https://mavenrepo.acme.host/maven-proxy-asis-confluent-releases
If some repositories requires credentials, add a file credentials.sbt (you can choose the basename you want)
to your project home directory with such content :
credentials ++= {
List("MAVEN_REPOSITORY_HOST", "MAVEN_REPOSITORY_USERNAME", "MAVEN_REPOSITORY_PASSWORD").flatMap(sys.env.get) match {
case List(host, user, password) =>
streams.value.log.info(s"private/internal dependencies resolution credentials for host '$host' user '$user' has been configured")
Some(Credentials("Artifactory Realm", host, user, password))
case _ =>
streams.value.log.warn(
"private/internal dependencies resolution may fail as some environment variables are missing : MAVEN_REPOSITORY_USERNAME / MAVEN_REPOSITORY_PASSWORD / MAVEN_REPOSITORY_HOST"
)
None
}
}
Which uses three environment variables MAVEN_REPOSITORY_HOST, MAVEN_REPOSITORY_USERNAME, MAVEN_REPOSITORY_PASSWORD from which sbt will
extract credentials information.
Note that thanks to those configurations files, your favorite IDE will be able to automatically take the right repository configuration without any specific configuration.
Global configuration¶
The sbt template uses some global configuration used throughout all jobs.
| Input / Variable | Description | Default value |
|---|---|---|
image / SBT_IMAGE |
The Docker image used to run sbt |
docker.io/sbtscala/scala-sbt:17.0.2_1.6.2_3.1.3 |
opts / SBT_OPTS |
Global sbt options | -Dsbt.global.base=sbt-cache/sbtboot -Dsbt.boot.directory=sbt-cache/boot -Dsbt.coursier.home=sbt-cache/coursier -Dsbt.ci=true -Dsbt.color=always |
cli-opts / SBT_CLI_OPTS |
Additional sbt options used on the command line | --batch |
As you can see, your sbt cache policy is preconfigured to use local cache in sbt-cache directory (not to download
dependencies over and over again).
If you have a good reason to do differently, you'll have to override the SBT_OPTS variable as well as
the cache policy.
Jobs¶
sbt-build job¶
The sbt template features a job sbt-build that performs build and tests at once.
This stage is performed in a single job for optimization purpose (it saves time) and also
for test jobs dependency reasons (some test jobs such as SONAR analysis have a dependency on test results).
It uses the following environment variable:
| Input / Variable | Description | Default value |
|---|---|---|
build-args / SBT_BUILD_ARGS |
sbt arguments for the build job packaging | clean package |
test-args / SBT_TEST_ARGS |
sbt arguments for the build job test phase | coverage test coverageAggregate |
Note:
- Always keep the clean goal to generate bytes code without any instrumentation coming from the test phasis.
About Code Coverage¶
With its default arguments, the GitLab CI template for sbt forces the use of sbt-coverage to compute code coverage during unit tests execution.
But this requires that you add this plugin to your project:
Add the plugin in your project/plugins.sbt:
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.1") // Check for newer releases : https://search.maven.org/artifact/org.scoverage/sbt-scoverage
sbt-sbom job¶
This job generates a SBOM file listing all dependencies using syft.
It is bound to the test stage, and uses the following variables:
In addition to logs in the console, this job produces the following reports, kept for one week:
| Report | Format | Usage |
|---|---|---|
reports/sbt-sbom.cyclonedx.json |
CycloneDX JSON | Security & Compliance integration |
publish jobs¶
The sbt template supports publishing:
- snapshot artifacts (on any branch change),
- and/or release artifacts (on versioned tags such as
x.y.z)
The expected behavior of publish jobs is controlled with the SBT_PUBLISH_MODE variable, supporting one of the
following values:
- none (default): Publishing is disabled.
snapshot: Auto-publishes snapshot artifacts on any branch change.ontag: Auto-publishes snapshot artifacts on any branch change, and publishes release artifacts as soon as a new release tag is committed. In this mode it is up to you to manage release numbering and tagging operations.release: Auto-publishes snapshot artifacts on any branch change, and implements a full publishing workflow with automatic release numbering and git tags management (see release job below for details).
Repository authentication¶
Your publication repository(ies) may require authentication credentials to publish artifacts.
You shall handle them in the following way:
- define all required credentials as: lock: project variables,
- define the target repositories and the credentials
with a dedicated sbt file such as
publish.sbtin your project home directory
Example:
Define the following environment variables :
| Input / Variable | Description |
|---|---|
maven-repository-publish-snapshot-url / MAVEN_REPOSITORY_PUBLISH_SNAPSHOT_URL |
Destination repository to publish snpashot artifacts |
maven-repository-publish-release-url / MAVEN_REPOSITORY_PUBLISH_RELEASE_URL |
Destination repository to publish release artifacts |
MAVEN_REPOSITORY_PUBLISH_USERNAME |
Repository Username |
MAVEN_REPOSITORY_PUBLISH_PASSWORD |
Repository Password |
credentials ++= {
val publishURLProperty = if (isSnapshot.value) "MAVEN_REPOSITORY_PUBLISH_SNAPSHOT_URL" else "MAVEN_REPOSITORY_PUBLISH_RELEASE_URL"
List(publishURLProperty, "MAVEN_REPOSITORY_PUBLISH_USERNAME", "MAVEN_REPOSITORY_PUBLISH_PASSWORD").flatMap(sys.env.get) match {
case List(url, username, password) =>
val host = new java.net.URL(url).getHost
streams.value.log.info(s"publish/release credentials for host '$host' user '$username' has been configured")
Some(Credentials("Artifactory Realm", host, username, password))
case _ =>
streams.value.log.warn(
"publish/release may fail as some environment variables are missing : MAVEN_REPOSITORY_PUBLISH_USERNAME / MAVEN_REPOSITORY_PUBLISH_PASSWORD / MAVEN_REPOSITORY_PUBLISH_SNAPSHOT_URL / MAVEN_REPOSITORY_PUBLISH_RELEASE_URL"
)
None
}
}
publishTo := {
val publishURLProperty = if (isSnapshot.value) "MAVEN_REPOSITORY_PUBLISH_SNAPSHOT_URL" else "MAVEN_REPOSITORY_PUBLISH_RELEASE_URL"
val mayBeTarget =
if (isSnapshot.value) sys.env.get(publishURLProperty).map(url => "snapshots on artifactory".at(url))
else sys.env.get(publishURLProperty).map(url => "releases on artifactory".at(url))
mayBeTarget match {
case None => streams.value.log.warn(s"publish repository target url not given ($publishURLProperty)")
case Some(target) => streams.value.log.info(s"publish to ${target.name} -> $target")
}
mayBeTarget
}
// To avoid error such as "java.net.ProtocolException: Too many follow-up requests: 21"
updateOptions := updateOptions.value.withGigahorse(false)
sbt-release job¶
This job is disabled by default and can be activated by setting the SBT_PUBLISH_MODE to release.
It is based on the sbt-release plugin. You'll have to add it in your
project/plugins.sbt:
// Check for newer releases : https://search.maven.org/artifact/com.github.sbt/sbt-release
addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0")
SCM authentication¶
A sbt release involves some Git push operations. For this you shall use a SSH key.
We recommend you to use a project deploy key with write access to your project.
The key should not have a passphrase ( see how to generate a new SSH key pair).
Specify
$GIT_PRIVATE_KEY as protected project variable with the private part of the deploy key.
-----BEGIN 0PENSSH PRIVATE KEY-----
blablabla
-----END OPENSSH PRIVATE KEY-----