skip to content

How would you route a publish to a release repository for a release version and a snapshot repository for a -SNAPSHOT version using the repository url?

level: middleimportance: should knowfreq 45%

answer

  1. version.endsWith("SNAPSHOT") ? snapshots : releases
  2. url computed at configuration time
  3. one repo computed vs two named repos
  4. version must be set first
  5. base url selects server layout

basics

~10 s

Set the repository url conditionally on the version: if version ends with -SNAPSHOT use the snapshot URL, otherwise the releases URL. Often two layout paths under one base host.

solid answer

~40 s

Many Maven servers expose separate release and snapshot endpoints. Since the publish repository `url` is just a property you assign in the DSL, you can compute it from the project `version`. A common pattern is a ternary on whether the version ends with `-SNAPSHOT`: ```kotlin publishing { repositories { maven { name = "myCompany" val releases = uri("https://repo.example.com/releases") val snapshots = uri("https://repo.example.com/snapshots") url = if (version.toString().endsWith("SNAPSHOT")) snapshots else releases } } } ``` This keeps one named repository (one set of tasks) while directing artifacts to the correct layout based on the build's version. The decision is made at configuration time from `project.version`, so it must already be set when the publishing block evaluates.

code

kotlin · 13 lines
kotlin
publishing {
  repositories {
    maven {
      name = "myCompany"
      url = uri(
        if (version.toString().endsWith("SNAPSHOT"))
          "https://repo.example.com/snapshots"
        else
          "https://repo.example.com/releases"
      )
    }
  }
}

go deeper

for a junior

Recognise that release vs snapshot can go to different URLs based on the version suffix.

for a middle

Write the conditional url from project.version.endsWith("SNAPSHOT") and know it's configuration-time.

for a senior

Weigh one-computed-url vs two-named-repositories and the CI ergonomics of each; handle the unset-version pitfall.

for a principal

Encode release/snapshot routing once in a shared convention plugin with validation, so no project hand-rolls the ternary inconsistently.

## Why two URLs Maven-style servers (Nexus, Artifactory) conventionally split storage into a *releases* repository (immutable, one version published once) and a *snapshots* repository (mutable, overwritten as development iterates). The `-SNAPSHOT` suffix on a version is the signal that the artifact is a work-in-progress and belongs in the snapshot store. ## Computing the url Because `url` is an ordinary assignable property of the `MavenArtifactRepository`, you can derive it from `project.version`: ```kotlin val isSnapshot = version.toString().endsWith("SNAPSHOT") url = uri(if (isSnapshot) "https://repo.example.com/snapshots" else "https://repo.example.com/releases") ``` This evaluates at **configuration time**, so `version` must be set before the `publishing` block runs (set it at the top of the build script, or in `gradle.properties`). ## One named repository vs two Two valid designs: 1. **One repository, computed url** (above) — a single name, one set of `publishTo<Name>Repository` tasks; the destination flips per build. Simplest for CI: the command is the same for release and snapshot builds. 2. **Two named repositories** — declare both `maven { name = "releases" }` and `maven { name = "snapshots" }`, generating two task sets, and invoke the appropriate one. More explicit but couples the CI command to the version type. ## Layout-based directories The `url` already encodes the directory layout: pointing at `/releases` vs `/snapshots` selects the server-side layout. Gradle's default Maven layout then arranges `group/artifact/version/…` underneath whichever base you chose. You rarely need to touch the repository's `layout` itself; choosing the right base `url` is the lever. ## Gotcha If `version` is still the default `unspecified` when this runs, the ternary silently routes to releases. Always ensure the version is assigned (and ideally validate it) before publishing.

  • When is the url ternary evaluated, and why does that matter?
    At configuration time, when the publishing block runs. So `project.version` must already be set; if it is still `unspecified`, the condition is false and the build wrongly targets the releases URL.
  • What is an alternative to computing one url?
    Declare two separately named repositories (`releases` and `snapshots`); Gradle generates two task sets and CI invokes the appropriate one based on the build type.

saying these in an interview costs you the question

  • Assuming the url is recomputed at execution time — it is fixed at configuration time.
  • Forgetting to set `version` before the publishing block, silently defaulting all builds to releases.

context