You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@creadur.apache.org by po...@apache.org on 2023/12/05 12:23:53 UTC
(creadur-rat) branch master updated: RAT-335: Improve the parsing of gitignore files.
This is an automated email from the ASF dual-hosted git repository.
pottlinger pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/creadur-rat.git
The following commit(s) were added to refs/heads/master by this push:
new ddb409a8 RAT-335: Improve the parsing of gitignore files.
new 4286326b Merge pull request #167 from nielsbasjes/RAT-335-GitIgnore
ddb409a8 is described below
commit ddb409a8d783518ac58c98e5b57a7b8b50083aa0
Author: Niels Basjes <ni...@basjes.nl>
AuthorDate: Fri Nov 24 23:09:59 2023 +0100
RAT-335: Improve the parsing of gitignore files.
---
apache-rat-plugin/pom.xml | 13 +++
.../java/org/apache/rat/mp/AbstractRatMojo.java | 93 +++++++++++++++-------
.../org/apache/rat/mp/util/ExclusionHelper.java | 29 ++++---
.../org/apache/rat/mp/util/ScmIgnoreParser.java | 87 +++++---------------
.../rat/mp/util/ignore/GitIgnoreMatcher.java | 56 +++++++++++++
.../GlobIgnoreMatcher.java} | 90 ++++++++++++---------
.../apache/rat/mp/util/ignore/IgnoreMatcher.java | 37 +++++++++
.../mp/util/ignore/IgnoringDirectoryScanner.java | 74 +++++++++++++++++
.../java/org/apache/rat/mp/RatCheckMojoTest.java | 40 ++++++++++
.../apache/rat/mp/util/ExclusionHelperTest.java | 24 +++---
.../apache/rat/mp/util/ScmIgnoreParserTest.java | 10 ++-
.../resources/unit/RAT-335-GitIgnore/.gitignore | 7 ++
.../resources/unit/RAT-335-GitIgnore/README.txt | 12 +++
.../unit/RAT-335-GitIgnore/dir1/.gitignore | 3 +
.../resources/unit/RAT-335-GitIgnore/dir1/dir1.md | 1 +
.../resources/unit/RAT-335-GitIgnore/dir1/dir1.txt | 1 +
.../unit/RAT-335-GitIgnore/dir1/file1.log | 1 +
.../resources/unit/RAT-335-GitIgnore/dir2/dir2.md | 1 +
.../resources/unit/RAT-335-GitIgnore/dir2/dir2.txt | 1 +
.../resources/unit/RAT-335-GitIgnore/dir3/dir3.log | 1 +
.../unit/RAT-335-GitIgnore/dir3/file3.log | 1 +
.../unit/RAT-335-GitIgnore/invoker.properties | 16 ++++
.../test/resources/unit/RAT-335-GitIgnore/pom.xml | 47 +++++++++++
.../test/resources/unit/RAT-335-GitIgnore/root.md | 1 +
pom.xml | 4 +
25 files changed, 492 insertions(+), 158 deletions(-)
diff --git a/apache-rat-plugin/pom.xml b/apache-rat-plugin/pom.xml
index f7e07e5c..7d602e72 100644
--- a/apache-rat-plugin/pom.xml
+++ b/apache-rat-plugin/pom.xml
@@ -89,6 +89,8 @@
<exclude>src/test/resources/unit/it2/src.txt</exclude>
<exclude>src/test/resources/unit/it3/src.apt</exclude>
<exclude>src/test/resources/unit/it4/*.html</exclude>
+ <exclude>src/test/resources/unit/RAT-335-GitIgnore/*</exclude>
+ <exclude>src/test/resources/unit/RAT-335-GitIgnore/**/*</exclude>
<exclude>**/*.iml</exclude>
<!-- RAT-171: needs to be added since SCM ignores are only parsed in project root -->
<exclude>**/.bzrignore</exclude>
@@ -287,6 +289,17 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.7.36</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>nl.basjes.gitignore</groupId>
+ <artifactId>gitignore-reader</artifactId>
+ <version>1.2.1</version>
+ </dependency>
</dependencies>
<reporting>
<plugins>
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java
index 11ccd836..89aaa30f 100644
--- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/AbstractRatMojo.java
@@ -38,9 +38,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.SortedSet;
import java.util.function.Consumer;
@@ -53,16 +51,17 @@ import org.apache.maven.project.MavenProject;
import org.apache.rat.ConfigurationException;
import org.apache.rat.Defaults;
import org.apache.rat.ReportConfiguration;
-import org.apache.rat.config.AddLicenseHeaders;
import org.apache.rat.config.SourceCodeManagementSystems;
import org.apache.rat.configuration.Format;
import org.apache.rat.configuration.LicenseReader;
import org.apache.rat.configuration.MatcherReader;
-import org.apache.rat.configuration.MatcherBuilderTracker;
import org.apache.rat.license.ILicense;
import org.apache.rat.license.ILicenseFamily;
import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
import org.apache.rat.mp.util.ScmIgnoreParser;
+import org.apache.rat.mp.util.ignore.GlobIgnoreMatcher;
+import org.apache.rat.mp.util.ignore.IgnoreMatcher;
+import org.apache.rat.mp.util.ignore.IgnoringDirectoryScanner;
import org.apache.rat.report.IReportable;
import org.codehaus.plexus.util.DirectoryScanner;
@@ -335,7 +334,7 @@ public abstract class AbstractRatMojo extends AbstractMojo {
* UndeclaredThrowableExceptions.
*/
private IReportable getReportable() throws MojoExecutionException {
- final DirectoryScanner ds = new DirectoryScanner();
+ final IgnoringDirectoryScanner ds = new IgnoringDirectoryScanner();
ds.setBasedir(basedir);
setExcludes(ds);
setIncludes(ds);
@@ -476,8 +475,8 @@ public abstract class AbstractRatMojo extends AbstractMojo {
return patterns;
}
- private void setExcludes(DirectoryScanner ds) throws MojoExecutionException {
- final List<String> excludeList = mergeDefaultExclusions();
+ private void setExcludes(IgnoringDirectoryScanner ds) throws MojoExecutionException {
+ final List<IgnoreMatcher> ignoreMatchers = mergeDefaultExclusions();
if (excludes == null || excludes.length == 0) {
getLog().debug("No excludes explicitly specified.");
} else {
@@ -486,47 +485,77 @@ public abstract class AbstractRatMojo extends AbstractMojo {
getLog().debug("Exclude: " + exclude);
}
}
+
+ final List<String> globExcludes = new ArrayList<>();
+ for (IgnoreMatcher ignoreMatcher : ignoreMatchers) {
+ if (ignoreMatcher instanceof GlobIgnoreMatcher) {
+ // The glob matching we do via the DirectoryScanner
+ globExcludes.addAll(((GlobIgnoreMatcher) ignoreMatcher).getExclusionLines());
+ } else {
+ // All others (git) are used directly
+ ds.addIgnoreMatcher(ignoreMatcher);
+ }
+ }
+
if (excludes != null) {
- Collections.addAll(excludeList, excludes);
+ Collections.addAll(globExcludes, excludes);
}
- if (!excludeList.isEmpty()) {
- final String[] allExcludes = excludeList.toArray(new String[excludeList.size()]);
+ if (!globExcludes.isEmpty()) {
+ final String[] allExcludes = globExcludes.toArray(new String[globExcludes.size()]);
ds.setExcludes(allExcludes);
}
}
- private List<String> mergeDefaultExclusions() throws MojoExecutionException {
- final Set<String> results = new HashSet<>();
+ private List<IgnoreMatcher> mergeDefaultExclusions() throws MojoExecutionException {
+ List<IgnoreMatcher> ignoreMatchers = new ArrayList<>();
+
+ final GlobIgnoreMatcher basicRules = new GlobIgnoreMatcher();
- addPlexusAndScmDefaults(getLog(), useDefaultExcludes, results);
- addMavenDefaults(getLog(), useMavenDefaultExcludes, results);
- addEclipseDefaults(getLog(), useEclipseDefaultExcludes, results);
- addIdeaDefaults(getLog(), useIdeaDefaultExcludes, results);
+ basicRules.addRules(addPlexusAndScmDefaults(getLog(), useDefaultExcludes));
+ basicRules.addRules(addMavenDefaults(getLog(), useMavenDefaultExcludes));
+ basicRules.addRules(addEclipseDefaults(getLog(), useEclipseDefaultExcludes));
+ basicRules.addRules(addIdeaDefaults(getLog(), useIdeaDefaultExcludes));
if (parseSCMIgnoresAsExcludes) {
getLog().debug("Will parse SCM ignores for exclusions...");
- results.addAll(ScmIgnoreParser.getExclusionsFromSCM(getLog(), project.getBasedir()));
+ ignoreMatchers.addAll(ScmIgnoreParser.getExclusionsFromSCM(getLog(), project.getBasedir()));
getLog().debug("Finished adding exclusions from SCM ignore files.");
}
if (excludeSubProjects && project != null && project.getModules() != null) {
- for (final Object o : project.getModules()) {
- final String moduleSubPath = (String) o;
+ for (final String moduleSubPath : project.getModules()) {
if (new File(basedir, moduleSubPath).isDirectory()) {
- results.add(moduleSubPath + "/**/*");
+ basicRules.addRule(moduleSubPath + "/**/*");
} else {
- results.add(StringUtils.substringBeforeLast(moduleSubPath, "/") + "/**/*");
+ basicRules.addRule(StringUtils.substringBeforeLast(moduleSubPath, "/") + "/**/*");
}
}
}
- getLog().debug("Finished creating list of implicit excludes.");
- if (results.isEmpty()) {
- getLog().debug("No excludes implicitly specified.");
- } else {
- getLog().debug(results.size() + " implicit excludes.");
- for (final String exclude : results) {
- getLog().debug("Implicit exclude: " + exclude);
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Finished creating list of implicit excludes.");
+ if (basicRules.getExclusionLines().isEmpty() && ignoreMatchers.isEmpty()) {
+ getLog().debug("No excludes implicitly specified.");
+ } else {
+ if (!basicRules.getExclusionLines().isEmpty()) {
+ getLog().debug(basicRules.getExclusionLines().size() + " implicit excludes.");
+ for (final String exclude : basicRules.getExclusionLines()) {
+ getLog().debug("Implicit exclude: " + exclude);
+ }
+ }
+ for (IgnoreMatcher ignoreMatcher : ignoreMatchers) {
+ if (ignoreMatcher instanceof GlobIgnoreMatcher) {
+ GlobIgnoreMatcher globIgnoreMatcher = (GlobIgnoreMatcher) ignoreMatcher;
+ if (!globIgnoreMatcher.getExclusionLines().isEmpty()) {
+ getLog().debug(globIgnoreMatcher.getExclusionLines().size() + " implicit excludes from SCM.");
+ for (final String exclude : globIgnoreMatcher.getExclusionLines()) {
+ getLog().debug("Implicit exclude: " + exclude);
+ }
+ }
+ } else {
+ getLog().debug("Implicit exclude: \n" + ignoreMatcher);
+ }
+ }
}
}
if (excludesFile != null) {
@@ -539,9 +568,13 @@ public abstract class AbstractRatMojo extends AbstractMojo {
}
final String charset = excludesFileCharset == null ? "UTF8" : excludesFileCharset;
getLog().debug("Loading excludes from file " + f + ", using character set " + charset);
- results.addAll(getPatternsFromFile(f, charset));
+ basicRules.addRules(getPatternsFromFile(f, charset));
+ }
+
+ if (!basicRules.isEmpty()) {
+ ignoreMatchers.add(basicRules);
}
- return new ArrayList<>(results);
+ return ignoreMatchers;
}
}
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ExclusionHelper.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ExclusionHelper.java
index 0ab75e90..8558e16b 100644
--- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ExclusionHelper.java
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ExclusionHelper.java
@@ -2,13 +2,17 @@ package org.apache.rat.mp.util;
import org.apache.maven.plugin.logging.Log;
import org.apache.rat.config.SourceCodeManagementSystems;
+import org.codehaus.plexus.util.AbstractScanner;
import org.codehaus.plexus.util.DirectoryScanner;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import static org.codehaus.plexus.util.AbstractScanner.DEFAULTEXCLUDES;
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -68,22 +72,22 @@ public final class ExclusionHelper {
"*.iws", //
".idea/**/*"));
- public static void addPlexusAndScmDefaults(Log log, final boolean useDefaultExcludes,
- final Set<String> excludeList1) {
+ public static Set<String> addPlexusAndScmDefaults(Log log, final boolean useDefaultExcludes) {
+ Set<String> excludeList = new HashSet<>();
if (useDefaultExcludes) {
log.debug("Adding plexus default exclusions...");
- Collections.addAll(excludeList1, DirectoryScanner.DEFAULTEXCLUDES);
+ Collections.addAll(excludeList, DEFAULTEXCLUDES);
log.debug("Adding SCM default exclusions...");
- excludeList1.addAll(//
- SourceCodeManagementSystems.getPluginExclusions());
+ excludeList.addAll(SourceCodeManagementSystems.getPluginExclusions());
} else {
log.debug("rat.useDefaultExcludes set to false. "
+ "Plexus and SCM default exclusions will not be added");
}
+ return excludeList;
}
- public static void addMavenDefaults(Log log, boolean useMavenDefaultExcludes,
- final Set<String> excludeList) {
+ public static Set<String> addMavenDefaults(Log log, boolean useMavenDefaultExcludes) {
+ Set<String> excludeList = new HashSet<>();
if (useMavenDefaultExcludes) {
log.debug("Adding exclusions often needed by Maven projects...");
excludeList.addAll(MAVEN_DEFAULT_EXCLUDES);
@@ -91,10 +95,11 @@ public final class ExclusionHelper {
log.debug("rat.useMavenDefaultExcludes set to false. "
+ "Exclusions often needed by Maven projects will not be added.");
}
+ return excludeList;
}
- public static void addEclipseDefaults(Log log, boolean useEclipseDefaultExcludes,
- final Set<String> excludeList) {
+ public static Set<String> addEclipseDefaults(Log log, boolean useEclipseDefaultExcludes) {
+ Set<String> excludeList = new HashSet<>();
if (useEclipseDefaultExcludes) {
log.debug("Adding exclusions often needed by projects "
+ "developed in Eclipse...");
@@ -104,10 +109,11 @@ public final class ExclusionHelper {
+ "Exclusions often needed by projects developed in "
+ "Eclipse will not be added.");
}
+ return excludeList;
}
- public static void addIdeaDefaults(Log log, boolean useIdeaDefaultExcludes,
- final Set<String> excludeList) {
+ public static Set<String> addIdeaDefaults(Log log, boolean useIdeaDefaultExcludes) {
+ Set<String> excludeList = new HashSet<>();
if (useIdeaDefaultExcludes) {
log.debug("Adding exclusions often needed by projects "
+ "developed in IDEA...");
@@ -117,6 +123,7 @@ public final class ExclusionHelper {
+ "Exclusions often needed by projects developed in "
+ "IDEA will not be added.");
}
+ return excludeList;
}
}
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java
index a165454f..675a3644 100644
--- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java
@@ -20,16 +20,14 @@ package org.apache.rat.mp.util;
*/
-import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.logging.Log;
import org.apache.rat.config.SourceCodeManagementSystems;
+import org.apache.rat.mp.util.ignore.GitIgnoreMatcher;
+import org.apache.rat.mp.util.ignore.GlobIgnoreMatcher;
+import org.apache.rat.mp.util.ignore.IgnoreMatcher;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -41,41 +39,6 @@ public final class ScmIgnoreParser {
// prevent instantiation of utility class
}
- private static final List<String> COMMENT_PREFIXES = Arrays.asList("#", "##", "//", "/**", "/*");
-
- /**
- * Parses excludes from the given SCM ignore file.
- *
- * @param log Maven log to show output during RAT runs.
- * @param scmIgnore if <code>null</code> or invalid an empty list of exclusions is returned.
- * @return all exclusions (=non-comment lines) from the SCM ignore file.
- */
- public static List<String> getExcludesFromFile(final Log log, final File scmIgnore) {
-
- final List<String> exclusionLines = new ArrayList<>();
-
- if (scmIgnore != null && scmIgnore.exists() && scmIgnore.isFile()) {
- log.debug("Parsing exclusions from " + scmIgnore);
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new FileReader(scmIgnore));
- String line;
- while ((line = reader.readLine()) != null) {
- if (!isComment(line)) {
- exclusionLines.add(line);
- log.debug("Added " + line);
- }
- }
- } catch (final IOException e) {
- log.warn("Cannot parse " + scmIgnore + " for exclusions. Will skip this file.");
- log.debug("Skip parsing " + scmIgnore + " due to " + e.getMessage());
- } finally {
- IOUtils.closeQuietly(reader);
- }
- }
- return exclusionLines;
- }
-
/**
* Parse ignore files from all known SCMs that have ignore files.
*
@@ -83,36 +46,28 @@ public final class ScmIgnoreParser {
* @param baseDir base directory from which to look for SCM ignores.
* @return Exclusions from the SCM ignore files.
*/
- public static List<String> getExclusionsFromSCM(final Log log, final File baseDir) {
- List<String> exclusions = new ArrayList<>();
+ public static List<IgnoreMatcher> getExclusionsFromSCM(final Log log, final File baseDir) {
+ List<IgnoreMatcher> ignoreMatchers = new ArrayList<>();
for (SourceCodeManagementSystems scm : SourceCodeManagementSystems.values()) {
- if (scm.hasIgnoreFile()) {
- exclusions.addAll(getExcludesFromFile(log, new File(baseDir, scm.getIgnoreFile())));
+ switch (scm) {
+ case GIT:
+ GitIgnoreMatcher gitIgnoreMatcher = new GitIgnoreMatcher(log, baseDir);
+ if (!gitIgnoreMatcher.isEmpty()) {
+ ignoreMatchers.add(gitIgnoreMatcher);
+ }
+ break;
+ default:
+ if (scm.hasIgnoreFile()) {
+ GlobIgnoreMatcher ignoreMatcher = new GlobIgnoreMatcher(log, new File(baseDir, scm.getIgnoreFile()));
+ if (!ignoreMatcher.isEmpty()) {
+ ignoreMatchers.add(ignoreMatcher);
+ }
+ }
+ break;
}
}
- return exclusions;
-
+ return ignoreMatchers;
}
- /**
- * Determines whether the given line is a comment or not based on scanning
- * for prefixes
- * {@see COMMENT_PREFIXES}.
- *
- * @param line line to verify.
- * @return <code>true</code> if the given line is a commented out line.
- */
- static boolean isComment(final String line) {
- if (line == null || line.length() <= 0) {
- return false;
- }
- final String trimLine = line.trim();
- for (String prefix : COMMENT_PREFIXES) {
- if (trimLine.startsWith(prefix)) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/GitIgnoreMatcher.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/GitIgnoreMatcher.java
new file mode 100644
index 00000000..844ce90c
--- /dev/null
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/GitIgnoreMatcher.java
@@ -0,0 +1,56 @@
+package org.apache.rat.mp.util.ignore;
+
+/*
+ * 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 nl.basjes.gitignore.GitIgnoreFileSet;
+import org.apache.maven.plugin.logging.Log;
+
+import java.io.File;
+import java.util.Optional;
+
+public class GitIgnoreMatcher implements IgnoreMatcher {
+
+ private final GitIgnoreFileSet gitIgnoreFileSet;
+
+ public GitIgnoreMatcher(final Log log, final File projectBaseDir) {
+ log.debug("Recursively loading .gitignore files in " + projectBaseDir);
+ // This will walk the project tree and load all .gitignore files
+ gitIgnoreFileSet = new GitIgnoreFileSet(projectBaseDir);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return gitIgnoreFileSet.isEmpty();
+ }
+
+ @Override
+ public Optional<Boolean> isIgnoredFile(String filename) {
+ Boolean isIgnoredFile = gitIgnoreFileSet.isIgnoredFile(filename);
+ if (isIgnoredFile == null) {
+ return Optional.empty();
+ }
+ return Optional.of(isIgnoredFile);
+ }
+
+ @Override
+ public String toString() {
+ return "Loaded .gitignore data:\n" + gitIgnoreFileSet;
+ }
+}
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/GlobIgnoreMatcher.java
similarity index 67%
copy from apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java
copy to apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/GlobIgnoreMatcher.java
index a165454f..3df95cd3 100644
--- a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ScmIgnoreParser.java
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/GlobIgnoreMatcher.java
@@ -1,4 +1,4 @@
-package org.apache.rat.mp.util;
+package org.apache.rat.mp.util.ignore;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,10 +19,8 @@ package org.apache.rat.mp.util;
* under the License.
*/
-
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.logging.Log;
-import org.apache.rat.config.SourceCodeManagementSystems;
import java.io.BufferedReader;
import java.io.File;
@@ -30,30 +28,53 @@ import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
+import java.util.Optional;
-/**
- * Helper to parse SCM ignore files to add entries as excludes during RAT runs.
- * Since we log errors it needs to reside inside of the maven plugin.
- */
-public final class ScmIgnoreParser {
- private ScmIgnoreParser() {
- // prevent instantiation of utility class
- }
+public class GlobIgnoreMatcher implements IgnoreMatcher {
+
+ final List<String> exclusionLines = new ArrayList<>();
private static final List<String> COMMENT_PREFIXES = Arrays.asList("#", "##", "//", "/**", "/*");
+ public GlobIgnoreMatcher() {
+ // No rules to load
+ }
+
+ public GlobIgnoreMatcher(final Log log, final File scmIgnore) {
+ loadFile(log, scmIgnore);
+ }
+
+ /**
+ * Add a single rule to the set
+ * @param rule The line that matches some files
+ */
+ public void addRule(final String rule) {
+ if (!exclusionLines.contains(rule)) {
+ exclusionLines.add(rule);
+ }
+ }
+
+ /**
+ * Add a set of rules to the set
+ * @param rules The line that matches some files
+ */
+ public void addRules(final Collection<String> rules) {
+ for (String rule : rules) {
+ if (!exclusionLines.contains(rule)) {
+ exclusionLines.add(rule);
+ }
+ }
+ }
+
/**
* Parses excludes from the given SCM ignore file.
*
* @param log Maven log to show output during RAT runs.
* @param scmIgnore if <code>null</code> or invalid an empty list of exclusions is returned.
- * @return all exclusions (=non-comment lines) from the SCM ignore file.
*/
- public static List<String> getExcludesFromFile(final Log log, final File scmIgnore) {
-
- final List<String> exclusionLines = new ArrayList<>();
-
+ public void loadFile(final Log log, final File scmIgnore) {
if (scmIgnore != null && scmIgnore.exists() && scmIgnore.isFile()) {
log.debug("Parsing exclusions from " + scmIgnore);
BufferedReader reader = null;
@@ -73,25 +94,6 @@ public final class ScmIgnoreParser {
IOUtils.closeQuietly(reader);
}
}
- return exclusionLines;
- }
-
- /**
- * Parse ignore files from all known SCMs that have ignore files.
- *
- * @param log Show information via maven logger.
- * @param baseDir base directory from which to look for SCM ignores.
- * @return Exclusions from the SCM ignore files.
- */
- public static List<String> getExclusionsFromSCM(final Log log, final File baseDir) {
- List<String> exclusions = new ArrayList<>();
- for (SourceCodeManagementSystems scm : SourceCodeManagementSystems.values()) {
- if (scm.hasIgnoreFile()) {
- exclusions.addAll(getExcludesFromFile(log, new File(baseDir, scm.getIgnoreFile())));
- }
- }
- return exclusions;
-
}
/**
@@ -102,7 +104,7 @@ public final class ScmIgnoreParser {
* @param line line to verify.
* @return <code>true</code> if the given line is a commented out line.
*/
- static boolean isComment(final String line) {
+ public static boolean isComment(final String line) {
if (line == null || line.length() <= 0) {
return false;
}
@@ -115,4 +117,20 @@ public final class ScmIgnoreParser {
}
return false;
}
+
+ public List<String> getExclusionLines() {
+ return exclusionLines;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return exclusionLines.isEmpty();
+ }
+
+ @Override
+ public Optional<Boolean> isIgnoredFile(String filename) {
+ // Not used for Glob Rules; using the DirectoryScanner instead
+ // It CAN be moved here if so desired.
+ return Optional.empty() ;
+ }
}
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/IgnoreMatcher.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/IgnoreMatcher.java
new file mode 100644
index 00000000..c1d1f49f
--- /dev/null
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/IgnoreMatcher.java
@@ -0,0 +1,37 @@
+package org.apache.rat.mp.util.ignore;
+
+/*
+ * 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 java.util.Optional;
+
+public interface IgnoreMatcher {
+ /**
+ * Checks if the file matches the stored expressions.
+ * @param filename The filename to be checked
+ * @return empty: not matched, True: must be ignored, False: it must be UNignored
+ */
+ Optional<Boolean> isIgnoredFile(String filename);
+
+ /**
+ * Returns {@code true} if this IgnoreMatcher contains no rules.
+ * @return {@code true} if this IgnoreMatcher contains no rules
+ */
+ boolean isEmpty();
+}
diff --git a/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/IgnoringDirectoryScanner.java b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/IgnoringDirectoryScanner.java
new file mode 100644
index 00000000..d8e340a4
--- /dev/null
+++ b/apache-rat-plugin/src/main/java/org/apache/rat/mp/util/ignore/IgnoringDirectoryScanner.java
@@ -0,0 +1,74 @@
+package org.apache.rat.mp.util.ignore;
+
+/*
+ * 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.codehaus.plexus.util.DirectoryScanner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+
+public class IgnoringDirectoryScanner extends DirectoryScanner {
+
+ public IgnoringDirectoryScanner() {
+ super();
+ }
+
+ List<IgnoreMatcher> ignoreMatcherList = new ArrayList<>();
+
+ public void addIgnoreMatcher(IgnoreMatcher ignoreMatcher) {
+ ignoreMatcherList.add(ignoreMatcher);
+ }
+
+ private boolean matchesAnIgnoreMatcher(String name) {
+ for (IgnoreMatcher ignoreMatcher : ignoreMatcherList) {
+ if (ignoreMatcher.isIgnoredFile(name).orElse(FALSE) == TRUE) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean isExcluded(String name) {
+ if (matchesAnIgnoreMatcher(name)) {
+ return true;
+ }
+ return super.isExcluded(name);
+ }
+
+ @Override
+ protected boolean isExcluded(String name, String[] tokenizedName) {
+ if (matchesAnIgnoreMatcher(name)) {
+ return true;
+ }
+ return super.isExcluded(name, tokenizedName);
+ }
+
+ @Override
+ protected boolean isExcluded(String name, char[][] tokenizedName) {
+ if (matchesAnIgnoreMatcher(name)) {
+ return true;
+ }
+ return super.isExcluded(name, tokenizedName);
+ }
+}
diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java
index d97b6786..bac6a379 100644
--- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java
+++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/RatCheckMojoTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.rat.mp;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.rat.mp.RatTestHelpers.ensureRatReportIsCorrect;
import static org.apache.rat.mp.RatTestHelpers.getSourceDirectory;
import static org.apache.rat.mp.RatTestHelpers.newArtifactFactory;
@@ -23,7 +24,11 @@ import static org.apache.rat.mp.RatTestHelpers.newArtifactRepository;
import static org.apache.rat.mp.RatTestHelpers.newSiteRenderer;
import java.io.File;
+import java.io.FileOutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.io.FileUtils;
import org.apache.rat.ReportConfiguration;
import org.apache.rat.ReportConfigurationTest;
import org.apache.rat.license.ILicenseFamily;
@@ -75,6 +80,7 @@ public class RatCheckMojoTest extends BetterAbstractMojoTestCase {
setVariableValueToObject(mojo, "siteRenderer", newSiteRenderer(getContainer()));
} else if (mojo instanceof RatCheckMojo) {
final File ratTxtFile = new File(buildDirectory, "rat.txt");
+ FileUtils.write(ratTxtFile, "", UTF_8); // Ensure the output file exists and is empty (rerunning the test will append)
setVariableValueToObject(mojo, "reportFile", ratTxtFile);
}
return mojo;
@@ -184,4 +190,38 @@ public class RatCheckMojoTest extends BetterAbstractMojoTestCase {
ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY);
}
+
+ /**
+ * Tests verifying gitignore parsing
+ */
+ public void testRAT335GitIgnore() throws Exception {
+ final RatCheckMojo mojo = newRatCheckMojo("RAT-335-GitIgnore");
+ final File ratTxtFile = getRatTxtFile(mojo);
+ final String dir = getDir(mojo);
+ final String[] expected = {
+ "Notes: 1",
+ "Binaries: 0",
+ "Archives: 0",
+ "Standards: 5$",
+ "Apache Licensed: 2$",
+ "Generated Documents: 0",
+ "^3 Unknown Licenses",
+ " AL +\\Q" + dir + "pom.xml\\E$",
+ "\\Q!????? " + dir + "dir1/dir1.md\\E$",
+ "\\Q!????? " + dir + "dir2/dir2.txt\\E$",
+ "\\Q!????? " + dir + "dir3/file3.log\\E$",
+ "^== File: \\Q" + dir + "dir1/dir1.md\\E$",
+ "^== File: \\Q" + dir + "dir2/dir2.txt\\E$",
+ "^== File: \\Q" + dir + "dir3/file3.log\\E$"
+ };
+ try {
+ mojo.execute();
+ fail("Expected RatCheckException");
+ } catch (RatCheckException e) {
+ final String msg = e.getMessage();
+ assertTrue("report filename was not contained in '" + msg + "'", msg.contains(ratTxtFile.getName()));
+ assertFalse("no null allowed in '" + msg + "'", (msg.toUpperCase().contains("NULL")));
+ ensureRatReportIsCorrect(ratTxtFile, expected, TextUtils.EMPTY);
+ }
+ }
}
diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ExclusionHelperTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ExclusionHelperTest.java
index ff31723b..1af2b9ae 100644
--- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ExclusionHelperTest.java
+++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ExclusionHelperTest.java
@@ -56,33 +56,33 @@ public class ExclusionHelperTest {
@Test
public void testAddingEclipseExclusions() {
final Set<String> exclusion = new HashSet<>();
- addEclipseDefaults(log, false, exclusion);
+ exclusion.addAll(addEclipseDefaults(log, false));
assertTrue(exclusion.isEmpty());
- addEclipseDefaults(log, true, exclusion);
+ exclusion.addAll(addEclipseDefaults(log, true));
assertEquals(5, exclusion.size());
- addEclipseDefaults(log, true, exclusion);
+ exclusion.addAll(addEclipseDefaults(log, true));
assertEquals(5, exclusion.size());
}
@Test
public void testAddingIdeaExclusions() {
final Set<String> exclusion = new HashSet<>();
- addIdeaDefaults(log, false, exclusion);
+ exclusion.addAll(addIdeaDefaults(log, false));
assertTrue(exclusion.isEmpty());
- addIdeaDefaults(log, true, exclusion);
+ exclusion.addAll(addIdeaDefaults(log, true));
assertEquals(4, exclusion.size());
- addIdeaDefaults(log, true, exclusion);
+ exclusion.addAll(addIdeaDefaults(log, true));
assertEquals(4, exclusion.size());
}
@Test
public void testAddingMavenExclusions() {
final Set<String> exclusion = new HashSet<>();
- addMavenDefaults(log, false, exclusion);
+ exclusion.addAll(addMavenDefaults(log, false));
assertTrue(exclusion.isEmpty());
- addMavenDefaults(log, true, exclusion);
+ exclusion.addAll(addMavenDefaults(log, true));
assertEquals(8, exclusion.size());
- addMavenDefaults(log, true, exclusion);
+ exclusion.addAll(addMavenDefaults(log, true));
assertEquals(8, exclusion.size());
}
@@ -91,14 +91,14 @@ public class ExclusionHelperTest {
final int expectedSizeMergedFromPlexusDefaultsAndScm = (37 + SourceCodeManagementSystems.getPluginExclusions().size());
final Set<String> exclusion = new HashSet<>();
- addPlexusAndScmDefaults(log, false, exclusion);
+ exclusion.addAll(addPlexusAndScmDefaults(log, false));
assertTrue(exclusion.isEmpty());
- addPlexusAndScmDefaults(log, true, exclusion);
+ exclusion.addAll(addPlexusAndScmDefaults(log, true));
assertEquals(
"Did you upgrade plexus to get more default excludes?",//
expectedSizeMergedFromPlexusDefaultsAndScm,//
exclusion.size());
- addPlexusAndScmDefaults(log, true, exclusion);
+ exclusion.addAll(addPlexusAndScmDefaults(log, true));
assertEquals(
"Did you upgrade plexus to get more default excludes?",//
expectedSizeMergedFromPlexusDefaultsAndScm,//
diff --git a/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ScmIgnoreParserTest.java b/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ScmIgnoreParserTest.java
index 67846108..342380dc 100644
--- a/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ScmIgnoreParserTest.java
+++ b/apache-rat-plugin/src/test/java/org/apache/rat/mp/util/ScmIgnoreParserTest.java
@@ -18,6 +18,7 @@ package org.apache.rat.mp.util;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.logging.Log;
+import org.apache.rat.mp.util.ignore.GlobIgnoreMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -31,9 +32,8 @@ import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
-import static org.apache.rat.mp.util.ScmIgnoreParser.getExcludesFromFile;
import static org.apache.rat.mp.util.ScmIgnoreParser.getExclusionsFromSCM;
-import static org.apache.rat.mp.util.ScmIgnoreParser.isComment;
+import static org.apache.rat.mp.util.ignore.GlobIgnoreMatcher.isComment;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -67,6 +67,9 @@ public class ScmIgnoreParserTest {
assertTrue(isComment(" /* comment that is */ "));
}
+ public List<String> getExcludesFromFile(final Log log, final File scmIgnore) {
+ return new GlobIgnoreMatcher(log, scmIgnore).getExclusionLines();
+ }
@Test
public void parseFromNonExistingFileOrDirectoryOrNull() {
@@ -77,7 +80,8 @@ public class ScmIgnoreParserTest {
@Test
public void parseFromTargetDirectoryHopefullyWithoutSCMIgnores() {
- assertTrue(getExclusionsFromSCM(log, new File("./target")).isEmpty());
+ // The target directory contains ignore files from other tests
+ assertTrue(getExclusionsFromSCM(log, new File("./target/classes")).isEmpty());
}
@Test
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore
new file mode 100644
index 00000000..8855fa80
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore
@@ -0,0 +1,7 @@
+*.md
+
+# This makes it ignore dir3/dir3.log and dir3/file3.log
+*.log
+
+# This makes it "unignore" dir3/file3.log
+!file*.log
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt
new file mode 100644
index 00000000..8681fb58
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/README.txt
@@ -0,0 +1,12 @@
+Note the output when running in the real commandline version of git
+
+# Files that must be ignored (dropping the gitignore matches outside of this test tree)
+$ git check-ignore --no-index --verbose $(find . -type f|sort) | fgrep 'apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/'
+
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore:2:!dir1.md ./dir1/dir1.md
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore:1:*.txt ./dir1/dir1.txt
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore:3:file1.log ./dir1/file1.log
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore:1:*.md ./dir2/dir2.md
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore:4:*.log ./dir3/dir3.log
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore:7:!file*.log ./dir3/file3.log
+apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/.gitignore:1:*.md ./root.md
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore
new file mode 100644
index 00000000..26fd5c95
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/.gitignore
@@ -0,0 +1,3 @@
+*.txt
+!dir1.md
+file1.log
\ No newline at end of file
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.md
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/dir1.txt
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir1/file1.log
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.md
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir2/dir2.txt
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/dir3.log
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/dir3/file3.log
@@ -0,0 +1 @@
+File without a valid license
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties
new file mode 100644
index 00000000..6e8c3479
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/invoker.properties
@@ -0,0 +1,16 @@
+# 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.
+
+invoker.goals = clean apache-rat:check
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml
new file mode 100644
index 00000000..0ec80739
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.rat.test</groupId>
+ <artifactId>RAT335</artifactId>
+ <version>1.0</version>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <version>@pom.version@</version>
+ <configuration>
+
+ <!-- Minimize the number of active rules to keep the test minimal -->
+ <excludes>
+ <exclude>**/.gitignore</exclude>
+ </excludes>
+ <useDefaultExcludes>false</useDefaultExcludes>
+ <useMavenDefaultExcludes>false</useMavenDefaultExcludes>
+ <useEclipseDefaultExcludes>false</useEclipseDefaultExcludes>
+ <useIdeaDefaultExcludes>false</useIdeaDefaultExcludes>
+
+ <parseSCMIgnoresAsExcludes>true</parseSCMIgnoresAsExcludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md
new file mode 100644
index 00000000..a31cbc89
--- /dev/null
+++ b/apache-rat-plugin/src/test/resources/unit/RAT-335-GitIgnore/root.md
@@ -0,0 +1 @@
+File without a valid license
diff --git a/pom.xml b/pom.xml
index c2d73b0d..ea805ee7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -635,6 +635,10 @@ agnostic home for software distribution comprehension and audit tools.
<name>Claude Warren</name>
<email>claude@apache.org</email>
</contributor>
+ <contributor>
+ <name>Niels Basjes</name>
+ <email>nielsbasjes@apache.org</email>
+ </contributor>
</contributors>
<scm>
<connection>scm:git:https://gitbox.apache.org/repos/asf/creadur-rat.git</connection>