-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle date-based tags as v1.2.3 style
- Loading branch information
Karl DeBisschop
committed
Jul 21, 2024
1 parent
a746948
commit dcfd438
Showing
6 changed files
with
104 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,38 +15,34 @@ | |
*/ | ||
package com.bioraft.rundeck.nexus; | ||
|
||
import java.util.Arrays; | ||
import java.util.Iterator; | ||
|
||
import org.apache.commons.lang.builder.CompareToBuilder; | ||
import org.apache.maven.artifact.versioning.ComparableVersion; | ||
|
||
/** | ||
* Puts branches or versions followed by a build designator into a uniform structure. | ||
* | ||
* Expands three-part semantic versions to handle cases where there are more | ||
* than 3 parts and where build specifier may be attached by "_" or "+". (Although | ||
* it would really just be better if people only used semantic versions.) | ||
* | ||
* Also puts branches into a similar structure. In particular, branches like | ||
* | ||
* <p>Parses versions and branches where there is a build specifier attached by "-", | ||
* "_" or "+". | ||
* | ||
* <p>Also puts branches into a similar structure. In particular, branches like | ||
* ISSUE-1234-bug-description will be sorted numerically. | ||
* | ||
* In particular, the algorithm assumes each componentVersion or docker image tag | ||
* | ||
* <p>In particular, the algorithm assumes each componentVersion or docker image tag | ||
* is composed of a version or branch followed by a build designator. The build | ||
* designator is first extracted by looking for a part of the componentVersion | ||
* after either "-", "_", or "+". If there is more than one [_+-] the match looks | ||
* for the last one. | ||
* | ||
* The part before the build designator (and separator) is considered the version | ||
* | ||
* <p>The part before the build designator (and separator) is considered the version | ||
* or branch. If there are two consecutive integers separated by a decimal, then it | ||
* is considered a version specifier. Otherwise it is considered a branch name. In | ||
* is considered a version specifier. Otherwise, it is considered a branch name. In | ||
* either case, it is split into parts at each period (i.e., "."). | ||
* | ||
* Each part of the versionOrBranch and the build specifier are considered in 3 parts: | ||
* | ||
* <p>Each part of the versionOrBranch and the build specifier are considered in 3 parts: | ||
* - Zero or more non-numeric initial characters | ||
* - Zero or more integers | ||
* - Zero or more concluding characters that may be a mix of integers and non-integers | ||
* | ||
* These fields in order are used to sort the assets. | ||
* | ||
* <p>These fields in order are used to sort the assets. | ||
* | ||
* @author Karl DeBisschop <[email protected]> | ||
* @since 2019-12-26 | ||
|
@@ -55,11 +51,11 @@ public class BranchOrVersion { | |
|
||
public static final String BUILD_SEPARATOR_REGEX = "[_+-]"; | ||
|
||
String artifactId; | ||
String versionOrBranch; | ||
String build; | ||
String sep; | ||
String[] parts; | ||
private final String artifactId; | ||
private final String versionOrBranch; | ||
private String build; | ||
private final String componentVersion; | ||
private final String comparator; | ||
|
||
public String getArtifactId() { | ||
return artifactId; | ||
|
@@ -75,35 +71,37 @@ public String getVersion() { | |
|
||
public BranchOrVersion(String path) { | ||
artifactId = component(path); | ||
String tag = tag(path); | ||
if (tag.matches("^.+" + BUILD_SEPARATOR_REGEX + "[a-zA-Z0-9]+$")) { | ||
build = tag.replaceFirst("^.+" + BUILD_SEPARATOR_REGEX + "([a-zA-Z0-9]+)$", "$1"); | ||
versionOrBranch = tag.replaceFirst("^(.+)" + BUILD_SEPARATOR_REGEX + build + "$", "$1"); | ||
sep = tag.replaceFirst("^.+(" + BUILD_SEPARATOR_REGEX + ")" + build + "$", "$1"); | ||
componentVersion = tag(path); | ||
String sep; | ||
if (componentVersion.matches("^.+" + BUILD_SEPARATOR_REGEX + "[a-zA-Z0-9_-]+$")) { | ||
build = componentVersion.replaceFirst("^.+" + BUILD_SEPARATOR_REGEX + "([a-zA-Z0-9_-]+)$", "$1"); | ||
versionOrBranch = componentVersion.replaceFirst("^(.+)" + BUILD_SEPARATOR_REGEX + build + "$", "$1"); | ||
sep = componentVersion.replaceFirst("^.+(" + BUILD_SEPARATOR_REGEX + ")" + build + "$", "$1"); | ||
} else { | ||
build = ""; | ||
versionOrBranch = tag; | ||
versionOrBranch = componentVersion; | ||
sep = ""; | ||
} | ||
this.parts = versionOrBranch.split("[.]"); | ||
} | ||
|
||
public Iterator<String> getIterator() { | ||
return Arrays.asList(parts).iterator(); | ||
if (componentVersion.matches("^rc(\\d+[.].*)")) { | ||
build = build + "rc"; | ||
if (sep.isEmpty()) { | ||
sep = "-"; | ||
} | ||
} | ||
comparator = componentVersion.replaceFirst("^(v|rc)(\\d+[.].*)", "$2") + sep + build; | ||
} | ||
|
||
/** | ||
* Consider a component version to be anything with 2 consecutive integer parts. | ||
* Anything else is considered to be a branch. | ||
*/ | ||
public boolean isVersion() { | ||
return versionOrBranch.matches(".*[0-9]+[.][0-9]+.*"); | ||
return versionOrBranch.matches(".*\\d+[.]\\d+.*"); | ||
} | ||
|
||
/** | ||
* Use array of parts to do comparison so it can compare regardless of number of | ||
* parts in a version specifier. | ||
* | ||
* Decorate maven ComparableVersion to handle a few edge cases. | ||
* | ||
* @param other The object to compare against. | ||
* @return Return 0 if equal, 1 if this is greater, -1 if that is greater. | ||
*/ | ||
|
@@ -112,50 +110,13 @@ public int compareTo(Object other) { | |
return 1; | ||
} | ||
BranchOrVersion that = (BranchOrVersion) other; | ||
CompareToBuilder comparator = new CompareToBuilder(); | ||
Iterator<String> thatIterator = that.getIterator(); | ||
Iterator<String> thisIterator = getIterator(); | ||
while (thatIterator.hasNext()) { | ||
if (!thisIterator.hasNext()) { | ||
if (comparator.toComparison() == 0) { | ||
return -1; | ||
} else { | ||
break; | ||
} | ||
} | ||
String thisOne = thisIterator.next(); | ||
String thatOne = thatIterator.next(); | ||
comparator.append(partOne(thisOne), partOne(thatOne)); | ||
comparator.append(partTwo(thisOne), partTwo(thatOne)); | ||
comparator.append(partThree(thisOne), partThree(thatOne)); | ||
} | ||
if (comparator.toComparison() == 0 && thisIterator.hasNext()) { | ||
return 1; | ||
} | ||
comparator.append(partOne(this.build), partOne(that.build)); | ||
comparator.append(partTwo(this.build), partTwo(that.build)); | ||
comparator.append(partThree(this.build), partThree(that.build)); | ||
return comparator.toComparison(); | ||
} | ||
|
||
private String partOne(String string) { | ||
return string.replaceFirst("^([^0-9]*).*$", "$1"); | ||
} | ||
|
||
private Integer partTwo(String string) { | ||
String integerPart = string.replaceFirst("^[^0-9]*([0-9]*).*$", "$1"); | ||
if (integerPart.length() == 0) { | ||
return 0; | ||
} | ||
return Integer.parseInt(integerPart); | ||
} | ||
|
||
private String partThree(String string) { | ||
return string.replaceFirst("^[^0-9]*[0-9]*", ""); | ||
ComparableVersion thisVersion = new ComparableVersion(comparator); | ||
ComparableVersion thatVersion = new ComparableVersion(that.comparator); | ||
return Integer.signum(thisVersion.compareTo(thatVersion)); | ||
} | ||
|
||
public String toString() { | ||
return artifactId + ":" + String.join(".", parts) + sep + build; | ||
return artifactId + ":" + componentVersion; | ||
} | ||
|
||
/** | ||
|
@@ -168,7 +129,7 @@ private String component(String path) { | |
/** | ||
* Extracts tag part of a path. The tag (or componentVersion in the Nexus query) | ||
* can reflect either a branch name or a semantic version. Either branches or | ||
* versions may be suffixed by a build specified, which can be numeric or | ||
* versions may be suffixed by a build specifier, which can be numeric or | ||
* string-valued. | ||
*/ | ||
private String tag(String path) { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ | |
* Expands three-part semantic versions to handle cases where there are more | ||
* than 3 parts and where build specifier may be attached by "_" or "+". | ||
* | ||
* It would really just be better if people only used semantic versions. | ||
* <p>It would really just be better if people only used semantic versions. | ||
* | ||
* @author Karl DeBisschop <[email protected]> | ||
* @since 2019-12-26 | ||
|
@@ -40,7 +40,7 @@ public class OptionProviderImpl { | |
|
||
static final String CONTINUATION_TOKEN = "continuationToken"; | ||
|
||
private OkHttpClient client; | ||
private final OkHttpClient client; | ||
|
||
private Map<String, String> config; | ||
|
||
|
@@ -105,12 +105,13 @@ public List<OptionValue> getOptionValues(Map<String, String> config) { | |
|
||
/** | ||
* Update the Branches Map. | ||
* | ||
* @param current The branch or version object we are considering. | ||
* @param versionOrBuild The version or build of the object we are considering. | ||
*/ | ||
private void updateBranchOrVersionMap(BranchOrVersion current, String versionOrBuild, Map<String, BranchOrVersion> map) { | ||
// If we are already tracking the branch, check to ensure this is newer before saving. | ||
// Otherwise, it is a new branc to us so start tracking it. | ||
// Otherwise, it is a new branch to us so start tracking it. | ||
if (map.containsKey(versionOrBuild)) { | ||
if (current.compareTo(map.get(versionOrBuild)) > 0) { | ||
map.put(versionOrBuild, current); | ||
|
@@ -135,10 +136,7 @@ static SortedSet<Map.Entry<String, BranchOrVersion>> entriesSortedByValues( | |
} | ||
|
||
/** | ||
* Perform the Nexus API request. | ||
* | ||
* This is really just syntactic sugar for the initial request (with no | ||
* continuation token). But it adds some clarity. | ||
* Perform the initial Nexus API request. | ||
* | ||
* @return An ArrayList of path strings. | ||
*/ | ||
|
@@ -149,7 +147,7 @@ private ArrayList<String> nexusSearch() { | |
/** | ||
* Perform the Nexus API request, including continuation for larger result sets. | ||
* | ||
* Since all we need to prepare the option list is path, extract that from the | ||
* <p>Since all we need to prepare the option list is path, extract that from the | ||
* JsonNode and return just a list of strings in the interest of conserving | ||
* system resources. | ||
* | ||
|
@@ -179,7 +177,7 @@ private ArrayList<String> nexusSearch(String continuationToken) { | |
return new ArrayList<>(); | ||
} | ||
json = body.string(); | ||
if (json.length() == 0) { | ||
if (json.isEmpty()) { | ||
return new ArrayList<>(); | ||
} | ||
} catch (NullPointerException | IOException e) { | ||
|
@@ -198,7 +196,7 @@ private ArrayList<String> nexusSearch(String continuationToken) { | |
} | ||
if (tree.has(CONTINUATION_TOKEN)) { | ||
String token = tree.path(CONTINUATION_TOKEN).asText(); | ||
if (token.length() > 0) { | ||
if (!token.isEmpty()) { | ||
ArrayList<String> nextItems = nexusSearch(token); | ||
itemList.addAll(nextItems); | ||
} | ||
|
@@ -225,8 +223,8 @@ private HttpUrl.Builder buildUrl(String endpoint, String continuationToken) { | |
/** | ||
* Provides a means of informing users that the Nexus host still needs to be | ||
* configured. | ||
* | ||
* All methods are straightforward implementations of the interface. | ||
* | ||
* <p>All methods are straightforward implementations of the interface. | ||
*/ | ||
static class ErrorOptionValue implements OptionValue { | ||
String name; | ||
|
Oops, something went wrong.