Skip to content

Commit

Permalink
A couple of improvements
Browse files Browse the repository at this point in the history
- Fallback to the default releaseVersion behavior for the first release
- Read the version qualifier from an environment variable
  • Loading branch information
julienrf committed Nov 30, 2023
1 parent 6e33573 commit 985ace1
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 30 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ In this mode, you can use sbt-version-policy to check that incoming pull request
import sbtversionpolicy.withsbtrelease.ReleaseVersion
releaseVersion := ReleaseVersion.fromCompatibility(versionPolicyIntention.value)
~~~
The `releaseVersion` function bumps the release version according to the compatibility guarantees defined
by `versionPolicyIntention`. Optionally, you can also define a _qualifier_ to append to the release version
by setting the environment variable `VERSION_POLICY_RELEASE_QUALIFIER` (e.g., `VERSION_POLICY_RELEASE_QUALIFIER=RC1`).
2. Reset `versionPolicyIntention` to `Compatibility.BinaryAndSourceCompatible` after every release.
This can be achieved by managing the setting `versionPolicyIntention` in a separate file (like [sbt-release] manages the setting `version` in a separate file, by default), and by adding a step that overwrites the content of that file and commits it.

Expand Down Expand Up @@ -245,8 +248,13 @@ In this mode, you can use sbt-version-policy to assess the incompatibilities int
ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease().value
}
~~~
In both cases, the `releaseVersion` function sets the release version according to the compatibility level
with the latest release. Optionally, you can also define a _qualifier_ to append to the release version
by setting the environment variable `VERSION_POLICY_RELEASE_QUALIFIER` (e.g., `VERSION_POLICY_RELEASE_QUALIFIER="-RC1"`).

Note that this mode can be enabled only _after_ the first release of the project has already been published.
Note that for the first release you have to set the release version yourself via the file `version.sbt` (e.g., set
`1.0.0-SNAPSHOT` or `0.1.0-SNAPSHOT`). This is because `sbt-version-policy` needs a previous release to exist to be
able to assess the compatibility level of the current state of the project with that release.

##### Example

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import sbtversionpolicy.Compatibility
import sbtversionpolicy.SbtVersionPolicyPlugin.aggregatedAssessedCompatibilityWithLatestRelease
import sbtversionpolicy.SbtVersionPolicyPlugin.autoImport.versionPolicyAssessCompatibility
import sbt.*
import sbtversionpolicy.SbtVersionPolicyMima.autoImport.versionPolicyPreviousVersions

/** Convenient methods to integrate with the plugin sbt-release */
object ReleaseVersion {

private val qualifierVariableName = "VERSION_POLICY_RELEASE_QUALIFIER"

/**
* @return a [release version function](https://github.com/sbt/sbt-release?tab=readme-ov-file#custom-versioning)
* that bumps the patch, minor, or major version number depending on the provided
* compatibility level.
* @param qualifier Optional qualifier to append to the version (e.g. `"-RC1"`). Empty by default.
* @param qualifier Optional qualifier to append to the version (e.g. `"-RC1"`). By default, it tries to read
* it from the environment variable VERSION_POLICY_RELEASE_QUALIFIER.
*/
def fromCompatibility(compatibility: Compatibility, qualifier: String = ""): String => String = {
def fromCompatibility(compatibility: Compatibility, qualifier: String = sys.env.getOrElse(qualifierVariableName, "")): String => String = {
val maybeBump =
compatibility match {
case Compatibility.None => Some(Version.Bump.Major)
Expand All @@ -31,10 +35,29 @@ object ReleaseVersion {
case Some(bump) => versionWithoutQualifier.bump(bump)
case None => versionWithoutQualifier
}).string
s"${bumpedVersion}${qualifier}"
bumpedVersion + qualifier
}
}

private def fromAssessedCompatibility(qualifier: String)(assessCompatibility: Def.Initialize[Task[Compatibility]]): Def.Initialize[Task[String => String]] =
Def.ifS(Def.task {
versionPolicyPreviousVersions.value.isEmpty
})(Def.task {
// If there are no previous versions to assess the compatibility with,
// fallback to the default release version function, which drops the qualifier
// from the version set in the file `version.sbt`
// (e.g., "1.0.0-SNAPSHOT" => "1.0.0")
(version: String) =>
Version(version)
.map(_.withoutQualifier.string + qualifier)
.getOrElse(Version.formatError(version))
})(Def.task {
val log = Keys.streams.value.log
val compatibility = assessCompatibility.value
log.debug(s"Compatibility level is ${compatibility}")
fromCompatibility(compatibility, qualifier)
})

/**
* Task returning a [release version function](https://github.com/sbt/sbt-release?tab=readme-ov-file#custom-versioning)
* based on the assessed compatibility level of the project.
Expand All @@ -44,26 +67,27 @@ object ReleaseVersion {
* {{{
* import sbtversionpolicy.withsbtrelease.ReleaseVersion
*
* releaseVersion := ReleaseVersion.fromAssessedCompatibilityWithLatestRelease.value
* releaseVersion := ReleaseVersion.fromAssessedCompatibilityWithLatestRelease().value
* }}}
*
* sbt-release uses the `releaseVersion` function to set the version before publishing a release (at step
* `setReleaseVersion`). It reads the current `version` (usually defined in a file `version.sbt`, and looking
* like `"1.2.3-SNAPSHOT"`), and applies the function to it.
*
* @param qualifier Optional qualifier to append to the version (e.g. `"-RC1"`). Empty by default.
* @param qualifier Optional qualifier to append to the version (e.g. `"-RC1"`). By default, it tries to read
* it from the environment variable VERSION_POLICY_RELEASE_QUALIFIER.
*/
def fromAssessedCompatibilityWithLatestRelease(qualifier: String = ""): Def.Initialize[Task[String => String]] =
Def.task {
def fromAssessedCompatibilityWithLatestRelease(
qualifier: String = sys.env.getOrElse(qualifierVariableName, "")
): Def.Initialize[Task[String => String]] =
fromAssessedCompatibility(qualifier)(Def.task {
val compatibilityResults = versionPolicyAssessCompatibility.value
val log = Keys.streams.value.log
val compatibilityWithLatestRelease =
compatibilityResults.headOption
.getOrElse(throw new MessageOnlyException("Unable to assess the compatibility level of this project. Is 'versionPolicyPreviousVersions' defined?"))
.getOrElse(throw new MessageOnlyException("Unable to assess the compatibility level of this project."))
val (_, compatibility) = compatibilityWithLatestRelease
log.debug(s"Compatibility level is ${compatibility}")
fromCompatibility(compatibility, qualifier)
}
compatibility
})

/**
* Task returning a [release version function](https://github.com/sbt/sbt-release?tab=readme-ov-file#custom-versioning)
Expand All @@ -80,20 +104,20 @@ object ReleaseVersion {
* .in(file("."))
* .aggregate(mySubproject1, mySubproject2)
* .settings(
* releaseVersion := ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease.value
* releaseVersion := ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease().value
* )
* }}}
*
* sbt-release uses the `releaseVersion` function to set the version before publishing a release (at step
* `setReleaseVersion`). It reads the current `version` (usually defined in a file `version.sbt`, and looking
* like `"1.2.3-SNAPSHOT"`), and applies the function to it.
*
* @param qualifier Optional qualifier to append to the version (e.g. `"-RC1"`). By default, it tries to read
* it from the environment variable VERSION_POLICY_RELEASE_QUALIFIER.
*/
def fromAggregatedAssessedCompatibilityWithLatestRelease(qualifier: String = ""): Def.Initialize[Task[String => String]] =
Def.task {
val log = Keys.streams.value.log
val compatibility = aggregatedAssessedCompatibilityWithLatestRelease.value
log.debug(s"Aggregated compatibility level is ${compatibility}")
fromCompatibility(compatibility, qualifier)
}
def fromAggregatedAssessedCompatibilityWithLatestRelease(
qualifier: String = sys.env.getOrElse(qualifierVariableName, "")
): Def.Initialize[Task[String => String]] =
fromAssessedCompatibility(qualifier)(aggregatedAssessedCompatibilityWithLatestRelease)

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ val module =
val root = project.in(file("."))
.aggregate(module)
.settings(
// Tell sbt-release to set the release version based on the level of compatibility with the previous release
releaseVersion := ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease().value,
// Custom release process for testing purpose only: the artifacts are locally published,
// and we don’t push to the remote repository.
releaseProcess := Seq[ReleaseStep](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $ exec git commit -m "Initial commit"
> reload

# First release
> release with-defaults release-version 1.0.0
> release with-defaults
> checkTag_1_0_0
> reload

Expand All @@ -17,13 +17,6 @@ $ copy-file file-to-add.template module/src/main/scala/org/organization/module/N
$ exec git add module/src/main/scala/org/organization/module/NewAPI.scala
$ exec git commit -m "Some hard work"

# Configure releaseVersion to bump the patch, minor, or major version number according
# to the assessed compatibility level.
# In practice, you would assign the releaseVersion in your build.sbt.
# Here, we show how to optionally add a qualifier to the release version (e.g. `"-RC1"`)
# via an environment variable RELEASE_VERSION_QUALIFIER
> set releaseVersion := sbtversionpolicy.withsbtrelease.ReleaseVersion.fromAggregatedAssessedCompatibilityWithLatestRelease(qualifier = sys.env.getOrElse("RELEASE_VERSION_QUALIFIER", "")).value

# Second release
> release with-defaults
# Check that sbt-version-policy bumped the minor version
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ThisBuild / version := "0.0.1-SNAPSHOT"
ThisBuild / version := "1.0.0-SNAPSHOT"

0 comments on commit 985ace1

Please sign in to comment.