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

feat: support to force using release version #3

Merged
merged 5 commits into from
Mar 30, 2024
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
5 changes: 3 additions & 2 deletions .releaserc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ plugins:
- "@semantic-release/changelog"
- - "@semantic-release/exec"
- publishCmd: ./gradlew publishPlugins
# prepareCmd: echo "${nextRelease.version}" > version.txt # TODO set via plugin
prepareCmd: ./gradlew "-PnewVersion=${nextRelease.version}" setReleaseVersion
verifyReleaseCmd: ./gradlew verifyReleaseVersion
- - "@semantic-release/git"
- assets:
- CHANGELOG.md
# - version.txt
- version.txt
- "@semantic-release/github"
6 changes: 6 additions & 0 deletions README → README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,10 @@ The plugin works based on the following assumptions:
3. If the git repository is not clean or HEAD does not point to a tag, the project version is a SNAPSHOT version that increases the minor version compared to the last release version
4. If no release version is configured or the version file is missing, the project version is `1.0.0-SNAPSHOT`

For a tag to be recognized it needs to match the configured release version, optionally with the prefix `v`, for example `1.0.0` or `v1.0.0`.

If the environment variable `RELEASE` is set to `true`, the release version is used, even if the repository is not clean.
This is intended for use cases where the release version was set, but the repository is expected to be dirty, e.g. due to other CI tasks.
A cleaner method is avoid the repository being dirty, e.g. by adding additional files that are created during the release process to `.gitignore` if possible.

By default the version file is assumed to be the file `version.txt` in the root project.
14 changes: 13 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java-gradle-plugin'
id 'groovy'
id 'com.gradle.plugin-publish' version "1.2.1"
id 'to.wetransform.semantic-release-version' version '1.0.0'
}

repositories {
Expand All @@ -15,7 +16,6 @@ java {
}

group = "to.wetransform"
version = "1.0.0"

dependencies {
implementation 'org.ajoberstar.grgit:grgit-core:5.2.2'
Expand Down Expand Up @@ -66,3 +66,15 @@ tasks.wrapper {
distributionType = Wrapper.DistributionType.ALL
gradleVersion = '8.6'
}

task('verifyReleaseVersion') {
//FIXME remove task once plugin could be updated

doLast {
def version = project.version

assert version
assert !version.endsWith('-SNAPSHOT')
// assert version =~ SEM_VER_REGEX
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package to.wetransform.gradle.version

import java.util.function.BiPredicate
import org.gradle.api.Project

class VersionExtension {
Expand All @@ -9,8 +10,27 @@ class VersionExtension {
this.gitDir = project.rootProject.projectDir
}

/**
* Location of the file that holds the last release version, if it exists.
*/
File versionFile

/**
* Location of the git repository to check.
*/
File gitDir

/**
* Test to verify if a tag is a version tag and if the version matches the provided release version.
*/
BiPredicate<String, String> verifyTag = { tag, version ->
def matcher = tag =~ /^v?((\d+)\.(\d+)\.(\d+))$/
if (matcher) {
matcher[0][1] == version
}
else {
false
}
}

}
59 changes: 50 additions & 9 deletions src/main/groovy/to/wetransform/gradle/version/VersionPlugin.groovy
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package to.wetransform.gradle.version;

import java.util.function.BiPredicate
import org.gradle.api.Plugin;
import org.gradle.api.Project;

class VersionPlugin implements Plugin<Project> {

private static def SEM_VER_REGEX = /(\d+)\.(\d+)\.(\d+)/

void apply(Project project) {
//XXX not sure how to easiest use the service - instead the repo is opened manually
// project.apply(plugin: 'org.ajoberstar.grgit.service')
Expand Down Expand Up @@ -31,25 +35,52 @@ class VersionPlugin implements Plugin<Project> {
}
}

project.task('verifyReleaseVersion') {
group 'Version'
description 'Check if a release version is configured, otherwise (if the version is a -SNAPSHOT version) fail'

doLast {
def version = project.version

assert version
assert !version.endsWith('-SNAPSHOT')
assert version =~ SEM_VER_REGEX
}
}

// set version

project.afterEvaluate {
if(it.version != Project.DEFAULT_VERSION) {
throw new IllegalStateException("Version may not be configured if version plugin is applied")
} else {
it.version = determineVersion(it, it.versionConfig.versionFile, it.versionConfig.gitDir)
it.version = determineVersion(
it, it.versionConfig.versionFile, it.versionConfig.gitDir, it.versionConfig.verifyTag
)
}
}
}

String determineVersion(Project project, File versionFile, File gitDir) {
String determineVersion(Project project, File versionFile, File gitDir, BiPredicate<String, String> verifyTag) {
// read version from file
if (!versionFile.exists()) {
def releaseVersion = null
if (versionFile.exists()) {
releaseVersion = versionFile.text.trim()

// verify version
if (releaseVersion) {
def matcher = releaseVersion =~ SEM_VER_REGEX
if (!matcher) {
throw new IllegalStateException("Provided version for last release is not a valid semantic version: $releaseVersion")
}
}
}

if (!releaseVersion) {
// assume initial snapshot
project.logger.info("Version file does not exists, assuming 1.0.0-SNAPSHOT")
project.logger.info("Version file does not exist or contains no version, assuming 1.0.0-SNAPSHOT")
return '1.0.0-SNAPSHOT'
}
def releaseVersion = versionFile.text.trim()

def dirty = false
def tagOnCurrentCommit = false
Expand All @@ -64,18 +95,28 @@ class VersionPlugin implements Plugin<Project> {
dirty = !grgit.status().isClean()
def currentCommit = grgit.head().id
tagOnCurrentCommit = grgit.tag.list().findAll { tag ->
tag.commit.id == currentCommit
tag.commit.id == currentCommit && verifyTag.test(tag.name, releaseVersion)
}
}

if ('true'.equalsIgnoreCase(System.getenv('RELEASE'))) {
// force release version if repo is dirty (e.g. during release in CI)
// but still verify tag
if (tagOnCurrentCommit) {
return releaseVersion
}
else {
throw new IllegalStateException("There is no matching tag for the configured release version $releaseVersion")
}
}

if (tagOnCurrentCommit && !dirty) {
//TODO check tags?
//XXX for now assume tag represents release
project.logger.info("Current commit is tagged and repository clean, using release version specified in file: $releaseVersion")
releaseVersion
}
else {
// build snapshot version with next minor version
def matcher = releaseVersion =~ /(\d+)\.(\d+)\.(\d+)/
def matcher = releaseVersion =~ SEM_VER_REGEX
if (matcher) {
project.logger.info("Current commit is not tagged or repository is dirty, using snapshot version based on last release")

Expand Down
1 change: 1 addition & 0 deletions version.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.0.0
Loading