Skip to content

Commit

Permalink
Merge pull request #111 from shipkit/sf--4-part-version
Browse files Browse the repository at this point in the history
Added support for 4-part versions
  • Loading branch information
shestee authored May 22, 2022
2 parents c9b6c75 + 095a7d1 commit 0432d9a
Show file tree
Hide file tree
Showing 16 changed files with 304 additions and 103 deletions.
36 changes: 19 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This way, you don't need to do any "version bump" commits in every release!
This project is inspired on [Axion plugin](https://github.com/allegro/axion-release-plugin), and few others, listed later in this document.

```shipkit-auto-version``` plugin is **tiny** and has a single dependency on [jSemver](https://github.com/zafarkhaja/jsemver).
It is a safe dependency because it is tiny, has no dependencies, and it is final (no code changes since 2015 - it wraps semver protocol that had [no changes since 2013](https://github.com/semver/semver/tree/v2.0.0)).
It is a safe dependency because it is tiny, has no dependencies, and it is final (no code changes since 2015 - it wraps semver protocol that as of 2022 had [no changes since 2013](https://github.com/semver/semver/tree/v2.0.0)).

Do you want to automate changelog generation?
Check out [shipkit-changelog](https://github.com/shipkit/shipkit-changelog) plugin that neatly integrate with ```shipkit-auto-version``` plugin.
Expand Down Expand Up @@ -158,15 +158,16 @@ When the plugin is applied to the project it will:
- identifies the latest (newest) version matching version spec
- compares the version with the version spec:

| case | spec | latest tag | -Pversion= | # of commits | result | description |
|------|-------|------------|-----------------|-----------------|-----------------|--------------------------------------|
| a | 1.0.* | v1.0.5 | | 0 | 1.0.5 | zero new commits |
| b | 1.0.* | v1.0.5 | | 2 | 1.0.7 | two new commits |
| c | 1.0.* | v1.0.5 | | 5 (2 merge + 1) | 1.0.8 | two merge commits and new one on top |
| d | 1.1.* | v1.0.5 | | 5 | 1.1.0 | first x.y.0 version |
| e | 2.0.* | v1.0.5 | | 5 | 2.0.0 | first z.0.0 version |
| f | 1.\*.5| | | | error | unsupported format |
| g | 1.0.* | v1.0.5 | 1.0.10-SNAPSHOT | [any] | 1.0.10-SNAPSHOT | version overridden from CLI argument |
| case | spec | latest tag | -Pversion= | # of commits | result | description |
|------|---------|------------|-----------------|-----------------|-----------------|-----------------------------------------|
| a | 1.0.* | v1.0.5 | | 0 | 1.0.5 | zero new commits |
| b | 1.0.* | v1.0.5 | | 2 | 1.0.7 | two new commits |
| c | 1.0.* | v1.0.5 | | 5 (2 merge + 1) | 1.0.8 | two merge commits and new one on top |
| d | 1.1.* | v1.0.5 | | 5 | 1.1.0 | first x.y.0 version |
| e | 2.0.* | v1.0.5 | | 5 | 2.0.0 | first z.0.0 version |
| f | 1.\*.5 | | | | error | unsupported format |
| g | 1.0.* | v1.0.5 | 1.0.10-SNAPSHOT | [any] | 1.0.10-SNAPSHOT | version overridden from CLI argument |
| e | 1.0.0.* | v1.0.0.5 | | 1 | 1.0.0.6 | we support 4-part versions (non-semver) |

- in case a),b) we are resolving the wildcard based on # of commits on top of the tag
- run `git log` to identify # of commits
Expand All @@ -186,6 +187,7 @@ When the plugin is applied to the project it will:

- in case d),e) use '0' as patch version
- in case g) the user manually specified the version on the command line
- in case e) we support 4-part versions like 1.2.3.4 (note that those versions are not semver compatible)

### When releasing every tag

Expand All @@ -202,13 +204,13 @@ When tag does not match the convention (`tagPrefix`) the plugin picks fallback v

#### Examples:

| case | version.properties | checked out on | -Pversion= | result
|------|---------------------------|-----------------|-----------------|------------------------------------------------------
| h | (empty/missing) | v1.0.5 | | 1.0.5 (no 'tagPrefix' specified, default is 'v')
| i | tagPrefix=ver- | ver-1.0.5 | | 1.0.5 ('tagPrefix' matches the tag)
| j | (empty/missing) | v1.0.5-2-sha123 | | 1.0.6-SNAPSHOT (ahead of "v1.0.5" tag)
| k | tagPrefix= | v1.0.5 | | 0.0.1-SNAPSHOT (empty tag prefix doesn't match 'v')
| l | (empty/missing) | v1.0.2 | 1.0.5-SNAPSHOT | 1.0.5-SNAPSHOT (version overridden from CLI argument)
| case | version.properties | checked out on | -Pversion= | result |
|------|---------------------------|-----------------|-----------------|------------------------------------------------------|
| h | (empty/missing) | v1.0.5 | | 1.0.5 (no 'tagPrefix' specified, default is 'v') |
| i | tagPrefix=ver- | ver-1.0.5 | | 1.0.5 ('tagPrefix' matches the tag) |
| j | (empty/missing) | v1.0.5-2-sha123 | | 1.0.6-SNAPSHOT (ahead of "v1.0.5" tag) |
| k | tagPrefix= | v1.0.5 | | 0.0.1-SNAPSHOT (empty tag prefix doesn't match 'v') |
| l | (empty/missing) | v1.0.2 | 1.0.5-SNAPSHOT | 1.0.5-SNAPSHOT (version overridden from CLI argument)|

## Similar plugins

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ class AutoVersionPluginIntegTest extends Specification {
run("tasks")
}

def "uses four-number version scheme"() {
file("version.properties") << "version=1.0.0.1"
file("build.gradle") << "assert project.version == '1.0.0.1'"

expect:
run("tasks")
}

File file(String path) {
def f = new File(rootDir, path)
if (!f.exists()) {
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/org/shipkit/auto/version/AutoVersion.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.shipkit.auto.version;

import com.github.zafarkhaja.semver.Version;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;

Expand Down Expand Up @@ -40,21 +39,21 @@ DeductedVersion deductVersion(String projectVersion) {

//Exposed for testing so that 'log' can be mocked
DeductedVersion deductVersion(Logger log, String projectVersion) {
Optional<Version> previousVersion = Optional.empty();
Optional<VersionNumber> previousVersion = Optional.empty();
VersionConfig config = VersionConfig.parseVersionFile(versionFile);

try {
Collection<Version> versions = new VersionsProvider(runner).getAllVersions(config.getTagPrefix());
Collection<VersionNumber> versions = new VersionsProvider(runner).getAllVersions(config.getTagPrefix());
PreviousVersionFinder previousVersionFinder = new PreviousVersionFinder();

if (config.getRequestedVersion().isPresent()) {
if (config.getVersionSpec().isPresent()) {
previousVersion = previousVersionFinder.findPreviousVersion(versions, config);
}

String nextVersion = new NextVersionPicker(runner, log).pickNextVersion(previousVersion,
config, projectVersion);

if (!config.getRequestedVersion().isPresent()) {
if (!config.getVersionSpec().isPresent()) {
previousVersion = previousVersionFinder.findPreviousVersion(versions, new VersionConfig(nextVersion, config.getTagPrefix()));
}

Expand All @@ -64,13 +63,13 @@ DeductedVersion deductVersion(Logger log, String projectVersion) {
} catch (Exception e) {
String message = "caught an exception, falling back to reasonable default";
log.debug("shipkit-auto-version " + message, e);
String v = config.getRequestedVersion().orElse("0.0.1-SNAPSHOT").replace("*", "unspecified");
String v = config.getVersionSpec().orElse("0.0.1-SNAPSHOT").replace("*", "unspecified");
explainVersion(log, v, message + "\n - run with --debug for more info");
return new DeductedVersion(v, previousVersion, config.getTagPrefix());
}
}

private void logPreviousVersion(Logger log, Optional<Version> previousVersion) {
private void logPreviousVersion(Logger log, Optional<VersionNumber> previousVersion) {
log.info("[shipkit-auto-version] " + previousVersion
.map(version -> "Previous version: " + version)
.orElse("No previous version"));
Expand Down
8 changes: 2 additions & 6 deletions src/main/java/org/shipkit/auto/version/DeductedVersion.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.shipkit.auto.version;

import com.github.zafarkhaja.semver.Version;

import javax.annotation.Nullable;
import java.util.Objects;
import java.util.Optional;
Expand All @@ -14,13 +12,11 @@ class DeductedVersion {
private final String version;
private final String previousVersion;
private final String previousTag;
private final String tagPrefix;

DeductedVersion(String version, Optional<Version> previousVersion, String tagPrefix) {
this.tagPrefix = tagPrefix;
DeductedVersion(String version, Optional<VersionNumber> previousVersion, String tagPrefix) {
Objects.requireNonNull(version, "version cannot be null");
this.version = version;
this.previousVersion = previousVersion.map(Version::toString).orElse(null);
this.previousVersion = previousVersion.map(VersionNumber::toString).orElse(null);
this.previousTag = previousVersion.map(v -> TagConvention.tagFor(v.toString(), tagPrefix)).orElse(null);
}

Expand Down
28 changes: 11 additions & 17 deletions src/main/java/org/shipkit/auto/version/NextVersionPicker.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.shipkit.auto.version;

import com.github.zafarkhaja.semver.Version;
import org.gradle.api.Project;
import org.gradle.api.logging.Logger;

Expand All @@ -26,13 +25,13 @@ class NextVersionPicker {
/**
* Picks the next version to use based on the input parameters
*/
String pickNextVersion(Optional<Version> previousVersion, VersionConfig config, String projectVersion) {
String pickNextVersion(Optional<VersionNumber> previousVersion, VersionConfig config, String projectVersion) {
if (!Project.DEFAULT_VERSION.equals(projectVersion)) {
explainVersion(log, projectVersion, "uses version already specified in the Gradle project");
return projectVersion;
}

if (!config.getRequestedVersion().isPresent()) {
if (!config.getVersionSpec().isPresent()) {
String tag;
String result;

Expand All @@ -50,11 +49,11 @@ String pickNextVersion(Optional<Version> previousVersion, VersionConfig config,
if (isSupportedVersion(tag, config.getTagPrefix())) {
result = tag.substring(config.getTagPrefix().length());
explainVersion(log, result, "deducted version based on tag: '" + tag + "'");
} else if (isSnapshot(tag, config.getTagPrefix())){
Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+");
} else if (isSnapshot(tag, config.getTagPrefix())) {
Pattern pattern = Pattern.compile("\\d+\\.\\d+\\.\\d+(\\.\\d+)?");
Matcher matcher = pattern.matcher(tag);
matcher.find();
result = Version.valueOf(matcher.group()).incrementPatchVersion("SNAPSHOT").toString();
result = new VersionNumber(matcher.group()).incrementBy(1).toString() + "-SNAPSHOT";
explainVersion(log, result,
"deducted snapshot based on tag: '" + config.getTagPrefix() + matcher.group() + "'");
} else {
Expand All @@ -67,21 +66,16 @@ String pickNextVersion(Optional<Version> previousVersion, VersionConfig config,

if (!config.isWildcard()) {
//if there is no wildcard we will use the version 'as is'
explainVersion(log, config.getRequestedVersion().get(), "uses verbatim version from version file");
return config.getRequestedVersion().get();
explainVersion(log, config.getVersionSpec().get(), "uses verbatim version from version file");
return config.getVersionSpec().get();
}

if (previousVersion.isPresent() && previousVersion.get().satisfies(config.getRequestedVersion().get())) {
Version prev = previousVersion.get();
if (previousVersion.isPresent() && previousVersion.get().satisfies(config.getVersionSpec().get())) {
VersionNumber prev = previousVersion.get();
String gitOutput = runner.run(
"git", "log", "--pretty=oneline", TagConvention.tagFor(prev.toString(), config.getTagPrefix()) + "..HEAD");
int commitCount = new CommitCounter().countCommitDelta(gitOutput);
String result = Version
.forIntegers(
prev.getMajorVersion(),
prev.getMinorVersion(),
prev.getPatchVersion() + commitCount)
.toString();
String result = prev.incrementBy(commitCount).toString();
explainVersion(log, result, "deducted version based on previous tag: '" + prev + "'");
return result;
} else {
Expand All @@ -95,7 +89,7 @@ String pickNextVersion(Optional<Version> previousVersion, VersionConfig config,
* Explain version in a consistent, human-readable way
*/
static void explainVersion(Logger log, String version, String reason) {
log.lifecycle("Building version '"+ version + "'\n" +
log.lifecycle("Building version '" + version + "'\n" +
" - reason: shipkit-auto-version " + reason);
}
}
22 changes: 10 additions & 12 deletions src/main/java/org/shipkit/auto/version/PreviousVersionFinder.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.shipkit.auto.version;

import com.github.zafarkhaja.semver.Version;

import java.util.Collection;
import java.util.Optional;

Expand All @@ -13,16 +11,16 @@ class PreviousVersionFinder {
/**
* Finds previous version based on the version specification
*/
Optional<Version> findPreviousVersion(Collection<Version> versions, VersionConfig config) {
if (config.getRequestedVersion().isPresent() && !config.isWildcard()) {
Optional<VersionNumber> findPreviousVersion(Collection<VersionNumber> versions, VersionConfig config) {
if (config.getVersionSpec().isPresent() && !config.isWildcard()) {
//Requested version is a concrete version like 1.0.0 (no wildcard).
//We just find the previous version
return findPrevious(versions, Version.valueOf(config.getRequestedVersion().get()));
return findPrevious(versions, new VersionNumber(config.getVersionSpec().get()));
}

Optional<Version> max = versions.stream()
.filter(v -> v.satisfies(config.getRequestedVersion().get()))
.max(Version::compareTo);
Optional<VersionNumber> max = versions.stream()
.filter(v -> v.satisfies(config.getVersionSpec().get()))
.max(VersionNumber::compareTo);

if (max.isPresent()) {
return max; //we found it! just return.
Expand All @@ -31,12 +29,12 @@ Optional<Version> findPreviousVersion(Collection<Version> versions, VersionConfi
//We did not find it. This happens in example scenario:
// versions are 0.0.1, 0.0.2 and the requested version is 0.1.*
String newPatchVersion = config.newPatchVersion();
return findPrevious(versions, Version.valueOf(newPatchVersion));
return findPrevious(versions, new VersionNumber(newPatchVersion));
}

private Optional<Version> findPrevious(Collection<Version> versions, Version version) {
private Optional<VersionNumber> findPrevious(Collection<VersionNumber> versions, VersionNumber version) {
return versions.stream()
.filter(v -> v.lessThan(version))
.max(Version::compareTo);
.filter(v -> v.compareTo(version) < 0)
.max(VersionNumber::compareTo);
}
}
Loading

0 comments on commit 0432d9a

Please sign in to comment.