Skip to content

Commit

Permalink
Handle date-based tags as v1.2.3 style
Browse files Browse the repository at this point in the history
  • Loading branch information
Karl DeBisschop committed Jul 21, 2024
1 parent a746948 commit dcfd438
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 143 deletions.
14 changes: 7 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ apply plugin: 'eclipse'
apply plugin: 'idea'

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

defaultTasks 'clean','build'
Expand All @@ -40,8 +40,8 @@ group = 'com.github.kdebisschop'

ext.rundeckPluginVersion = '1.2'
ext.pluginClassNames='com.bioraft.rundeck.nexus.Nexus3OptionProvider'
ext.pluginName = 'Nexus3 Option Values Porvider'
ext.pluginDescription = 'Fetches and filters assests from a Nexus3 repository'
ext.pluginName = 'Nexus3 Option Values Provider'
ext.pluginDescription = 'Fetches and filters assets from a Nexus3 repository'

scmVersion {
ignoreUncommittedChanges = true
Expand All @@ -65,7 +65,6 @@ scmVersion {
project.version = scmVersion.version

repositories {
mavenLocal()
mavenCentral()
}

Expand All @@ -86,9 +85,10 @@ gradle.projectsEvaluated {
}

dependencies {
implementation 'org.rundeck:rundeck-core:3.4.10-20220118'
implementation 'org.rundeck:rundeck-core:5.4.0-20240618'
implementation 'org.apache.maven:maven-artifact:3.9.8'

testImplementation group: 'junit', name: 'junit', version:'4.12'
testImplementation group: 'junit', name: 'junit', version: '4.13.1'

testImplementation (
'org.mockito:mockito-all:1.10.19',
Expand Down
123 changes: 42 additions & 81 deletions src/main/java/com/bioraft/rundeck/nexus/BranchOrVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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.
*/
Expand All @@ -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;
}

/**
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class Nexus3OptionProvider implements OptionValuesPlugin {

public static final String PLUGIN_NAME = "Nexus3OptionProvider";

private OkHttpClient client;
private final OkHttpClient client;

@PluginProperty(title = "Endpoint scheme", description = "Nexus server scheme", required = true, defaultValue = "https", scope = PropertyScope.Project)
private String endpointScheme;
Expand Down Expand Up @@ -89,7 +89,7 @@ public List<OptionValue> getOptionValues(Map configuration) {
private void setVariable(Map configuration, String variableName, String variable) {
if (configuration.containsKey(variableName)) {
config.put(variableName, configuration.get(variableName).toString());
} else if (variable != null && variable.length() > 0) {
} else if (variable != null && !variable.isEmpty()) {
config.put(variableName, variable);
}
}
Expand Down
22 changes: 10 additions & 12 deletions src/main/java/com/bioraft/rundeck/nexus/OptionProviderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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.
*/
Expand All @@ -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.
*
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
Expand All @@ -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;
Expand Down
Loading

0 comments on commit dcfd438

Please sign in to comment.