Skip to content

Commit

Permalink
Add range type in ignoreVersion
Browse files Browse the repository at this point in the history
  • Loading branch information
slawekjaranowski committed Jun 21, 2024
1 parent 0cafa40 commit 7b86752
Show file tree
Hide file tree
Showing 15 changed files with 278 additions and 71 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@
<version>1.4.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
<version>1.4.1</version>
</dependency>

<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
Expand Down
6 changes: 6 additions & 0 deletions versions-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>

<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@
public class DefaultVersionsHelper implements VersionsHelper {
private static final String CLASSPATH_PROTOCOL = "classpath";

private static final String TYPE_EXACT = "exact";

private static final String TYPE_REGEX = "regex";

private static final int LOOKUP_PARALLEL_THREADS = 5;

/**
Expand Down Expand Up @@ -258,8 +254,7 @@ public ArtifactVersions lookupArtifactVersions(
try {
Collection<IgnoreVersion> ignoredVersions = getIgnoredVersions(artifact);
if (!ignoredVersions.isEmpty() && getLog().isDebugEnabled()) {
getLog().debug("Found ignored versions: "
+ ignoredVersions.stream().map(IgnoreVersion::toString).collect(Collectors.joining(", ")));
getLog().debug("Found ignored versions: " + ignoredVersions + " for artifact" + artifact);
}

final List<RemoteRepository> repositories;
Expand Down Expand Up @@ -292,21 +287,7 @@ public ArtifactVersions lookupArtifactVersions(
.getVersions()
.stream()
.filter(v -> ignoredVersions.stream().noneMatch(i -> {
if (TYPE_REGEX.equals(i.getType())
&& Pattern.compile(i.getVersion())
.matcher(v.toString())
.matches()) {
if (getLog().isDebugEnabled()) {
getLog().debug("Version " + v + " for artifact "
+ ArtifactUtils.versionlessKey(artifact)
+ " found on ignore list: "
+ i);
}
return true;
}

if (TYPE_EXACT.equals(i.getType())
&& i.getVersion().equals(v.toString())) {
if (IgnoreVersionHelper.isVersionIgnored(v, i)) {
if (getLog().isDebugEnabled()) {
getLog().debug("Version " + v + " for artifact "
+ ArtifactUtils.versionlessKey(artifact)
Expand Down Expand Up @@ -342,25 +323,24 @@ private List<IgnoreVersion> getIgnoredVersions(Artifact artifact) {
final List<IgnoreVersion> ret = new ArrayList<>();

for (final IgnoreVersion ignoreVersion : ruleSet.getIgnoreVersions()) {
if (!TYPE_EXACT.equals(ignoreVersion.getType()) && !TYPE_REGEX.equals(ignoreVersion.getType())) {
if (IgnoreVersionHelper.isValidType(ignoreVersion)) {
ret.add(ignoreVersion);
} else {
getLog().warn("The type attribute '" + ignoreVersion.getType() + "' for global ignoreVersion["
+ ignoreVersion + "] is not valid." + " Please use either '" + TYPE_EXACT + "' or '"
+ TYPE_REGEX
+ ignoreVersion + "] is not valid. Please use one of '" + IgnoreVersionHelper.VALID_TYPES
+ "'.");
} else {
ret.add(ignoreVersion);
}
}

final Rule rule = getBestFitRule(artifact.getGroupId(), artifact.getArtifactId());

if (rule != null) {
for (IgnoreVersion ignoreVersion : rule.getIgnoreVersions()) {
if (!TYPE_EXACT.equals(ignoreVersion.getType()) && !TYPE_REGEX.equals(ignoreVersion.getType())) {
getLog().warn("The type attribute '" + ignoreVersion.getType() + "' for " + rule + " is not valid."
+ " Please use either '" + TYPE_EXACT + "' or '" + TYPE_REGEX + "'.");
} else {
if (IgnoreVersionHelper.isValidType(ignoreVersion)) {
ret.add(ignoreVersion);
} else {
getLog().warn("The type attribute '" + ignoreVersion.getType() + "' for " + rule + " is not valid."
+ " Please use one of '" + IgnoreVersionHelper.VALID_TYPES + "'.");
}
}
}
Expand Down Expand Up @@ -789,7 +769,7 @@ private static RuleSet enrichRuleSet(Collection<String> ignoredVersions, RuleSet
.addAll(ignoredVersions.stream()
.map(v -> {
IgnoreVersion ignoreVersion = new IgnoreVersion();
ignoreVersion.setType(TYPE_REGEX);
ignoreVersion.setType(IgnoreVersion.TYPE_REGEX);
ignoreVersion.setVersion(v);
return ignoreVersion;
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.codehaus.mojo.versions.api;

/*
* Copyright MojoHaus and Contributors
* 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
*
* https://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.
*/

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.regex.Pattern;

import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
import org.apache.maven.artifact.versioning.VersionRange;
import org.codehaus.mojo.versions.model.IgnoreVersion;
import org.codehaus.mojo.versions.utils.DefaultArtifactVersionCache;
import org.eclipse.aether.version.Version;

/**
* Helper class for {@link IgnoreVersion}
*/
public class IgnoreVersionHelper {

static class IgnoreVersionException extends RuntimeException {
IgnoreVersionException(Throwable cause) {
super(cause);
}
}

public static final List<String> VALID_TYPES = Collections.unmodifiableList(
Arrays.asList(IgnoreVersion.TYPE_EXACT, IgnoreVersion.TYPE_REGEX, IgnoreVersion.TYPE_RANGE));

private static final Map<String, BiFunction<Version, IgnoreVersion, Boolean>> VERSION_MATCHERS;

static {
VERSION_MATCHERS = new HashMap<>();
VERSION_MATCHERS.put(IgnoreVersion.TYPE_EXACT, IgnoreVersionHelper::isVersionIgnoredExact);
VERSION_MATCHERS.put(IgnoreVersion.TYPE_REGEX, IgnoreVersionHelper::isVersionIgnoredRegex);
VERSION_MATCHERS.put(IgnoreVersion.TYPE_RANGE, IgnoreVersionHelper::isVersionIgnoredRange);
}

private IgnoreVersionHelper() {}

/**
* Check if type for given ignoredVersion is valid.
*
* @param ignoreVersion an ignored version to check
* @return true if type is valid
*/
public static boolean isValidType(IgnoreVersion ignoreVersion) {
return VALID_TYPES.contains(ignoreVersion.getType());
}

public static boolean isVersionIgnored(Version version, IgnoreVersion ignoreVersion) {
return VERSION_MATCHERS.get(ignoreVersion.getType()).apply(version, ignoreVersion);
}

private static boolean isVersionIgnoredExact(Version version, IgnoreVersion ignoreVersion) {
return ignoreVersion.getVersion().equals(version.toString());
}

private static boolean isVersionIgnoredRegex(Version version, IgnoreVersion ignoreVersion) {
return Pattern.compile(ignoreVersion.getVersion())
.matcher(version.toString())
.matches();
}

private static boolean isVersionIgnoredRange(Version version, IgnoreVersion ignoreVersion) {
try {
ArtifactVersion aVersion = DefaultArtifactVersionCache.of(version.toString());
VersionRange versionRange = VersionRange.createFromVersionSpec(ignoreVersion.getVersion());
if (versionRange.hasRestrictions()) {
return versionRange.containsVersion(aVersion);
} else {
return versionRange.getRecommendedVersion().equals(aVersion);
}
} catch (InvalidVersionSpecificationException e) {
throw new IgnoreVersionException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* Simple cache for {@link org.apache.maven.artifact.versioning.ArtifactVersion}
*/
public class DefaultArtifactVersionCache {
private static final int MAX_CACHE_SIZE = 0x200;
private static final int MAX_CACHE_SIZE = 512;
private static final Map<String, DefaultArtifactVersion> CACHE = new LRUMap<>(MAX_CACHE_SIZE);
private static final ReentrantReadWriteLock CACHE_LOCK = new ReentrantReadWriteLock();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.codehaus.mojo.versions.api;

/*
* Copyright MojoHaus and Contributors
* 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
*
* https://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.
*/

import java.util.stream.Stream;

import org.codehaus.mojo.versions.model.IgnoreVersion;
import org.eclipse.aether.util.version.GenericVersionScheme;
import org.eclipse.aether.version.VersionScheme;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.params.provider.Arguments.of;

class IgnoreVersionHelperTest {

private static final VersionScheme VERSION_SCHEME = new GenericVersionScheme();

static Stream<Arguments> ignoredTypeExact() {
return Stream.of(of("1.0.0", "1.0.0", true), of("2.0.0", "1.0.0", false));
}

@ParameterizedTest
@MethodSource
void ignoredTypeExact(String version, String ignore, boolean expected) throws Exception {

IgnoreVersion ignoreVersion = aIgnoreVersion(ignore, IgnoreVersion.TYPE_EXACT);

assertEquals(
expected, IgnoreVersionHelper.isVersionIgnored(VERSION_SCHEME.parseVersion(version), ignoreVersion));
}

public static Stream<Arguments> ignoredTypeRegex() {
return Stream.of(
of("1.0.0", "1\\.0\\..*", true),
of("1.0.0-SNAPSHOT", ".*-SNAPSHOT", true),
of("1.0.0", "2\\.0\\..*", false));
}

@ParameterizedTest
@MethodSource
void ignoredTypeRegex(String version, String ignore, boolean expected) throws Exception {

IgnoreVersion ignoreVersion = aIgnoreVersion(ignore, IgnoreVersion.TYPE_REGEX);

assertEquals(
expected, IgnoreVersionHelper.isVersionIgnored(VERSION_SCHEME.parseVersion(version), ignoreVersion));
}

public static Stream<Arguments> ignoredTypeRange() {
return Stream.of(
of("1.0.0", "[1.0,)", true),
of("1.0.0", "(,2.0.0]", true),
of("2.2.0", "[1.0,3)", true),
of("2.2.0", "[1.0,2.0)", false),
of("2.2.0", "(,2.0.0]", false),
of("1.0.0", "1.0.0", true),
of("1.0.0", "1.0", true),
of("1.0.1", "1.0", false),
of("1.0.0", "2.0.0", false));
}

@ParameterizedTest
@MethodSource
void ignoredTypeRange(String version, String ignore, boolean expected) throws Exception {

IgnoreVersion ignoreVersion = aIgnoreVersion(ignore, IgnoreVersion.TYPE_RANGE);

assertEquals(
expected, IgnoreVersionHelper.isVersionIgnored(VERSION_SCHEME.parseVersion(version), ignoreVersion));
}

@Test
void invalidRangeShouldThrowException() throws Exception {
IgnoreVersion ignoreVersion = aIgnoreVersion("[1,,", IgnoreVersion.TYPE_RANGE);

assertThrows(
IgnoreVersionHelper.IgnoreVersionException.class,
() -> IgnoreVersionHelper.isVersionIgnored(VERSION_SCHEME.parseVersion("1.0.0"), ignoreVersion));
}

private IgnoreVersion aIgnoreVersion(String version, String type) {
IgnoreVersion ignoreVersion = new IgnoreVersion();
ignoreVersion.setVersion(version);
ignoreVersion.setType(type);
return ignoreVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public class MaxDependencyUpdates extends AbstractEnforcerRule {
* <p>Allows specifying the {@linkplain RuleSet} object describing rules
* on artifact versions to ignore when considering updates.</p>
*
* @see <a href="https://www.mojohaus.org/versions-maven-plugin/version-rules.html#Using_the_ruleSet_element_in_the_POM">
* @see <a href="https://www.mojohaus.org/versions/versions-maven-plugin/version-rules.html#Using_the_ruleSet_element_in_the_POM">
* Using the ruleSet element in the POM</a>
*
* @since 2.14.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
<artifactId>dummy-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>localhost</groupId>
<artifactId>dummy-impl</artifactId>
<version>1.0</version>
</dependency>
</dependencies>

<build>
<pluginManagement>
<plugins>
Expand All @@ -27,6 +33,18 @@
<version>3.0</version>
</ignoreVersion>
</ignoreVersions>
<rules>
<rule>
<groupId>localhost</groupId>
<artifactId>dummy-impl</artifactId>
<ignoreVersions>
<ignoreVersion>
<type>range</type>
<version>[2.0,)</version>
</ignoreVersion>
</ignoreVersions>
</rule>
</rules>
</ruleSet>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
output = new File(basedir, "output1.txt").text
assert ! ( output =~ /\Qlocalhost:dummy-api\E\s*\.*\s*1\.1\s+->\s+3\.0\b/ )
assert output =~ /\Qlocalhost:dummy-api\E\s*\.*\s*1\.1\s+->\s+2\.1\b/
assert output =~ /\Qlocalhost:dummy-impl\E\s*\.*\s*1\.0\s+->\s+1\.4\b/

output = new File(basedir, "output2.txt").text
assert ! ( output =~ /\Qlocalhost:dummy-api\E\s*\.*\s*1\.1\s+->\s+2\.1\b/ )
assert output =~ /\Qlocalhost:dummy-api\E\s*\.*\s*1\.1\s+->\s+2\.0\b/
assert output =~ /\Qlocalhost:dummy-impl\E\s*\.*\s*1\.0\s+->\s+1\.4\b/
Loading

0 comments on commit 7b86752

Please sign in to comment.