Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#15 add option to release with a version type e.g. major minor patch #40

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ existing issue.
|---------------------------------------|-----------------------------------------------------------------------------------------------|---------------------------|----------------------------------------------------------------------|
| Release with explicit version numbers | Release with while providing explicit version numbers | :white_check_mark: | [#3](https://github.com/simonhauck/gradle-release-plugin/issues/3) |
| Support Trunk based released | The plugin can perform a release on a given branch | :white_check_mark: | [#3](https://github.com/simonhauck/gradle-release-plugin/issues/3) |
| Simplified API | Release with a single parameter like major, minor, patch | :x: | [#15](https://github.com/simonhauck/gradle-release-plugin/issues/15) |
| Simplified API | Release with a single parameter like major, minor, patch | :white_check_mark: | [#15](https://github.com/simonhauck/gradle-release-plugin/issues/15) |
| Support Gitflow | The plugin should be able to perform merge commits from a development branch to a main branch | :x: | No issue created yet |
| Check for snapshot versions | Add an optional check to verify the project does not use any snapshot versions. | :x: | No issue created yet |

Expand Down Expand Up @@ -76,12 +76,14 @@ plugins {
id("io.github.simonhauck.release") version "<the-current-version>"
}

val versionFile = layout.projectDirectory.file("version.properties")

release {
versionPropertyFile.set(layout.projectDirectory.file("version.properties"))
versionPropertyFile.set(versionFile)
}

// If you want to set the version in you gradle project you can use this helper method
version = Version.fromPropertiesFile(layout.projectDirectory.file("version.properties").asFile)
version = Version.fromPropertiesFile(versionFile.asFile)
```

The plugin provides sensible defaults for the release process. If you want to customize the release process, have a look
Expand Down Expand Up @@ -116,15 +118,20 @@ gradle command
You can trigger a release by running the following gradle command

```shell
./gradlew release -PreleaseVersion=1.0.0 -PpostReleaseVersion=1.0.1-SNAPSHOT
./gradlew release -PreleaseVersion=1.0.0 -PpostReleaseVersion=1.0.1-SNAPSHOT
```

Replace the values for the `releaseVersion` and `postReleaseVersion` with your desired target values.

#### Option 2: Use the release type

[WIP] This feature is not yet fully implement. This feature is tracked in
this [issue](https://github.com/simonhauck/gradle-release-plugin/issues/15)
If you have a [semver](https://semver.org/) compatible version you can choose to use the simplified api.

```shell
./gradlew release -PreleaseType=<release-type>
```

Replace the _release-type_ with ``major``, ``minor`` or ``patch``. This will determine the version automatically.

### Customizing the release process

Expand Down
4 changes: 3 additions & 1 deletion example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ plugins {
id("io.github.simonhauck.release")
}

val versionFile = layout.projectDirectory.file("version.properties")

// You can set the version from the version.properties file. You can utilize this helper method
version = Version.fromPropertiesFile(layout.projectDirectory.file("version.properties").asFile)
version = Version.fromPropertiesFile(versionFile.asFile)

tasks.withType<BaseReleaseTask> {
// This is just here, because it interferes with the release task of this parent project
Expand Down
9 changes: 0 additions & 9 deletions release-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,6 @@ gradlePlugin {
}
}

publishing {
repositories {
maven {
name = "localPluginRepository"
url = uri("../local-plugin-repository")
}
}
}

private fun readVersionFromFile(file: File): String = readProperties(file).getProperty("version")

private fun readProperties(propertiesFile: File) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import java.io.File
import org.gradle.api.GradleException

data class Version(
val version: String,
val value: String,
) {

companion object {
fun fromPropertiesFile(file: File): String {
val properties = PropertiesFileUtil().readProperties(file)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ internal class VersionHolder(private val tmpFileLocation: File) : VersionHolderA
log.info { "Saving versions to ${tmpFileLocation.absolutePath} to $releaseVersions" }

Properties().apply {
setProperty(RELEASE_VERSION_KEY, releaseVersions.releaseVersion.version)
setProperty(POST_RELEASE_VERSION_KEY, releaseVersions.postReleaseVersion.version)
setProperty(RELEASE_VERSION_KEY, releaseVersions.releaseVersion.value)
setProperty(POST_RELEASE_VERSION_KEY, releaseVersions.postReleaseVersion.value)
writeToFile(tmpFileLocation)
}
}
Expand All @@ -36,7 +36,7 @@ internal class VersionHolder(private val tmpFileLocation: File) : VersionHolderA
override fun writeVersionPropertyToFile(file: File, version: Version) {
val updatedMap =
readPropertiesFile(file).toMutableMap().apply {
put("version", version.version)
put("version", version.value)
toMap()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ internal sealed interface VersionIncrementStrategy {

val requiredPropertyDescription: List<String>

fun tryParse(parameters: Map<String, String>): ReleaseVersions?
fun tryParse(currentVersion: Version, parameters: Map<String, String>): ReleaseVersions?
}

internal class ManualVersionSelectionStrategy() : VersionIncrementStrategy {
Expand All @@ -21,7 +21,10 @@ internal class ManualVersionSelectionStrategy() : VersionIncrementStrategy {
"$POST_RELEASE_VERSION_KEY - The version after the release"
)

override fun tryParse(parameters: Map<String, String>): ReleaseVersions? {
override fun tryParse(
currentVersion: Version,
parameters: Map<String, String>
): ReleaseVersions? {
val releaseVersion = parameters[RELEASE_VERSION_KEY]
val postReleaseVersion = parameters[POST_RELEASE_VERSION_KEY]

Expand All @@ -37,3 +40,41 @@ internal class ManualVersionSelectionStrategy() : VersionIncrementStrategy {
private const val POST_RELEASE_VERSION_KEY = "postReleaseVersion"
}
}

internal class ReleaseTypeSelectionStrategy : VersionIncrementStrategy {
override val strategyName: String
get() = "ReleaseType selection"

override val requiredPropertyDescription: List<String>
get() = listOf("$RELEASE_TYPE - The type of release ($MAJOR_KEY, $MINOR_KEY, $PATCH_KEY)")

override fun tryParse(
currentVersion: Version,
parameters: Map<String, String>
): ReleaseVersions? {
val releaseType = parameters[RELEASE_TYPE] ?: return null

val versionInfo = VersionInfo.fromVersion(currentVersion)

val releaseVersion =
when (releaseType) {
"major" -> versionInfo.bumpMajor()
"minor" -> versionInfo.bumpMinor()
"patch" ->
if (versionInfo.isPreRelease()) versionInfo.bumpToRelease()
else versionInfo.bumpPatch()
else -> return null
}

val postReleaseVersion = releaseVersion.bumpPatch("SNAPSHOT")

return ReleaseVersions(releaseVersion.toVersion(), postReleaseVersion.toVersion())
}

companion object {
private const val RELEASE_TYPE = "releaseType"
private const val MAJOR_KEY = "major"
private const val MINOR_KEY = "minor"
private const val PATCH_KEY = "patch"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ internal class VersionIncrementStrategyParser : VersionIncrementStrategyParserAp
private val parsers =
listOf(
ManualVersionSelectionStrategy(),
ReleaseTypeSelectionStrategy(),
)

override fun parseOrThrow(
currentVersion: Version,
parameters: Map<String, String>
): ReleaseVersions {
val parsedVersion = parsers.firstNotNullOfOrNull { it.tryParse(parameters) }
val parsedVersion = parsers.firstNotNullOfOrNull { it.tryParse(currentVersion, parameters) }

if (parsedVersion == null) {
log.error { "No version increment strategy found" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package io.github.simonhauck.release.version.internal

import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.raise.either
import arrow.core.raise.ensure
import arrow.core.raise.ensureNotNull
import io.github.simonhauck.release.version.api.Version
import org.gradle.api.GradleException

internal data class VersionInfo(
val major: Int,
val minor: Int,
val patch: Int,
val preReleaseSuffix: String? = null,
val buildMetaData: String? = null
) {

fun isPreRelease(): Boolean {
return preReleaseSuffix != null
}

fun toVersion(): Version {
val preReleaseSuffixString = preReleaseSuffix?.let { "-$preReleaseSuffix" } ?: ""
val buildMetaDataString = buildMetaData?.let { "+$buildMetaData" } ?: ""
return Version("$major.$minor.$patch$preReleaseSuffixString$buildMetaDataString")
}

fun bumpToRelease(): VersionInfo {
return copy(preReleaseSuffix = null, buildMetaData = null)
}

fun bumpPatch(newPreLeaseSuffix: String? = null): VersionInfo {
return copy(patch = patch + 1, preReleaseSuffix = newPreLeaseSuffix, buildMetaData = null)
}

fun bumpMinor(newPreLeaseSuffix: String? = null): VersionInfo {
return copy(
minor = minor + 1,
patch = 0,
preReleaseSuffix = newPreLeaseSuffix,
buildMetaData = null
)
}

fun bumpMajor(newPreLeaseSuffix: String? = null): VersionInfo {
return copy(
major = major + 1,
minor = 0,
patch = 0,
preReleaseSuffix = newPreLeaseSuffix,
buildMetaData = null
)
}

companion object {

fun fromVersion(version: Version): VersionInfo {
return parseVersionInfo(version).getOrElse { throw it }
}

private fun parseVersionInfo(version: Version): Either<GradleException, VersionInfo> =
either {
val value = version.value
val regexString =
"""^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?${'$'}"""
val matchEntire = regexString.toRegex().matchEntire(value)

val matcher = regexString.toPattern().matcher(value)

val parsingException = buildErrorMessage(version)
val parseResult = ensureNotNull(matchEntire) { parsingException }
ensure(matcher.matches()) { parsingException }

val major = parseResult.groups[1]?.value?.toInt() ?: raise(parsingException)
val minor = parseResult.groups[2]?.value?.toInt() ?: raise(parsingException)
val patch = parseResult.groups[3]?.value?.toInt() ?: raise(parsingException)
val prerelease = parseResult.groups[4]?.value
val buildMetaData = parseResult.groups[5]?.value

VersionInfo(major, minor, patch, prerelease, buildMetaData)
}

private fun buildErrorMessage(version: Version): GradleException {
val message =
"Can not parse versionInfo of '${version.value}' since it does not conform to the SemVer pattern"
return GradleException(message)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class GitCommandApiTest {
internal class GitCommandApiTest {

@TempDir lateinit var tmpDir: File

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class ReleasePluginTest {
internal class ReleasePluginTest {

@TempDir lateinit var tmpDir: File

private val testDriver = ReleasePluginTestDriver()

@Test
fun `the version file should contain the next development version at the end`() =
fun `the version file should contain the next development version at the end when the versions are set directly`() =
testDriver(tmpDir) {
createValidRepositoryWithRemote()

Expand All @@ -36,6 +36,27 @@ class ReleasePluginTest {
.isEqualTo("version=1.2.1-SNAPSHOT")
}

@Test
fun `releasing with releaseType strategy should be successful`() =
testDriver(tmpDir) {
updateVersionProperties("1.0.1-SNAPSHOT")
createValidRepositoryWithRemote()

val runner =
testKitRunner()
.withArguments(
"release",
"-PreleaseType=minor",
)
.build()

val actual = runner.task(":release")?.outcome

assertThat(actual).isEqualTo(TaskOutcome.SUCCESS)
assertThat(client1WorkDir.resolve("version.properties").readText())
.isEqualTo("version=1.1.1-SNAPSHOT")
}

@Test
fun `no files should be changed, untracked or commited when the release plugin has finished successful`() =
testDriver(tmpDir) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class CalculateReleaseVersionTaskTest {
internal class CalculateReleaseVersionTaskTest {

@TempDir lateinit var tmpDir: File

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class CommitAndTagTaskTest {
internal class CommitAndTagTaskTest {

@TempDir lateinit var tmpDir: File

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class PushTaskTest {
internal class PushTaskTest {

@TempDir lateinit var tmpDir: File
private val testDriver = ReleasePluginTestDriver()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class WriteVersionTaskTest {
internal class WriteVersionTaskTest {
@TempDir lateinit var tempDir: File

private val testDriver = ReleasePluginTestDriver()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import io.github.simonhauck.release.git.api.GitError
import io.github.simonhauck.release.git.api.isOk
import org.assertj.core.api.Assertions

fun <T> Either<GitError, T>.assertIsOk(): T {
internal fun <T> Either<GitError, T>.assertIsOk(): T {
Assertions.assertThat(isOk()).isTrue()
return get()
}

fun <T, E> Either<T, E>.get(): E {
internal fun <T, E> Either<T, E>.get(): E {
return when (this) {
is Either.Left -> throw IllegalStateException("Expected Right but got Left")
is Either.Right -> this.value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.gradle.api.GradleException
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.io.TempDir

class VersionHolderApiTest {
internal class VersionHolderApiTest {
@TempDir lateinit var tempDir: File

@Test
Expand Down
Loading