Skip to content

Commit

Permalink
[MNG-7122] Require specific Maven compatibility version for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
rfscholte authored and slachiewicz committed Oct 10, 2021
1 parent 4daa48e commit 184db56
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@
import org.eclipse.aether.util.filter.ScopeDependencyFilter;
import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
import org.eclipse.aether.util.graph.selector.AndDependencySelector;
import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
import org.eclipse.aether.util.version.GenericVersionScheme;
import org.eclipse.aether.version.InvalidVersionSpecificationException;
import org.eclipse.aether.version.VersionRange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -76,16 +80,33 @@
public class DefaultPluginDependenciesResolver
implements PluginDependenciesResolver
{
private static final String MAVENCORE_COMPATIBILITY_VERSIONS = "(,)";

This comment has been minimized.

Copy link
@michael-o

michael-o Jan 9, 2022

Member

I don't stand how this should work if all versions are allowed


private static final String REPOSITORY_CONTEXT = "plugin";

private final Logger logger = LoggerFactory.getLogger( getClass() );

private final RepositorySystem repoSystem;

private final VersionRange mavenCompatibilityVersionRange;

@Inject
public DefaultPluginDependenciesResolver( RepositorySystem repoSystem )
{
this.repoSystem = repoSystem;

try
{
// o.a.m.plugins:maven-compiler-plugin:jar:3.1 depends on o.a.m:maven-toolchain:jar:1.0
// maven-its:mng-4666 depends on o.a.m:maven-model:0.1-stub
this.mavenCompatibilityVersionRange =
new GenericVersionScheme().parseVersionRange( MAVENCORE_COMPATIBILITY_VERSIONS );
}
catch ( InvalidVersionSpecificationException e )
{
throw new RuntimeException( e );
}

}

private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
Expand Down Expand Up @@ -182,7 +203,10 @@ private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact,

DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
pluginSession.setDependencySelector( selector );
pluginSession.setDependencyGraphTransformer( session.getDependencyGraphTransformer() );
pluginSession.setDependencyGraphTransformer(
ChainedDependencyGraphTransformer.newInstance(
session.getDependencyGraphTransformer(),
new MavenCompatibilityChecker( mavenCompatibilityVersionRange ) ) );

CollectRequest request = new CollectRequest();
request.setRequestContext( REPOSITORY_CONTEXT );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.apache.maven.plugin.internal;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.eclipse.aether.graph.DependencyNode;

class IncompatibleDependencyException extends Exception
{
private final DependencyNode node;

IncompatibleDependencyException( DependencyNode node )
{
this.node = node;
}

DependencyNode getNode()
{
return node;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.apache.maven.plugin.internal;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import org.eclipse.aether.RepositoryException;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.collection.DependencyGraphTransformationContext;
import org.eclipse.aether.collection.DependencyGraphTransformer;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.version.VersionRange;

/**
* Ensure that Maven core dependencies fit within the versionRange
*
* @since 4.0.0
*/
class MavenCompatibilityChecker implements DependencyGraphTransformer
{
private final VersionRange versionRange;

MavenCompatibilityChecker( VersionRange versionRange )
{
this.versionRange = versionRange;
}

@Override
public DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context )
throws RepositoryException
{
try
{
validateNode( node );
}
catch ( IncompatibleDependencyException e )
{
throw new RepositoryException(
String.format( "%s depends on %s, which does not match the required Maven versionrange of %s",
node.getArtifact(), e.getNode().getArtifact(), versionRange ) );
}

return node;
}

private void validateNode( DependencyNode node )
throws IncompatibleDependencyException
{
if ( isCoreArtifact( node.getArtifact() ) && !versionRange.containsVersion( node.getVersion() ) )
{
throw new IncompatibleDependencyException( node );
}

for ( DependencyNode child : node.getChildren() )
{
validateNode( child );
}
}

private static boolean isCoreArtifact( Artifact artifact )
{
return artifact.getArtifactId().startsWith( "maven-" )
&& artifact.getGroupId().equals( "org.apache.maven" );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.apache.maven.plugin.internal;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.util.Collections;

import org.eclipse.aether.RepositoryException;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.graph.DefaultDependencyNode;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.util.version.GenericVersionScheme;
import org.eclipse.aether.version.VersionScheme;
import org.junit.jupiter.api.Test;

class MavenCompatibilityCheckerTest
{
private final VersionScheme versionScheme = new GenericVersionScheme();

@Test
void compatible() throws Exception
{
MavenCompatibilityChecker checker =
new MavenCompatibilityChecker( versionScheme.parseVersionRange( "[3.0,)" ) );

Artifact pluginArtifact = new DefaultArtifact( "o.a.m.p:plugin:1.0" );
Dependency plugin = new Dependency( pluginArtifact, "compile" );
DefaultDependencyNode node = new DefaultDependencyNode( plugin );
node.setVersion( versionScheme.parseVersion( "1.0" ) );

Artifact coreArtifact = new DefaultArtifact( "org.apache.maven:maven-core:3.0" );
Dependency core = new Dependency( coreArtifact, "compile" );
DefaultDependencyNode coreNode = new DefaultDependencyNode( core );
coreNode.setVersion( versionScheme.parseVersion( "3.0" ) );

node.setChildren(Collections.singletonList( coreNode ) );

assertThat( checker.transformGraph( node, null ), is(node));

This comment has been minimized.

Copy link
@michael-o

michael-o Jan 9, 2022

Member

Missing WS

}

@Test
void incompatible() throws Exception
{
MavenCompatibilityChecker checker =
new MavenCompatibilityChecker( versionScheme.parseVersionRange( "[3.0,)" ) );

Artifact pluginArtifact = new DefaultArtifact( "o.a.m.p:plugin:1.0" );
Dependency plugin = new Dependency( pluginArtifact, "compile" );
DefaultDependencyNode node = new DefaultDependencyNode( plugin );
node.setVersion( versionScheme.parseVersion( "1.0" ) );

Artifact coreArtifact = new DefaultArtifact( "org.apache.maven:maven-core:2.0" );
Dependency core = new Dependency( coreArtifact, "compile" );
DefaultDependencyNode coreNode = new DefaultDependencyNode( core );
coreNode.setVersion( versionScheme.parseVersion( "2.0" ) );

node.setChildren(Collections.singletonList( coreNode ) );

RepositoryException exception = assertThrows( RepositoryException.class, () -> checker.transformGraph( node, null ) );
assertThat( exception.getMessage(), is( "o.a.m.p:plugin:jar:1.0 depends on org.apache.maven:maven-core:jar:2.0, "
+ "which does not match the required Maven versionrange of [3.0,)" ) );
}

}

0 comments on commit 184db56

Please sign in to comment.