Skip to content

Commit

Permalink
Merge pull request #3 from IntershopCommunicationsAG/feature/tbergman…
Browse files Browse the repository at this point in the history
…n-AddMavenSorting

rework semantic version integrate all maven issues
  • Loading branch information
Thomas-Bergmann authored Dec 13, 2023
2 parents d11e869 + 0aafb94 commit 25d9297
Show file tree
Hide file tree
Showing 30 changed files with 2,527 additions and 565 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ jobs:
env:
JAVA_OPTS: "-Xmx1024M"
GRADLE_OPTS: "-Dorg.gradle.daemon=true"
run: ./gradlew test build -s
run: ./gradlew -Pversion=${{ github.ref_name }}-SNAPSHOT test build javadoc -s
- name: Post Build
run: rm -f $HOME/.gradle/gradle.properties
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ jobs:
env:
JAVA_OPTS: "-Xmx1024M"
GRADLE_OPTS: "-Dorg.gradle.daemon=true"
run: ./gradlew -PrunOnCI=true test build :publishIntershopMvnPublicationToMavenRepository -s
run: ./gradlew -Pversion=${{ github.ref_name }} -PrunOnCI=true test build :publishIntershopMvnPublicationToMavenRepository -s
- name: Post Build
run: rm -f $HOME/.gradle/gradle.properties
113 changes: 88 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,107 @@
# Introduction

This project targets the handling of (possibly) [semantic versions](https://semver.org/). Besides semantic versions this project also supports some derived versions that are used by various libraries.
* [Semantic Versions v1.0.0](https://semver.org/spec/v1.0.0.html) declares one extension as pre-release in lexicographic ASCII order.
* [Semantic Versions v2.0.0](https://semver.org/spec/v2.0.0.html) allows one extension and one build extension (both are optional).
* [Maven Specification](https://maven.apache.org/pom.html#Version_Order_Specification) allows multiple extensions including post-release and GA extensions
* [Maven Version Sorting](https://maven.apache.org/ref/3.8.5/maven-artifact/apidocs/org/apache/maven/artifact/versioning/ComparableVersion.html) contains alias for pre-releases with same semantic meaning (e.g 1.0.0-a1 is same as 1.0.0-alpha1), all unknown extensions are recognized as post-releases.

# Usage
## Syntax
Unfortunatelly, the build extension is not used to declare:
* platform specific artifacts. e.g. for different jre (bytecodes) like -jre8 or -jre11, or for docker -amd64
* major dependencies, e.g. -jakarta or -centos

The supported syntax follows this pattern:
# Syntax

`<major>.<minor>.<patch>-<incrementState><increment>`
The general syntax is comparable to SemVer.
`<major>.<minor>.<patch>(-<extension>)?(+<build extension>)?`

For the `incrementState` the following values (case-insensitive) are supported:
Allows multiple extensions and more than three numbers.
`<major>.<minor>.<patch>(.<increment>)*(-<extension>)*`

* FINAL
* GA (default)
* RC
Allows to remove trailing zeros.
`<major>(.<minor>(.<patch>)?)?(.<increment>)*(-<extension>)*`

```
# 1.0.0-GA+20230101-56789
<valid semver> ::= <numberic version>
| <numberic version> <extensions>
# 1.12.0
<numberic version> ::= <digits>
| <digits> "." <digits>
<extensions> ::= "-" <release-extension>
| "+" <build-extension>
| "-" <release-extension> <extensions>
| "+" <build-extension> <extensions>
# 123 or 0815
<digits> ::= <digit>
| <digit> <digits>
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
# feature_2343
<letters> ::= <letter>
| <letter> <letters>
| <letter> "_" <letters>
<letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
| "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
| "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
| "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
| "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
| "y" | "z"
```

Following `release-extension` are regonized with special semantic meaning:

DEV-Release extensions
* LOCAL
* DEV
* SNAPSHOT
* MILESTONE (m)

Besides this syntax even more version components are supported:
PRE-Release extensions
* ALPHA (a)
* BETA (b)
* PREVIEW (ea, rc, cr)

`<major>.<minor>.<patch>[.<comp4>[.<comp5>...[.<compN>]]]-<incrementState><increment>`
GA-Release extensions
* FINAL
* GA
* RELEASE

POST-Release extensions
* SP

Build extensions
* v
* (separated with +)

Platform extensions
* jre

### Examples

| Example | Major | Minor | Patch | IncrementState | Increment |
|-------------|-------|-------|-------|----------------|-----------|
| 1.2.3 | 1 | 2 | 3 | GA | 0 |
| 4.5.6-FINAL | 4 | 5 | 6 | GA | 0 |
| 4.5.6-GA | 4 | 5 | 6 | GA | 0 |
| 4.5.6-RC1 | 4 | 5 | 6 | RC | 1 |
| 4.5.6-DEV3 | 4 | 5 | 6 | DEV | 3 |
| 1.2.3.4.5.6 | 1 | 2 | 3 | GA | 4 |
| Example | Major | Minor | Patch | Extentension Type |
|-------------|-------|-------|-------|----------------|
| 1.2.3 | 1 | 2 | 3 | GA |
| 4.5.6-FINAL | 4 | 5 | 6 | GA |
| 4.5.6-GA | 4 | 5 | 6 | GA |
| 4.5.6-RC1 | 4 | 5 | 6 | RC |
| 4.5.6-DEV3 | 4 | 5 | 6 | DEV |
| 1.2.3.4.5.6 | 1 | 2 | 3 | GA |
| 4.5.6-RC1-jre8 | 4 | 5 | 6 | RC |

# Usage
## Creation

Either
Creating a semantic version object
```java
SemanticVersion.valueOf("1.2.3")
```

or
```java
SemanticVersion.valueOf(1, 2, 3)
```

## Comparing
```java
Expand All @@ -58,7 +118,10 @@ Compares two versions with semantic meaning. This leads to following outcome.
| `== 0` | semanticVersion1 == semanticVersion2 | same semantic meaning |
| `> 0` | semanticVersion1 > semanticVersion2 | semanticVersion1 is greater/newer |

## Finding an appropriate version
## Find newest version for a given update strategy
Supporting former releases, doesn't allow often to migrate to the newest version of a library. Therefore
The `SemanticVersionMigration.getMigration` supports filtering for a given update strategy.

Imagine the current version is
* `1.2.3`

Expand All @@ -73,7 +136,7 @@ the following code will find the appropriate update version matching your desire
SemanticVersions.getNewestVersion(updateStrategy, List.of("1.2.4", "1.3.0", "2.0.1", "2.0.2-RC1"), "1.2.3")
```

with the following outcome
with the following outcome (getMigration return an optional)

| UpdateStrategy | Outcome |
|----------------|-----------|
Expand Down
29 changes: 6 additions & 23 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,15 @@ plugins {
// artifact signing - necessary on Maven Central
signing

// intershop version plugin
id("com.intershop.gradle.scmversion") version "6.2.0"

id("com.dorongold.task-tree") version "2.1.0"
}

scm {
version {
type = "threeDigits"
initialVersion = "1.0.0"
}
}

// release configuration
group = "com.intershop.version"
description = "semantic version"

// IMPORTANT version referenced at README.md, adapt it there
version = scm.version.version
// IMPORTANT version referenced at README.md, adapt it there

// set correct project status
if (project.version.toString().endsWith("-SNAPSHOT")) {
status = "snapshot"
}
// IMPORTANT will be set by -Pversion=${{ github.ref_name }}
// version = "1.0.0"

val sonatypeUsername: String? by project
val sonatypePassword: String? by project
Expand Down Expand Up @@ -96,7 +80,7 @@ tasks {
xml.required.set(true)
html.required.set(true)

html.outputLocation.set( File(project.buildDir, "jacocoHtml") )
html.outputLocation.set( File(project.layout.buildDirectory.asFile.get(), "jacocoHtml") )
}

val jacocoTestReport by tasks
Expand Down Expand Up @@ -161,10 +145,9 @@ signing {
}

dependencies {
implementation(gradleApi())

implementation("org.apache.commons:commons-collections4:4.4")

testImplementation("org.junit.jupiter:junit-jupiter:5.9.0")
testImplementation("org.hamcrest:hamcrest:2.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
29 changes: 17 additions & 12 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
Expand Down Expand Up @@ -133,26 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
Expand Down Expand Up @@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi

# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.

set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
Expand Down
97 changes: 97 additions & 0 deletions src/main/java/com/intershop/version/semantic/ExtensionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright 2020 Intershop Communications AG.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.intershop.version.semantic;

/**
* Semantic meaning of version extension
* <ul>
* <li>DEV an internal version for internal testing and migration (alpha,beta,snapshot,dev)</li>
* <li>PRE a version before the GA is happen to get feedback from stack holder (rc,cr,ea,preview)</li>
* <li>BUILD the version extension contains a build number (it's not related to a version state) (like 'v' or '+')</li>
* <li>NEUTRAL version extension for initialization</li>
* <li>PLATFORM a version extension which references a required platform (jre)</li>
* <li>GA a version which is officially supported (GA,FINAL)</li>
* <li>POST a version which is has the same code, but may has documentation fixes (sp)</li>
* <li>UNSPECIFIED a extension with undefined semantic (e.g. abc)</li>
* </ul>
*/
public enum ExtensionType
{
/**
* internal developer version
*/
DEV(false, true),

/**
* pre release for testing purposes or preview for external stackholder
*/
PRE(false, true),

/**
* build extension (will be ignored for semantic meaning of version)
*/
BUILD(true, true),
/**
* extension type not defined yet
*/
NEUTRAL(true, false),

/**
* platform extension marker
*/
PLATFORM(true, false),

/**
* general availability marker
*/
GA(true, true),

/**
* post release marker
*/
POST(true, true),

/**
* release marker with unknown semantic
*/
UNSPECIFIED(false, true);

private final boolean recommendedForProduction;
private final boolean areNumbersRelevantForSorting;

ExtensionType(boolean recommendedForProduction, boolean areNumbersRelevantForSorting)
{
this.recommendedForProduction = recommendedForProduction;
this.areNumbersRelevantForSorting = areNumbersRelevantForSorting;
}

/**
* @return true if the related version is recommended for production
*/
public boolean isRecommendedForProduction()
{
return recommendedForProduction;
}

/**
* @return true numbers in the version extension is relevant for sorting (true for rc1; false for jre8)
*/
public boolean isAreNumbersRelevantForSorting()
{
return areNumbersRelevantForSorting;
}
}
Loading

0 comments on commit 25d9297

Please sign in to comment.