Infrastructure worth keeping — and kept patched.

One build cache server for Gradle and Maven

If your company builds some projects with Gradle and others with Maven, you do not need two cache servers. FosterStack Cache serves both, with one login. This is a real run: a repository with a Gradle app and a Maven app, both pointed at one 0.2.1 server. Maven works through the Apache Maven Build Cache Extension.

The repository

mixed-repo/
  gradle-app/    settings.gradle.kts, build.gradle.kts, gradle.properties, src/
  maven-app/     pom.xml, settings.xml, src/, .mvn/extensions.xml, .mvn/maven-build-cache-config.xml

Two small Java apps, built by two different tools.

One server, one login

FSCACHE_USERNAME=build FSCACHE_PASSWORD=<a long secret> ./fscache

Both tools send that same login, each in its own way. The secret comes from one environment variable, FSCACHE_PASSWORD.

The Gradle side

gradle-app/settings.gradle.kts, with org.gradle.caching=true in gradle.properties:

rootProject.name = "gradle-app"

// FosterStack Cache — remote Gradle build cache.
// https://github.com/fosterstack/cache
buildCache {
    remote<HttpBuildCache> {
        url = uri("https://cache.example.com/")
        isPush = true
        credentials {
            username = "build"
            password = System.getenv("FSCACHE_PASSWORD")
        }
    }
}

The Maven side

maven-app/.mvn/maven-build-cache-config.xml. The remote element goes inside configuration, and saveToRemote="true" is what makes it upload:

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://maven.apache.org/BUILD-CACHE-CONFIG/1.2.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/BUILD-CACHE-CONFIG/1.2.0 https://maven.apache.org/xsd/build-cache-config-1.2.0.xsd">
  <configuration>
    <enabled>true</enabled>
    <!-- FosterStack Cache — remote Maven build cache.
         https://github.com/fosterstack/cache -->
    <remote enabled="true" saveToRemote="true" id="fosterstack-cache">
      <url>https://cache.example.com/</url>
    </remote>
  </configuration>
</cache>

And settings.xml, whose server id must match the remote's. Maven filled in the password from the same environment variable:

<settings>
  <servers>
    <server>
      <id>fosterstack-cache</id>
      <username>build</username>
      <password>${env.FSCACHE_PASSWORD}</password>
    </server>
  </servers>
</settings>

The extension itself is added in .mvn/extensions.xml. See Maven build cache extension: remote server setup.

What happened

Each app was built twice. For Gradle, I ran gradle clean in between. For Maven, I deleted target and the extension's local cache folder, so the only copy left was on the server. (I also turned Gradle's local cache off.)

BuildResultServer afterwards
Gradle, first:compileJava ran1 entry
Gradle, second> Task :compileJava FROM-CACHE, "1 from cache"1 hit
Maven, firstbuilt, then three lines of Saved to remote cache4 entries in all
Maven, secondFound cached build, restoring demo:maven-app from cache3 hits in all

The counts are the server's own, from its status page. Gradle stores its work under keys of a single long hex number. The Maven extension stores its files under a path. Here is what the server held on disk afterwards:

blobs/8a/8a2fb682ab19c1d434fd2d1ee3e8b27a                              (Gradle)
blobs/v1.1/demo/maven-app/3aa3eaca44f8d0fa/ma/maven-app.jar            (Maven)
blobs/v1.1/demo/maven-app/3aa3eaca44f8d0fa/bu/buildinfo.xml            (Maven)
blobs/v1.1/demo/maven-app/e17172d0-.../bu/build-cache-report.xml       (Maven)
blobs/v1.1/demo/maven-app/14c158a7-.../bu/build-cache-report.xml       (Maven)

They sit side by side in one store, under one size cap, watched by one set of metrics. See server sizing and monitoring.

What this does not show

Related: Gradle build cache tutorial and Maven build cache extension not restoring.

Gradle and Maven setup FosterStack home