Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MENFORCER-458] Move Build-in rules to new API #233

Merged
merged 1 commit into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package org.apache.maven.enforcer.rules;

import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule;
import org.apache.maven.model.InputLocation;
import org.apache.maven.project.MavenProject;

/**
* Abstract help rule.
Expand All @@ -37,4 +39,66 @@ public String getMessage() {
public void setMessage(String message) {
this.message = message;
}

/**
* Returns an identifier of a given project.
* @param project the project
* @return the identifier of the project in the format {@code <groupId>:<artifactId>:<version>}
*/
private static String getProjectId(MavenProject project) {
StringBuilder buffer = new StringBuilder(128);

buffer.append(
(project.getGroupId() != null && project.getGroupId().length() > 0)
? project.getGroupId()
: "[unknown-group-id]");
buffer.append(':');
buffer.append(
(project.getArtifactId() != null && project.getArtifactId().length() > 0)
? project.getArtifactId()
: "[unknown-artifact-id]");
buffer.append(':');
buffer.append(
(project.getVersion() != null && project.getVersion().length() > 0)
? project.getVersion()
: "[unknown-version]");

return buffer.toString();
}

/**
* Creates a string with line/column information for problems originating directly from this POM. Inspired by
* {@code o.a.m.model.building.ModelProblemUtils.formatLocation(...)}.
*
* @param project the current project.
* @param location The location which should be formatted, must not be {@code null}.
* @return The formatted problem location or an empty string if unknown, never {@code null}.
*/
protected static String formatLocation(MavenProject project, InputLocation location) {
StringBuilder buffer = new StringBuilder();

if (!location.getSource().getModelId().equals(getProjectId(project))) {
buffer.append(location.getSource().getModelId());

if (location.getSource().getLocation().length() > 0) {
if (buffer.length() > 0) {
buffer.append(", ");
}
buffer.append(location.getSource().getLocation());
}
}
if (location.getLineNumber() > 0) {
if (buffer.length() > 0) {
buffer.append(", ");
}
buffer.append("line ").append(location.getLineNumber());
}
if (location.getColumnNumber() > 0) {
if (buffer.length() > 0) {
buffer.append(", ");
}
buffer.append("column ").append(location.getColumnNumber());
}
return buffer.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ public void execute() throws EnforcerRuleException {

@Override
public String toString() {
return String.format("AlwaysFail[level=%s, message=%s]", getLevel(), getMessage());
return String.format("AlwaysFail[message=%s]", getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ public void execute() {

@Override
public String toString() {
return String.format("AlwaysPass[level=%s, message=%s]", getLevel(), getMessage());
return String.format("AlwaysPass[message=%s]", getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,28 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.plugins.enforcer;
package org.apache.maven.enforcer.rules;

import javax.inject.Inject;
import javax.inject.Named;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

import org.apache.maven.enforcer.rule.api.EnforcerRule2;
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.apache.maven.enforcer.rules.utils.ArtifactMatcher;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;

/**
* This rule bans all scope values except for {@code import} from dependencies within the dependency management.
* There is a configuration option to ignore certain dependencies in this check.
*/
public class BanDependencyManagementScope extends AbstractNonCacheableEnforcerRule implements EnforcerRule2 {
@Named("banDependencyManagementScope")
public final class BanDependencyManagementScope extends AbstractStandardEnforcerRule {

/**
* Specify the dependencies that will be ignored. This can be a list of artifacts in the format
Expand All @@ -54,40 +55,37 @@ public class BanDependencyManagementScope extends AbstractNonCacheableEnforcerRu
*/
private boolean checkEffectivePom = false;

private final MavenProject project;

@Inject
public BanDependencyManagementScope(MavenProject project) {
this.project = Objects.requireNonNull(project);
}

@Override
public void execute(EnforcerRuleHelper helper) throws EnforcerRuleException {
Log logger = helper.getLog();
MavenProject project;
try {
project = (MavenProject) helper.evaluate("${project}");
if (project == null) {
throw new EnforcerRuleException("${project} is null");
}
// only evaluate local depMgmt, without taking into account inheritance and interpolation
DependencyManagement depMgmt = checkEffectivePom
? project.getModel().getDependencyManagement()
: project.getOriginalModel().getDependencyManagement();
if (depMgmt != null && depMgmt.getDependencies() != null) {
List<Dependency> violatingDependencies = getViolatingDependencies(logger, depMgmt);
if (!violatingDependencies.isEmpty()) {
String message = getMessage();
StringBuilder buf = new StringBuilder();
if (message == null) {
message = "Scope other than 'import' is not allowed in 'dependencyManagement'";
}
buf.append(message + System.lineSeparator());
for (Dependency violatingDependency : violatingDependencies) {
buf.append(getErrorMessage(project, violatingDependency));
}
throw new EnforcerRuleException(buf.toString());
public void execute() throws EnforcerRuleException {
// only evaluate local depMgmt, without taking into account inheritance and interpolation
DependencyManagement depMgmt = checkEffectivePom
? project.getModel().getDependencyManagement()
: project.getOriginalModel().getDependencyManagement();
if (depMgmt != null && depMgmt.getDependencies() != null) {
List<Dependency> violatingDependencies = getViolatingDependencies(depMgmt);
if (!violatingDependencies.isEmpty()) {
String message = getMessage();
StringBuilder buf = new StringBuilder();
if (message == null) {
message = "Scope other than 'import' is not allowed in 'dependencyManagement'";
}
buf.append(message + System.lineSeparator());
for (Dependency violatingDependency : violatingDependencies) {
buf.append(getErrorMessage(project, violatingDependency));
}
throw new EnforcerRuleException(buf.toString());
}
} catch (ExpressionEvaluationException e) {
throw new EnforcerRuleException("Cannot resolve expression: " + e.getCause(), e);
}
}

protected List<Dependency> getViolatingDependencies(Log logger, DependencyManagement depMgmt) {
protected List<Dependency> getViolatingDependencies(DependencyManagement depMgmt) {
final ArtifactMatcher excludesMatcher;
if (excludes != null) {
excludesMatcher = new ArtifactMatcher(excludes, Collections.emptyList());
Expand All @@ -98,7 +96,8 @@ protected List<Dependency> getViolatingDependencies(Log logger, DependencyManage
for (Dependency dependency : depMgmt.getDependencies()) {
if (dependency.getScope() != null && !"import".equals(dependency.getScope())) {
if (excludesMatcher != null && excludesMatcher.match(dependency)) {
logger.debug("Skipping excluded dependency " + dependency + " with scope " + dependency.getScope());
getLog().debug("Skipping excluded dependency " + dependency + " with scope "
+ dependency.getScope());
continue;
}
violatingDependencies.add(dependency);
Expand All @@ -118,7 +117,10 @@ public void setExcludes(List<String> theExcludes) {
this.excludes = theExcludes;
}

public void setCheckEffectivePom(boolean checkEffectivePom) {
this.checkEffectivePom = checkEffectivePom;
@Override
public String toString() {
return String.format(
"BanDependencyManagementScope[message=%s, excludes=%s, checkEffectivePom=%b]",
getMessage(), excludes, checkEffectivePom);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* 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.
*/
package org.apache.maven.enforcer.rules;

import javax.inject.Inject;
import javax.inject.Named;

import java.util.Objects;

import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.model.DistributionManagement;
import org.apache.maven.project.MavenProject;

/**
* This rule will check if a pom contains a <code>distributionManagement</code> part. This should be by best practice
* only defined once. It could happen that you like to check the parent as well. This can be activated by using the
* <code>ignoreParent</code> which is by default turned off (<code>true</code>) which means not to check the parent.
*
* @author Karl Heinz Marbaise
* @since 1.4
*/
@Named("banDistributionManagement")
public final class BanDistributionManagement extends AbstractStandardEnforcerRule {

/**
* Allow using a repository entry in the distributionManagement area.
*/
private boolean allowRepository = false;

/**
* Allow snapshotRepository entry in the distributionManagement area.
*/
private boolean allowSnapshotRepository = false;

/**
* Allow site entry in the distributionManagement area.
*/
private boolean allowSite = false;

private final MavenProject project;

@Inject
public BanDistributionManagement(MavenProject project) {
this.project = Objects.requireNonNull(project);
}

@Override
public void execute() throws EnforcerRuleException {

if (project.isExecutionRoot()) {
if (project.getParent() == null) {
// Does it make sense to check something? If yes please make a JIRA ticket for it.
getLog().debug("We have no parent and in the root of a build we don't check anything,");
getLog().debug("because that is the location where we defined maven-enforcer-plugin.");
} else {
getLog().debug("We are in the root of the execution and we have a parent.");

DistributionManagementCheck check = new DistributionManagementCheck(project);
check.execute(isAllowRepository(), isAllowSnapshotRepository(), isAllowSite());
}
} else {
getLog().debug("We are in a deeper level.");
DistributionManagementCheck check = new DistributionManagementCheck(project);
check.execute(isAllowRepository(), isAllowSnapshotRepository(), isAllowSite());
}
}

public boolean isAllowRepository() {
return allowRepository;
}

public void setAllowRepository(boolean allowRepository) {
this.allowRepository = allowRepository;
}

public boolean isAllowSnapshotRepository() {
return allowSnapshotRepository;
}

public void setAllowSnapshotRepository(boolean allowSnapshotRepository) {
this.allowSnapshotRepository = allowSnapshotRepository;
}

public boolean isAllowSite() {
return allowSite;
}

public void setAllowSite(boolean allowSite) {
this.allowSite = allowSite;
}

private static class DistributionManagementCheck {
private DistributionManagement distributionManagement;

DistributionManagementCheck(MavenProject project) {
this.distributionManagement = project.getOriginalModel().getDistributionManagement();
}

public void execute(boolean isAllowRepository, boolean isAllowSnapshotRepository, boolean isAllowSite)
throws EnforcerRuleException {
if (hasDistributionManagement()) {
if (!isAllowRepository && hasRepository()) {
throw new EnforcerRuleException("You have defined a repository in distributionManagement.");
} else if (!isAllowSnapshotRepository && hasSnapshotRepository()) {
throw new EnforcerRuleException("You have defined a snapshotRepository in distributionManagement.");
} else if (!isAllowSite && hasSite()) {
throw new EnforcerRuleException("You have defined a site in distributionManagement.");
}
}
}

private boolean hasRepository() {
return getDistributionManagement().getRepository() != null;
}

public DistributionManagement getDistributionManagement() {
return distributionManagement;
}

public void setDistributionManagement(DistributionManagement distributionManagement) {
this.distributionManagement = distributionManagement;
}

private boolean hasSnapshotRepository() {
return getDistributionManagement().getSnapshotRepository() != null;
}

private boolean hasSite() {
return getDistributionManagement().getSite() != null;
}

private boolean hasDistributionManagement() {
return getDistributionManagement() != null;
}
}

@Override
public String toString() {
return String.format(
"BanDistributionManagement[allowRepository=%b, allowSnapshotRepository=%b, allowSite=%b]",
allowRepository, allowSnapshotRepository, allowSite);
}
}
Loading