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:

  1. Created a Maven Repository: Set up a Maven-type repository in the CloudRepo Admin Portal

  2. Created a Repository User: Configure a dedicated user for repository access

  3. 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:

build.sbt - Basic Resolver Configuration
 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 2: Environment Variables

Use environment variables for CI/CD environments:

build.sbt - Environment Variables
1credentials += Credentials(
2  "CloudRepo",
3  "your-org.mycloudrepo.io",
4  sys.env.getOrElse("CLOUDREPO_USERNAME", ""),
5  sys.env.getOrElse("CLOUDREPO_PASSWORD", "")
6)

Publishing Configuration

Configure SBT to publish artifacts to CloudRepo:

Basic Publishing Setup

build.sbt - Publishing Configuration
 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:

Publishing 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:

build.sbt - Version-based Publishing
 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

build.sbt - Cross-Building Configuration
 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

build.sbt - Multiple Repository Configuration
 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:

build.sbt - Custom Resolver Patterns
 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:

build.sbt - Cache Configuration
 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

Multi-Project Structure
my-application/
├── build.sbt
├── project/
│   ├── build.properties
│   ├── plugins.sbt
│   └── Dependencies.scala
├── common/
│   └── src/
├── core/
│   └── src/
├── api/
│   └── src/
└── web/
    └── src/

Root Build Configuration

build.sbt - Multi-Project 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

project/Dependencies.scala
 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:

build.sbt - Cross-Platform Configuration
 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:

project/plugins.sbt - Custom Plugin
 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:

project/plugins.sbt - Using Custom Plugin
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:

build.sbt - Assembly Configuration
 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

build.sbt - Custom Tasks
 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:

project/plugins.sbt - Coursier Setup
1addSbtCoursier
build.sbt - Coursier Configuration
 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

.github/workflows/scala-ci.yml
 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

.gitlab-ci.yml
 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

Jenkinsfile
 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:

build.sbt - SBT 0.13.x Syntax
 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:

  1. Verify credentials are correct:

    curl -u username:password https://your-org.mycloudrepo.io/repositories/releases/
    
  2. Check credentials file format and location:

    cat ~/.sbt/.credentials
    # Should show realm, host, user, password on separate lines
    
  3. Ensure realm matches exactly:

    credentials += Credentials("CloudRepo", "your-org.mycloudrepo.io", "user", "pass")
    

Dependency Resolution Issues

Problem: SBT cannot find dependencies in CloudRepo.

Solutions:

  1. 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"
    
  2. Verify artifact coordinates:

    # List repository contents
    curl -u username:password https://your-org.mycloudrepo.io/repositories/releases/com/yourcompany/
    
  3. 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:

  1. Enable Coursier for faster resolution:

    // In project/plugins.sbt
    addSbtCoursier
    
  2. Use cached resolution:

    updateOptions := updateOptions.value.withCachedResolution(true)
    
  3. Parallel downloads:

    concurrent.restrictions in Global := Seq(
      Tags.limit(Tags.Test, 1),
      Tags.limitAll(15)
    )
    

Best Practices

  1. Version Management

    • Use semantic versioning (MAJOR.MINOR.PATCH)

    • Tag releases in Git to match published versions

    • Use SNAPSHOT suffix for development versions

  2. Security

    • Never commit credentials to version control

    • Use environment variables in CI/CD

    • Rotate credentials regularly

    • Use read-only credentials where possible

  3. Repository Organization

    • Separate releases and snapshots repositories

    • Use descriptive artifact names

    • Include sources and documentation

    • Clean up old snapshots periodically

  4. Build Optimization

    • Cache dependencies in CI/CD

    • Use Coursier for faster resolution

    • Parallelize test execution

    • Minimize resolver chain length

  5. 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.