Todor Kolev
Todor Kolev

Reputation: 1482

Split sbt release in stages?

I have an SBT project and a CD pipeline and what I want is to execute the following sequence of steps:

  1. Checkout my project from the git repo
  2. Tag the commit
  3. Run the tests
  4. Package my app

Now at this point I don't want to release anything yet as I will promote the binaries to another environment to run the end-to-end tests. Only if they complete successfully would I want to push the git tags and upload my artefact to the remote artefactory repository. What I want to achieve really, is to be able to first run sbt prepereRelease after which I will promote to my TEST environment and later, if everything goes ok, to run sbt doRelease. So I want something similar to this in my build.sbt:

releaseProcess := Seq[ReleaseStep](
      checkSnapshotDependencies,
      inquireVersions,
      runClean,
      runTest,
      setReleaseVersion,
      commitReleaseVersion,
      tagRelease,
      setNextVersion,
      commitNextVersion
)

commands += Command.command("prepareRelease")((state:State) => {
  val newState = Command.process("release",state)
  println("Release called from prepareRelease...")
  newState
})

releaseProcess := Seq[ReleaseStep](
      publishArtifacts,
      setNextVersion,
      commitNextVersion,
      pushChanges
)

commands += Command.command("doRelease")((state:State) => {
  val newState = Command.process("release",state)
  println("Release called from doRelease...")
  newState
})

I almost feel like I will have to define two custom commands and each one will have to call the original release command from the sbt-release plugin with a different releaseProcess setting - that's the bit I don't know how to go about. Unfortunately the above setup won't work as the releaseProcess setting accumulates the steps and you still end up with all the steps being executed at once.

Upvotes: 4

Views: 1336

Answers (2)

Todor Kolev
Todor Kolev

Reputation: 1482

The way I ended up implementing it is by creating two custom commands and appending the releaseProcess setting to the state object which I then pass onto the release plugin:

// Defines the release process
releaseIgnoreUntrackedFiles := true

commands += Command.command("prepareRelease")((state: State) => {
  println("Preparing release...")
  val extracted = Project extract state
  val customState = extracted.append(Seq(releaseProcess := Seq[ReleaseStep](
    checkSnapshotDependencies,
    inquireVersions,
    runClean,
    setReleaseVersion,
    commitReleaseVersion,
    tagRelease,
    runTest
  )), state)
  val newState = Command.process("release with-defaults", customState)
  Command.process("dist", newState)
})

commands += Command.command("completeRelease")((state: State) => {
  println("Completing release...")
  val extracted = Project extract state
  val customState = extracted.append(Seq(releaseProcess := Seq[ReleaseStep](
    inquireVersions,
    setNextVersion,
    commitNextVersion,
    pushChanges
  )), state)
  val newState = Command.process("release with-defaults", customState)
  newState
})

So my pipeline does something similar to the following:

  1. sbt prepareRelease

  2. At this point I deploy the binaries to my TEST environment

  3. If everything runs through fine then I do sbt completeRelease

  4. And eventually curl my zip into nexus

Upvotes: 1

Justin Kaeser
Justin Kaeser

Reputation: 5948

You have defined prepareRelease and doRelease as setting. This means the value of the setting will be only calculated once when the build is loaded or reloaded. Furthermore, the ReleaseStep type only describes functions to be executed as part of a release process, and won't do anything on its own.

It looks like you are using the sbt-release plugin. Following the documentation, you will have to redefine the releaseProcess key with your custom steps, and run the release command to execute them.

Upvotes: 0

Related Questions