4

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.

Todor Kolev
  • 1,432
  • 1
  • 16
  • 33

2 Answers2

1

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

Todor Kolev
  • 1,432
  • 1
  • 16
  • 33
  • I am in a similar scenario where the process in long and have to do this kind of multi step release process. One question though, what happens when there are commits in the main branch while the some stage is still in process ? – Abhi Mar 14 '21 at 12:33
  • Once you've created the tag you release that tag. Everything that is pushed to the branch afterwards will be ignored by this particular pipeline run. – Todor Kolev Mar 15 '21 at 22:10
0

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.

Justin Kaeser
  • 5,868
  • 27
  • 46
  • 1
    Going by [the source](https://github.com/sbt/sbt-release/blob/master/src/main/scala/ReleasePlugin.scala#L156-L194), you will have to copy the code there and adapt it tp your needs, since it is not parameterizable. – Justin Kaeser Mar 05 '18 at 14:25
  • Thanks for you comment, I was just trying to articulate what I'm after. I know how to redefine the releaseProcess but in my case I need two separate commands - one to prepare the release and one to push everything. 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. I've updated my question to reflect this. – Todor Kolev Mar 05 '18 at 14:25