SBT Repositories
This section provides comprehensive documentation for configuring and using SBT-based repositories with CloudRepo for Scala projects.
Overview
SBT (Scala Build Tool) is the de facto build tool for Scala projects, providing powerful dependency management, incremental compilation, and cross-compilation capabilities. SBT uses a Scala-based DSL and integrates seamlessly with both Maven and Ivy repository formats.
SBT and Repository Formats
SBT can work with both Maven and Ivy repository formats:
Maven Repositories: The most common format, compatible with Maven Central and most artifact repositories
Ivy Repositories: Legacy format still used by some Scala libraries, particularly older ones
CloudRepo supports Maven repository format, which is fully compatible with SBT and covers the vast majority of use cases.
Why Private SBT Repositories?
Scala development teams need private repositories to:
Protect Proprietary Code: Secure internal Scala libraries and domain-specific languages (DSLs)
Manage Cross-Compilation: Store artifacts compiled for multiple Scala versions (2.12, 2.13, 3.x)
Distribute SBT Plugins: Share custom SBT plugins within your organization
Control Dependencies: Ensure consistent dependency versions across microservices
Support Multiple Platforms: Manage artifacts for JVM, Scala.js, and Scala Native
Cache Dependencies: Improve build times by caching commonly used libraries
CloudRepo provides fully managed, cloud-based repositories that eliminate infrastructure overhead while providing enterprise-grade security and no egress fees.
Prerequisites
Before configuring SBT with CloudRepo, ensure you have:
Created a Maven Repository: Set up a Maven-type repository in the CloudRepo Admin Portal
Created a Repository User: Configure a dedicated user for repository access
Installed SBT: Version 1.0 or higher recommended
If you haven’t completed the repository setup, please refer to:
Important
Admin users cannot directly access repositories for security reasons. Always create dedicated repository users for artifact access.
Note
CloudRepo repositories use the following URL format:
https://[organization-id].mycloudrepo.io/repositories/[repository-id]
Basic Configuration
SBT configuration is typically done in build.sbt
at the project root. We’ll cover both consuming and publishing artifacts.
Setting Up Resolvers
Add CloudRepo as a resolver to fetch dependencies:
1// CloudRepo resolver for private dependencies
2resolvers += "CloudRepo" at "https://your-org.mycloudrepo.io/repositories/your-repo"
3
4// Include standard resolvers
5resolvers ++= Seq(
6 Resolver.mavenCentral,
7 Resolver.sonatypeRepo("releases"),
8 Resolver.sonatypeRepo("snapshots")
9)
10
11// Dependencies from CloudRepo
12libraryDependencies ++= Seq(
13 "com.yourcompany" %% "your-scala-library" % "1.0.0",
14 "com.yourcompany" % "your-java-library" % "2.1.0"
15)
Note
Use %%
for Scala libraries (adds Scala version suffix) and %
for Java libraries.
Authentication Setup
SBT supports multiple authentication methods. Choose the one that best fits your workflow:
Method 1: Credentials File (Recommended)
Create a credentials file at ~/.sbt/.credentials
:
1realm=CloudRepo
2host=your-org.mycloudrepo.io
3user=your-username
4password=your-password
Then reference it in build.sbt
:
1credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
Method 2: Environment Variables
Use environment variables for CI/CD environments:
1credentials += Credentials(
2 "CloudRepo",
3 "your-org.mycloudrepo.io",
4 sys.env.getOrElse("CLOUDREPO_USERNAME", ""),
5 sys.env.getOrElse("CLOUDREPO_PASSWORD", "")
6)
Method 3: Inline Credentials (Not Recommended)
For testing only - never commit credentials to version control:
1credentials += Credentials(
2 "CloudRepo",
3 "your-org.mycloudrepo.io",
4 "username",
5 "password"
6)
Publishing Configuration
Configure SBT to publish artifacts to CloudRepo:
Basic Publishing Setup
1// Organization and artifact settings
2organization := "com.yourcompany"
3name := "your-scala-library"
4version := "1.0.0"
5
6// Scala version and cross-compilation
7scalaVersion := "2.13.12"
8crossScalaVersions := Seq("2.12.18", "2.13.12", "3.3.1")
9
10// Publishing settings
11publishTo := {
12 val cloudRepo = "https://your-org.mycloudrepo.io/repositories/"
13 if (isSnapshot.value)
14 Some("snapshots" at cloudRepo + "snapshots")
15 else
16 Some("releases" at cloudRepo + "releases")
17}
18
19// Include sources and javadocs
20publishArtifact in (Compile, packageSrc) := true
21publishArtifact in (Compile, packageDoc) := true
22
23// POM customization
24pomIncludeRepository := { _ => false }
25pomExtra := (
26 <url>https://github.com/yourcompany/your-library</url>
27 <licenses>
28 <license>
29 <name>Apache 2.0</name>
30 <url>http://www.apache.org/licenses/LICENSE-2.0</url>
31 </license>
32 </licenses>
33 <scm>
34 <connection>scm:git:github.com/yourcompany/your-library.git</connection>
35 <developerConnection>scm:git:git@github.com:yourcompany/your-library.git</developerConnection>
36 <url>github.com/yourcompany/your-library</url>
37 </scm>
38 <developers>
39 <developer>
40 <id>johndoe</id>
41 <name>John Doe</name>
42 <email>john@yourcompany.com</email>
43 </developer>
44 </developers>
45)
Publishing Commands
Once configured, use these SBT commands:
1# Publish to CloudRepo
2sbt publish
3
4# Publish locally for testing
5sbt publishLocal
6
7# Cross-publish for all Scala versions
8sbt +publish
9
10# Publish signed artifacts (if GPG configured)
11sbt publishSigned
12
13# Clean, compile, test, and publish
14sbt clean compile test publish
Advanced Publishing Features
SNAPSHOT vs Release Versions
SBT automatically detects SNAPSHOT versions:
1version := "1.0.0-SNAPSHOT" // Will publish to snapshots repository
2
3publishTo := {
4 val baseUrl = "https://your-org.mycloudrepo.io/repositories/"
5 if (version.value.endsWith("SNAPSHOT"))
6 Some("CloudRepo Snapshots" at baseUrl + "snapshots")
7 else
8 Some("CloudRepo Releases" at baseUrl + "releases")
9}
10
11// Overwrite snapshots (useful for CI)
12publishConfiguration := publishConfiguration.value.withOverwrite(true)
13publishLocalConfiguration := publishLocalConfiguration.value.withOverwrite(true)
Cross-Building for Multiple Scala Versions
1scalaVersion := "2.13.12"
2crossScalaVersions := Seq("2.12.18", "2.13.12", "3.3.1")
3
4// Version-specific dependencies
5libraryDependencies ++= {
6 CrossVersion.partialVersion(scalaVersion.value) match {
7 case Some((2, 12)) =>
8 Seq("org.scala-lang.modules" %% "scala-collection-compat" % "2.11.0")
9 case Some((2, 13)) =>
10 Seq.empty
11 case Some((3, _)) =>
12 Seq.empty
13 case _ =>
14 Seq.empty
15 }
16}
17
18// Publish all cross-built versions
19// Run: sbt +publish
Consuming Dependencies
Configuring Multiple Repositories
1// Define repository URLs
2val cloudRepoReleases = "CloudRepo Releases" at
3 "https://your-org.mycloudrepo.io/repositories/releases"
4val cloudRepoSnapshots = "CloudRepo Snapshots" at
5 "https://your-org.mycloudrepo.io/repositories/snapshots"
6
7// Configure resolvers with priority order
8resolvers ++= Seq(
9 cloudRepoReleases,
10 cloudRepoSnapshots,
11 Resolver.mavenCentral,
12 Resolver.sonatypeRepo("releases"),
13 "Typesafe Repository" at "https://repo.typesafe.com/typesafe/releases/",
14 Resolver.jcenterRepo
15)
16
17// Credentials for private repositories
18credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
19
20// Dependencies
21libraryDependencies ++= Seq(
22 "com.yourcompany" %% "core-library" % "2.1.0",
23 "com.yourcompany" %% "utils" % "1.3.2",
24 "com.typesafe.akka" %% "akka-actor" % "2.8.5",
25 "org.scalatest" %% "scalatest" % "3.2.17" % Test
26)
Resolver Chains and Patterns
Configure custom resolver patterns for non-standard layouts:
1// Maven-style resolver (default)
2resolvers += "CloudRepo Maven" at
3 "https://your-org.mycloudrepo.io/repositories/maven"
4
5// Ivy-style resolver with custom pattern
6resolvers += Resolver.url(
7 "CloudRepo Ivy",
8 url("https://your-org.mycloudrepo.io/repositories/ivy")
9)(Resolver.ivyStylePatterns)
10
11// Custom artifact pattern
12resolvers += {
13 val patterns = Patterns()
14 .withIsMavenCompatible(true)
15 .withArtifactPatterns(Vector(
16 "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]"
17 ))
18 .withIvyPatterns(Vector(
19 "[organisation]/[module]/[revision]/ivy.xml"
20 ))
21
22 Resolver.url("CloudRepo Custom",
23 url("https://your-org.mycloudrepo.io/repositories/custom"))(patterns)
24}
Cache Management
Control how SBT caches dependencies:
1// Force update of snapshots
2updateOptions := updateOptions.value.withLatestSnapshots(true)
3
4// Cache resolution for faster builds
5updateOptions := updateOptions.value.withCachedResolution(true)
6
7// Custom cache location
8dependencyCacheDirectory := baseDirectory.value / ".cache"
9
10// Clean cache task
11val cleanCache = taskKey[Unit]("Clean dependency cache")
12cleanCache := {
13 import sbt.io.IO
14 IO.delete(dependencyCacheDirectory.value)
15}
Multi-Project Builds
SBT excels at managing multi-module projects:
Project Structure
my-application/
├── build.sbt
├── project/
│ ├── build.properties
│ ├── plugins.sbt
│ └── Dependencies.scala
├── common/
│ └── src/
├── core/
│ └── src/
├── api/
│ └── src/
└── web/
└── src/
Root Build Configuration
1import Dependencies._
2
3ThisBuild / organization := "com.yourcompany"
4ThisBuild / scalaVersion := "2.13.12"
5ThisBuild / version := "1.0.0-SNAPSHOT"
6
7// CloudRepo configuration for all projects
8ThisBuild / resolvers += "CloudRepo" at
9 "https://your-org.mycloudrepo.io/repositories/your-repo"
10
11ThisBuild / publishTo := {
12 val cloudRepo = "https://your-org.mycloudrepo.io/repositories/"
13 if (isSnapshot.value)
14 Some("snapshots" at cloudRepo + "snapshots")
15 else
16 Some("releases" at cloudRepo + "releases")
17}
18
19ThisBuild / credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
20
21// Root project (doesn't publish)
22lazy val root = (project in file("."))
23 .settings(
24 name := "my-application",
25 publish / skip := true
26 )
27 .aggregate(common, core, api, web)
28
29// Common utilities module
30lazy val common = (project in file("common"))
31 .settings(
32 name := "common",
33 libraryDependencies ++= commonDependencies
34 )
35
36// Core business logic
37lazy val core = (project in file("core"))
38 .settings(
39 name := "core",
40 libraryDependencies ++= coreDependencies
41 )
42 .dependsOn(common)
43
44// API module
45lazy val api = (project in file("api"))
46 .settings(
47 name := "api",
48 libraryDependencies ++= apiDependencies
49 )
50 .dependsOn(core)
51
52// Web application
53lazy val web = (project in file("web"))
54 .settings(
55 name := "web",
56 libraryDependencies ++= webDependencies,
57 // Don't publish the web module
58 publish / skip := true
59 )
60 .dependsOn(api)
Dependencies Object
1import sbt._
2
3object Dependencies {
4 // Versions
5 val akkaVersion = "2.8.5"
6 val circeVersion = "0.14.6"
7 val http4sVersion = "0.23.23"
8 val scalaTestVersion = "3.2.17"
9
10 // Common dependencies
11 val commonDependencies = Seq(
12 "org.typelevel" %% "cats-core" % "2.10.0",
13 "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5",
14 "ch.qos.logback" % "logback-classic" % "1.4.11",
15 "org.scalatest" %% "scalatest" % scalaTestVersion % Test
16 )
17
18 // Core dependencies
19 val coreDependencies = Seq(
20 "com.typesafe.akka" %% "akka-actor-typed" % akkaVersion,
21 "com.typesafe.akka" %% "akka-stream" % akkaVersion,
22 "io.circe" %% "circe-core" % circeVersion,
23 "io.circe" %% "circe-generic" % circeVersion,
24 "io.circe" %% "circe-parser" % circeVersion
25 )
26
27 // API dependencies
28 val apiDependencies = Seq(
29 "org.http4s" %% "http4s-ember-server" % http4sVersion,
30 "org.http4s" %% "http4s-circe" % http4sVersion,
31 "org.http4s" %% "http4s-dsl" % http4sVersion
32 )
33
34 // Web dependencies
35 val webDependencies = Seq(
36 "org.http4s" %% "http4s-ember-client" % http4sVersion,
37 "org.http4s" %% "http4s-scala-xml" % http4sVersion
38 )
39}
Advanced SBT Features
Cross-Platform Building
Build for JVM, Scala.js, and Scala Native:
1import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
2
3lazy val sharedSettings = Seq(
4 organization := "com.yourcompany",
5 version := "1.0.0",
6 scalaVersion := "2.13.12"
7)
8
9lazy val myLibrary = crossProject(JVMPlatform, JSPlatform, NativePlatform)
10 .crossType(CrossType.Pure)
11 .in(file("my-library"))
12 .settings(sharedSettings)
13 .settings(
14 name := "my-cross-platform-library",
15 libraryDependencies ++= Seq(
16 "org.scalatest" %%% "scalatest" % "3.2.17" % Test
17 )
18 )
19 .jvmSettings(
20 // JVM-specific settings
21 libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.8.5"
22 )
23 .jsSettings(
24 // Scala.js-specific settings
25 scalaJSUseMainModuleInitializer := true,
26 libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0"
27 )
28 .nativeSettings(
29 // Scala Native-specific settings
30 nativeLinkStubs := true
31 )
32
33lazy val myLibraryJVM = myLibrary.jvm
34lazy val myLibraryJS = myLibrary.js
35lazy val myLibraryNative = myLibrary.native
SBT Plugin Distribution
Create and distribute custom SBT plugins via CloudRepo:
1// Plugin project build.sbt
2sbtPlugin := true
3organization := "com.yourcompany"
4name := "sbt-custom-plugin"
5version := "0.1.0"
6
7publishTo := Some("CloudRepo" at
8 "https://your-org.mycloudrepo.io/repositories/sbt-plugins")
9
10// Add plugin dependencies
11addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.5")
To use the published plugin in other projects:
1resolvers += "CloudRepo Plugins" at
2 "https://your-org.mycloudrepo.io/repositories/sbt-plugins"
3
4addSbtPlugin("com.yourcompany" % "sbt-custom-plugin" % "0.1.0")
Assembly Plugin for Fat JARs
Create executable fat JARs with all dependencies:
1import sbtassembly.AssemblyPlugin.autoImport._
2
3// Assembly settings
4assembly / assemblyJarName := s"${name.value}-${version.value}-fat.jar"
5
6assembly / mainClass := Some("com.yourcompany.Main")
7
8// Merge strategy for duplicate files
9assembly / assemblyMergeStrategy := {
10 case "META-INF/services/org.apache.spark.sql.sources.DataSourceRegister" =>
11 MergeStrategy.concat
12 case PathList("META-INF", xs @ _*) => MergeStrategy.discard
13 case "reference.conf" => MergeStrategy.concat
14 case x => MergeStrategy.defaultMergeStrategy(x)
15}
16
17// Exclude Scala library from fat JAR (if provided at runtime)
18assembly / assemblyOption := (assembly / assemblyOption).value
19 .withIncludeScala(false)
20
21// Publish fat JAR to CloudRepo
22addArtifact(assembly / assemblyArtifact)
23
24publishTo := Some("CloudRepo" at
25 "https://your-org.mycloudrepo.io/repositories/releases")
Custom Tasks and Commands
1// Custom deployment task
2val deploy = taskKey[Unit]("Deploy to CloudRepo and notify")
3
4deploy := {
5 val log = streams.value.log
6
7 // Run tests
8 (Test / test).value
9 log.info("Tests passed")
10
11 // Publish artifacts
12 publish.value
13 log.info(s"Published ${name.value} ${version.value} to CloudRepo")
14
15 // Custom notification logic
16 val webhook = "https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
17 import scala.sys.process._
18 val message = s"""{"text":"Deployed ${name.value} ${version.value}"}"""
19 s"""curl -X POST -H 'Content-Type: application/json' -d '$message' $webhook""".!
20}
21
22// Custom command with arguments
23commands += Command.args("release", "<version>") { (state, args) =>
24 val version = args.headOption.getOrElse("1.0.0")
25 s"""set version := "$version"""" ::
26 "clean" ::
27 "compile" ::
28 "test" ::
29 "publish" ::
30 state
31}
Coursier for Faster Resolution
Use Coursier for faster dependency resolution:
1addSbtCoursier
1// Coursier cache configuration
2csrCacheDirectory := Some(baseDirectory.value / ".coursier-cache")
3
4// Parallel downloads
5coursierParallelDownloads := 8
6
7// Custom repository with Coursier
8resolvers += MavenRepository(
9 "CloudRepo",
10 "https://your-org.mycloudrepo.io/repositories/releases",
11 credentials = Credentials(Path.userHome / ".sbt" / ".credentials")
12)
CI/CD Integration
GitHub Actions
1name: Scala CI
2
3on:
4 push:
5 branches: [ main, develop ]
6 pull_request:
7 branches: [ main ]
8
9jobs:
10 test:
11 runs-on: ubuntu-latest
12
13 strategy:
14 matrix:
15 scala: [ '2.12.18', '2.13.12', '3.3.1' ]
16
17 steps:
18 - uses: actions/checkout@v3
19
20 - name: Setup JDK
21 uses: actions/setup-java@v3
22 with:
23 distribution: 'temurin'
24 java-version: '11'
25
26 - name: Setup Scala
27 uses: olafurpg/setup-scala@v13
28 with:
29 java-version: '11'
30
31 - name: Cache SBT
32 uses: actions/cache@v3
33 with:
34 path: |
35 ~/.sbt
36 ~/.ivy2/cache
37 ~/.coursier
38 key: ${{ runner.os }}-sbt-${{ matrix.scala }}-${{ hashFiles('**/build.sbt') }}
39
40 - name: Configure CloudRepo credentials
41 run: |
42 mkdir -p ~/.sbt
43 echo "realm=CloudRepo" > ~/.sbt/.credentials
44 echo "host=${{ secrets.CLOUDREPO_HOST }}" >> ~/.sbt/.credentials
45 echo "user=${{ secrets.CLOUDREPO_USERNAME }}" >> ~/.sbt/.credentials
46 echo "password=${{ secrets.CLOUDREPO_PASSWORD }}" >> ~/.sbt/.credentials
47
48 - name: Run tests
49 run: sbt ++${{ matrix.scala }} clean coverage test coverageReport
50
51 - name: Publish snapshot
52 if: github.ref == 'refs/heads/develop'
53 run: sbt ++${{ matrix.scala }} publish
54
55 - name: Publish release
56 if: github.ref == 'refs/heads/main'
57 run: |
58 VERSION=$(git describe --tags --abbrev=0)
59 sbt ++${{ matrix.scala }} 'set version := "'$VERSION'"' publish
GitLab CI
1image: hseeberger/scala-sbt:11.0.15_1.7.1_2.13.12
2
3variables:
4 SBT_OPTS: "-Dsbt.global.base=sbt-cache/.sbtboot -Dsbt.boot.directory=sbt-cache/.boot -Dsbt.ivy.home=sbt-cache/.ivy"
5 CLOUDREPO_HOST: "your-org.mycloudrepo.io"
6
7cache:
8 key: "$CI_PROJECT_ID"
9 untracked: true
10 paths:
11 - sbt-cache/
12
13before_script:
14 - mkdir -p ~/.sbt
15 - |
16 cat > ~/.sbt/.credentials << EOF
17 realm=CloudRepo
18 host=$CLOUDREPO_HOST
19 user=$CLOUDREPO_USERNAME
20 password=$CLOUDREPO_PASSWORD
21 EOF
22
23stages:
24 - test
25 - publish
26
27test:
28 stage: test
29 script:
30 - sbt clean coverage test coverageReport
31 artifacts:
32 reports:
33 junit:
34 - target/test-reports/*.xml
35 paths:
36 - target/scala-*/scoverage-report/
37
38publish-snapshot:
39 stage: publish
40 script:
41 - sbt publish
42 only:
43 - develop
44
45publish-release:
46 stage: publish
47 script:
48 - VERSION=$(git describe --tags --abbrev=0)
49 - sbt "set version := \"$VERSION\"" publish
50 only:
51 - tags
Jenkins Pipeline
1pipeline {
2 agent {
3 docker {
4 image 'hseeberger/scala-sbt:11.0.15_1.7.1_2.13.12'
5 args '-v /var/run/docker.sock:/var/run/docker.sock'
6 }
7 }
8
9 environment {
10 CLOUDREPO_CREDS = credentials('cloudrepo-credentials')
11 SBT_OPTS = '-Xmx2G -XX:+UseG1GC'
12 }
13
14 stages {
15 stage('Setup') {
16 steps {
17 sh '''
18 mkdir -p ~/.sbt
19 cat > ~/.sbt/.credentials << EOF
20realm=CloudRepo
21host=your-org.mycloudrepo.io
22user=$CLOUDREPO_CREDS_USR
23password=$CLOUDREPO_CREDS_PSW
24EOF
25 '''
26 }
27 }
28
29 stage('Compile') {
30 steps {
31 sh 'sbt clean compile'
32 }
33 }
34
35 stage('Test') {
36 parallel {
37 stage('Unit Tests') {
38 steps {
39 sh 'sbt test'
40 }
41 }
42 stage('Integration Tests') {
43 steps {
44 sh 'sbt it:test'
45 }
46 }
47 }
48 }
49
50 stage('Package') {
51 steps {
52 sh 'sbt package assembly'
53 }
54 }
55
56 stage('Publish') {
57 when {
58 anyOf {
59 branch 'main'
60 branch 'develop'
61 tag pattern: "v\\d+\\.\\d+\\.\\d+", comparator: "REGEXP"
62 }
63 }
64 steps {
65 script {
66 if (env.TAG_NAME) {
67 sh "sbt 'set version := \"${env.TAG_NAME.substring(1)}\"' publish"
68 } else {
69 sh 'sbt publish'
70 }
71 }
72 }
73 }
74 }
75
76 post {
77 always {
78 junit '**/target/test-reports/*.xml'
79 archiveArtifacts artifacts: '**/target/scala-*/*.jar', fingerprint: true
80 }
81 success {
82 echo 'Pipeline successful!'
83 }
84 failure {
85 emailext(
86 subject: "Build Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
87 body: "Check console output at ${env.BUILD_URL}",
88 to: 'team@yourcompany.com'
89 )
90 }
91 }
92}
Legacy SBT Support
For projects using SBT 0.13.x (legacy), some syntax differs:
1// SBT 0.13.x style
2organization := "com.yourcompany"
3name := "legacy-project"
4version := "1.0.0"
5scalaVersion := "2.11.12"
6
7// Resolver configuration (0.13.x)
8resolvers += "CloudRepo" at "https://your-org.mycloudrepo.io/repositories/releases"
9
10// Publishing (0.13.x)
11publishTo <<= version { v: String =>
12 val cloudRepo = "https://your-org.mycloudrepo.io/repositories/"
13 if (v.trim.endsWith("SNAPSHOT"))
14 Some("snapshots" at cloudRepo + "snapshots")
15 else
16 Some("releases" at cloudRepo + "releases")
17}
18
19// Credentials (0.13.x)
20credentials += Credentials(Path.userHome / ".ivy2" / ".credentials")
21
22// Dependencies (0.13.x)
23libraryDependencies ++= Seq(
24 "com.yourcompany" %% "core" % "1.0.0",
25 "org.scalatest" %% "scalatest" % "2.2.6" % "test"
26)
Troubleshooting
Common Issues and Solutions
Authentication Failures
Problem: 401 Unauthorized
errors when resolving or publishing.
Solutions:
Verify credentials are correct:
curl -u username:password https://your-org.mycloudrepo.io/repositories/releases/
Check credentials file format and location:
cat ~/.sbt/.credentials # Should show realm, host, user, password on separate lines
Ensure realm matches exactly:
credentials += Credentials("CloudRepo", "your-org.mycloudrepo.io", "user", "pass")
Dependency Resolution Issues
Problem: SBT cannot find dependencies in CloudRepo.
Solutions:
Check resolver URL format:
// Correct resolvers += "CloudRepo" at "https://your-org.mycloudrepo.io/repositories/releases" // Incorrect (missing /repositories/) resolvers += "CloudRepo" at "https://your-org.mycloudrepo.io/releases"
Verify artifact coordinates:
# List repository contents curl -u username:password https://your-org.mycloudrepo.io/repositories/releases/com/yourcompany/
Clear caches:
rm -rf ~/.ivy2/cache/com.yourcompany rm -rf ~/.coursier/cache sbt clean update
Cross-Compilation Issues
Problem: Published artifacts missing for some Scala versions.
Solution:
# Ensure all versions are published
sbt +publish # Note the + prefix
# Or explicitly for each version
sbt ++2.12.18 publish
sbt ++2.13.12 publish
sbt ++3.3.1 publish
Snapshot Overwriting
Problem: Snapshots not updating despite new publishes.
Solution:
// Force snapshot updates
updateOptions := updateOptions.value.withLatestSnapshots(true)
// For publishing, allow overwrites
publishConfiguration := publishConfiguration.value.withOverwrite(true)
Build Performance
Problem: Slow dependency resolution.
Solutions:
Enable Coursier for faster resolution:
// In project/plugins.sbt addSbtCoursier
Use cached resolution:
updateOptions := updateOptions.value.withCachedResolution(true)
Parallel downloads:
concurrent.restrictions in Global := Seq( Tags.limit(Tags.Test, 1), Tags.limitAll(15) )
Best Practices
Version Management
Use semantic versioning (MAJOR.MINOR.PATCH)
Tag releases in Git to match published versions
Use SNAPSHOT suffix for development versions
Security
Never commit credentials to version control
Use environment variables in CI/CD
Rotate credentials regularly
Use read-only credentials where possible
Repository Organization
Separate releases and snapshots repositories
Use descriptive artifact names
Include sources and documentation
Clean up old snapshots periodically
Build Optimization
Cache dependencies in CI/CD
Use Coursier for faster resolution
Parallelize test execution
Minimize resolver chain length
Documentation
Document custom SBT tasks
Include README with setup instructions
Document cross-compilation requirements
Maintain CHANGELOG for releases
Summary
SBT with CloudRepo provides a powerful, scalable solution for managing Scala artifacts. Key benefits include:
Seamless Integration: Native support for Maven repository format
Cross-Compilation: Easy management of multiple Scala versions
No Egress Fees: Cost-effective artifact distribution
Enterprise Security: Fine-grained access controls
Multi-Platform Support: JVM, Scala.js, and Scala Native
With proper configuration, teams can efficiently share Scala libraries, manage dependencies, and maintain consistent builds across development, staging, and production environments.
Additional Resources
For additional help or questions, please contact CloudRepo support. We typically respond within a few business hours and are happy to help with any SBT configuration challenges.