You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2021/05/03 09:49:14 UTC

[jackrabbit-filevault-package-maven-plugin] 01/01: JCRVLT-518 optionally generate CSV report

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/csv-report
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault-package-maven-plugin.git

commit 9d939167483e06f59049b071b601f035b23943f3
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Mon May 3 11:48:55 2021 +0200

    JCRVLT-518 optionally generate CSV report
---
 pom.xml                                            |  5 ++
 .../maven/packaging/AbstractValidateMojo.java      | 92 ++++++++++++----------
 .../maven/packaging/ValidateFilesMojo.java         | 24 +++---
 .../maven/packaging/ValidatePackageMojo.java       | 26 +++---
 .../maven/packaging/ValidationHelper.java          | 56 ++++++++++---
 .../maven/packaging/AbstractValidateMojoTest.java  | 15 ++--
 .../maven/packaging/GenerateMetadataMojoTest.java  |  5 +-
 .../maven/packaging/SimpleEmbeddedTest.java        | 16 ++--
 .../filevault/maven/packaging/VaultMojoTest.java   |  5 +-
 .../maven/packaging/it/DefaultProjectIT.java       |  5 +-
 .../maven/packaging/it/ProjectBuilder.java         | 14 ++--
 11 files changed, 156 insertions(+), 107 deletions(-)

diff --git a/pom.xml b/pom.xml
index a4707cd..07ab4f9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -429,6 +429,11 @@
             <scope>compile</scope>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-csv</artifactId>
+            <version>1.8</version>
+        </dependency>
         <!-- testing -->
         <dependency>
             <groupId>org.hamcrest</groupId>
diff --git a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojo.java b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojo.java
index 236fd76..a8f864d 100644
--- a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojo.java
+++ b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojo.java
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.filevault.maven.packaging;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -26,6 +27,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import org.apache.commons.csv.CSVFormat;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.filevault.maven.packaging.validator.impl.context.DependencyResolver;
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
@@ -154,6 +156,9 @@ public abstract class AbstractValidateMojo extends AbstractMojo {
     @Parameter(property = "vault.package.dependency.to.maven.ga")
     protected Collection<String> mapPackageDependencyToMavenGa;
 
+    @Parameter(property = "vault.validation.csvReportFile")
+    protected File csvReportFile;
+
     @Component
     protected RepositorySystem repositorySystem;
 
@@ -165,8 +170,6 @@ public abstract class AbstractValidateMojo extends AbstractMojo {
 
     protected final ValidationExecutorFactory validationExecutorFactory;
 
-    protected final ValidationHelper validationHelper;
-
     protected DependencyResolver resolver;
     
     /**
@@ -181,7 +184,6 @@ public abstract class AbstractValidateMojo extends AbstractMojo {
     public AbstractValidateMojo() {
         super();
         this.validationExecutorFactory = new ValidationExecutorFactory(this.getClass().getClassLoader());
-        this.validationHelper = new ValidationHelper();
     }
 
     static Map<Dependency, Artifact> resolveMap(Collection<String> mapPackageDependencyToMavenGa) {
@@ -212,49 +214,57 @@ public abstract class AbstractValidateMojo extends AbstractMojo {
         }
         translateLegacyParametersToValidatorParameters();
         final Collection<PackageInfo> resolvedDependencies = new LinkedList<>();
-        if (project != null) {
-            validationHelper.clearPreviousValidationMessages(buildContext, project.getBasedir());
-        }
+        
         // repository structure only defines valid roots
         // https://github.com/apache/jackrabbit-filevault-package-maven-plugin/blob/02a853e64d985f075fe88d19101d7c66d741767f/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/impl/DependencyValidator.java#L51
-        try {
-            Collection<String> validRoots = new LinkedList<>();
-            for (PackageInfo packageInfo : getPackageInfoFromMavenBasedDependencies(repositoryStructurePackages)) {
-                for (PathFilterSet set : packageInfo.getFilter().getFilterSets()) {
-                    validRoots.add(set.getRoot());
-                }
+        try (ValidationHelper validationHelper = new ValidationHelper()) {
+            if (csvReportFile != null) {
+                validationHelper.setCsvFile(csvReportFile, StandardCharsets.UTF_8, CSVFormat.EXCEL);
             }
-            if (!validRoots.isEmpty()) {
-                ValidatorSettings settings = null;
-                if (validatorsSettings != null) {
-                    settings = validatorsSettings.get(AdvancedFilterValidatorFactory.ID);
-                } else {
-                    validatorsSettings = new HashMap<>();
+            if (project != null) {
+                validationHelper.clearPreviousValidationMessages(buildContext, project.getBasedir());
+            }
+            try {
+                Collection<String> validRoots = new LinkedList<>();
+                for (PackageInfo packageInfo : getPackageInfoFromMavenBasedDependencies(repositoryStructurePackages)) {
+                    for (PathFilterSet set : packageInfo.getFilter().getFilterSets()) {
+                        validRoots.add(set.getRoot());
+                    }
                 }
-                if (settings == null) {
-                    settings = new ValidatorSettings();
-                    settings.addOption(AdvancedFilterValidatorFactory.OPTION_VALID_ROOTS, StringUtils.join(validRoots, ","));
-                    validatorsSettings.put(AdvancedFilterValidatorFactory.ID, settings);
-                } else {
-                    String oldValidRoots = settings.getOptions().get(AdvancedFilterValidatorFactory.OPTION_VALID_ROOTS);
-                    settings.addOption(AdvancedFilterValidatorFactory.OPTION_VALID_ROOTS, oldValidRoots + "," + StringUtils.join(validRoots, ","));
+                if (!validRoots.isEmpty()) {
+                    ValidatorSettings settings = null;
+                    if (validatorsSettings != null) {
+                        settings = validatorsSettings.get(AdvancedFilterValidatorFactory.ID);
+                    } else {
+                        validatorsSettings = new HashMap<>();
+                    }
+                    if (settings == null) {
+                        settings = new ValidatorSettings();
+                        settings.addOption(AdvancedFilterValidatorFactory.OPTION_VALID_ROOTS, StringUtils.join(validRoots, ","));
+                        validatorsSettings.put(AdvancedFilterValidatorFactory.ID, settings);
+                    } else {
+                        String oldValidRoots = settings.getOptions().get(AdvancedFilterValidatorFactory.OPTION_VALID_ROOTS);
+                        settings.addOption(AdvancedFilterValidatorFactory.OPTION_VALID_ROOTS, oldValidRoots + "," + StringUtils.join(validRoots, ","));
+                    }
                 }
+            } catch (IOException e) {
+                throw new MojoExecutionException("Could not get meta information for repositoryStructurePackages '"
+                        + StringUtils.join(repositoryStructurePackages, ",") + "': " + e.getMessage(), e);
             }
+            try {
+                resolvedDependencies.addAll(getPackageInfoFromMavenBasedDependencies(dependencies));
+            } catch (IOException e) {
+                throw new MojoExecutionException(
+                        "Could not get meta information for dependencies '" + StringUtils.join(dependencies, ",") + "': " + e.getMessage(),
+                        e);
+            }
+            // resolve mapping map
+            resolver = new DependencyResolver(DefaultRepositoryRequest.getRepositoryRequest(session, project), repositorySystem,
+                    resolutionErrorHandler, resolveMap(mapPackageDependencyToMavenGa), resolvedDependencies);
+            doExecute(validationHelper);
         } catch (IOException e) {
-            throw new MojoExecutionException("Could not get meta information for repositoryStructurePackages '"
-                    + StringUtils.join(repositoryStructurePackages, ",") + "': " + e.getMessage(), e);
-        }
-        try {
-            resolvedDependencies.addAll(getPackageInfoFromMavenBasedDependencies(dependencies));
-        } catch (IOException e) {
-            throw new MojoExecutionException(
-                    "Could not get meta information for dependencies '" + StringUtils.join(dependencies, ",") + "': " + e.getMessage(),
-                    e);
+            throw new MojoExecutionException("Could not create/write to CSV File", e);
         }
-        // resolve mapping map
-        resolver = new DependencyResolver(DefaultRepositoryRequest.getRepositoryRequest(session, project), repositorySystem,
-                resolutionErrorHandler, resolveMap(mapPackageDependencyToMavenGa), resolvedDependencies);
-        doExecute();
     }
 
     private Collection<PackageInfo> getPackageInfoFromMavenBasedDependencies(Collection<MavenBasedPackageDependency> dependencies) throws IOException {
@@ -312,12 +322,12 @@ public abstract class AbstractValidateMojo extends AbstractMojo {
         filterValidatorSettings.addOption(AdvancedFilterValidatorFactory.OPTION_SEVERITY_FOR_ORPHANED_FILTER_RULES, "debug");
     }
     
-    public abstract void doExecute() throws MojoExecutionException, MojoFailureException;
-    
+    public abstract void doExecute(ValidationHelper validationHelper) throws MojoExecutionException, MojoFailureException;
+
     protected Map<String, ValidatorSettings> getValidatorSettingsForPackage(PackageId packageId, boolean isSubPackage) {
         return getValidatorSettingsForPackage(getLog(), validatorsSettings, packageId, isSubPackage);
     }
-        
+
     static Map<String, ValidatorSettings> getValidatorSettingsForPackage(Log log, Map<String, ValidatorSettings> validatorsSettings, PackageId packageId, boolean isSubPackage) {
         Map<String, ValidatorSettings> validatorSettingsById = new HashMap<>();
         if (validatorsSettings == null) {
diff --git a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidateFilesMojo.java b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidateFilesMojo.java
index d2c0190..995602f 100644
--- a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidateFilesMojo.java
+++ b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidateFilesMojo.java
@@ -168,7 +168,7 @@ public class ValidateFilesMojo extends AbstractValidateMojo {
     }
 
     @Override
-    public void doExecute() throws MojoExecutionException, MojoFailureException {
+    public void doExecute(ValidationHelper validationHelper) throws MojoExecutionException, MojoFailureException {
         disableChecksOnlyWorkingForPackages();
         try {
             File metaInfoVaultSourceDirectory = AbstractMetadataPackageMojo.getMetaInfVaultSourceDirectory(metaInfVaultDirectory, getLog());
@@ -185,12 +185,12 @@ public class ValidateFilesMojo extends AbstractValidateMojo {
             }
             validationHelper.printUsedValidators(getLog(), executor, context, true);
             if (metaInfRootDirectory != null) {
-                validateDirectory(executor, metaInfRootDirectory, true);
+                validateDirectory(validationHelper, executor, metaInfRootDirectory, true);
             }
-            validateDirectory(executor, generatedMetaInfRootDirectory, true);
+            validateDirectory(validationHelper, executor, generatedMetaInfRootDirectory, true);
             File jcrSourceDirectory = AbstractSourceAndMetadataPackageMojo.getJcrSourceDirectory(jcrRootSourceDirectory, builtContentDirectory, getLog());
             if (jcrSourceDirectory != null) {
-                validateDirectory(executor, jcrSourceDirectory, false);
+                validateDirectory(validationHelper, executor, jcrSourceDirectory, false);
             }
             validationHelper.printMessages(executor.done(), getLog(), buildContext, project.getBasedir().toPath());
         } catch (IOException | ConfigurationException e) {
@@ -199,7 +199,7 @@ public class ValidateFilesMojo extends AbstractValidateMojo {
         validationHelper.failBuildInCaseOfViolations(failOnValidationWarnings);
     }
 
-    private void validateDirectory(ValidationExecutor executor, File baseDir, boolean isMetaInf) {
+    private void validateDirectory(ValidationHelper validationHelper, ValidationExecutor executor, File baseDir, boolean isMetaInf) {
         Scanner scanner = buildContext.newScanner(baseDir);
         // make sure filtering does work equally as within the package goal
         scanner.setExcludes(excludes);
@@ -209,20 +209,20 @@ public class ValidateFilesMojo extends AbstractValidateMojo {
         List<String> sortedFileNames = Arrays.asList(scanner.getIncludedFiles());
         sortedFileNames.sort(new DotContentXmlFirstComparator());
         for (String fileName : sortedFileNames) {
-            validateFile(executor, baseDir, isMetaInf, fileName);
+            validateFile(validationHelper, executor, baseDir, isMetaInf, fileName);
         }
         for (String relativeFile : scanner.getIncludedDirectories()) {
-            validateFolder(executor, baseDir, isMetaInf, relativeFile);
+            validateFolder(validationHelper, executor, baseDir, isMetaInf, relativeFile);
         }
     }
 
 
-    private void validateFile(ValidationExecutor executor, File baseDir, boolean isMetaInf, String relativeFile) {
+    private void validateFile(ValidationHelper validationHelper, ValidationExecutor executor, File baseDir, boolean isMetaInf, String relativeFile) {
         File absoluteFile = new File(baseDir, relativeFile);
         validationHelper.clearPreviousValidationMessages(buildContext, absoluteFile);
         getLog().debug("Validating file " + getProjectRelativeFilePath(absoluteFile) + "...");
         try (InputStream input = new FileInputStream(absoluteFile)) {
-            validateInputStream(executor, input, baseDir, isMetaInf, relativeFile);
+            validateInputStream(validationHelper, executor, input, baseDir, isMetaInf, relativeFile);
         } catch (FileNotFoundException e) {
             getLog().error("Could not find file " + getProjectRelativeFilePath(absoluteFile), e);
         } catch (IOException e) {
@@ -230,18 +230,18 @@ public class ValidateFilesMojo extends AbstractValidateMojo {
         }
     }
     
-    private void validateFolder(ValidationExecutor executor, File baseDir, boolean isMetaInf, String relativeFile) {
+    private void validateFolder(ValidationHelper validationHelper, ValidationExecutor executor, File baseDir, boolean isMetaInf, String relativeFile) {
         File absoluteFile = new File(baseDir, relativeFile);
         validationHelper.clearPreviousValidationMessages(buildContext, absoluteFile);
         getLog().debug("Validating folder " + getProjectRelativeFilePath(absoluteFile) + "...");
         try {
-            validateInputStream(executor, null, baseDir, isMetaInf, relativeFile);
+            validateInputStream(validationHelper, executor, null, baseDir, isMetaInf, relativeFile);
         } catch (IOException e) {
             getLog().error("Could not validate folder " + getProjectRelativeFilePath(absoluteFile), e);
         }
     }
     
-    private void validateInputStream(ValidationExecutor executor, InputStream input, File baseDir, boolean isMetaInf, String relativeFile) throws IOException {
+    private void validateInputStream(ValidationHelper validationHelper, ValidationExecutor executor, InputStream input, File baseDir, boolean isMetaInf, String relativeFile) throws IOException {
         final Collection<ValidationViolation> messages;
         if (isMetaInf) {
             messages = executor.validateMetaInf(input, Paths.get(relativeFile), baseDir.toPath());
diff --git a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidatePackageMojo.java b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidatePackageMojo.java
index 748e322..f334b99 100644
--- a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidatePackageMojo.java
+++ b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidatePackageMojo.java
@@ -80,18 +80,18 @@ public class ValidatePackageMojo extends AbstractValidateMojo {
     }
 
     @Override
-    public void doExecute() throws MojoExecutionException, MojoFailureException {
+    public void doExecute(ValidationHelper validationHelper) throws MojoExecutionException, MojoFailureException {
         try {
             boolean foundPackage = false;
             if (packageFile != null && !packageFile.isDirectory()) {
-                validatePackage(packageFile);
+                validatePackage(validationHelper, packageFile);
                 foundPackage = true;
             } 
             if (!attachedArtifacts.isEmpty()) {
                 for (Artifact attached : attachedArtifacts) {
                     // validate attached artifacts with given classifiers
                     if (classifiers.contains(attached.getClassifier())) {
-                        validatePackage(attached.getFile());
+                        validatePackage(validationHelper, attached.getFile());
                         foundPackage = true;
                     }
                 }
@@ -105,7 +105,7 @@ public class ValidatePackageMojo extends AbstractValidateMojo {
         }
     }
 
-    private void validatePackage(File file) throws IOException, ParserConfigurationException, SAXException, MojoExecutionException {
+    private void validatePackage(ValidationHelper validationHelper, File file) throws IOException, ParserConfigurationException, SAXException, MojoExecutionException {
         getLog().info("Start validating package " + getProjectRelativeFilePath(file) + "...");
 
         // open file to extract the meta data for the validation context
@@ -117,7 +117,7 @@ public class ValidatePackageMojo extends AbstractValidateMojo {
             executor = validationExecutorFactory.createValidationExecutor(context, false, enforceRecursiveSubpackageValidation, getValidatorSettingsForPackage(context.getProperties().getId(), false));
             if (executor != null) {
                 validationHelper.printUsedValidators(getLog(), executor, context, true);
-                validateArchive(archive, file.toPath(), context, executor);
+                validateArchive(validationHelper, archive, file.toPath(), context, executor);
             } else {
                 throw new MojoExecutionException("No registered validators found!");
             }
@@ -125,13 +125,13 @@ public class ValidatePackageMojo extends AbstractValidateMojo {
         }
     }
 
-    private void validateArchive(Archive archive, Path path, ArchiveValidationContextImpl context,
+    private void validateArchive(ValidationHelper validationHelper, Archive archive, Path path, ArchiveValidationContextImpl context,
             ValidationExecutor executor) throws IOException, SAXException, ParserConfigurationException {
-        validateEntry(archive, archive.getRoot(), Paths.get(""), path, context, executor);
+        validateEntry(validationHelper, archive, archive.getRoot(), Paths.get(""), path, context, executor);
         validationHelper.printMessages(executor.done(), getLog(), buildContext, packageFile.toPath());
     }
 
-    private void validateEntry(Archive archive, Archive.Entry entry, Path entryPath, Path packagePath, ArchiveValidationContextImpl context,
+    private void validateEntry(ValidationHelper validationHelper, Archive archive, Archive.Entry entry, Path entryPath, Path packagePath, ArchiveValidationContextImpl context,
             ValidationExecutor executor) throws IOException, SAXException, ParserConfigurationException {
         // sort children to make sure that .content.xml comes first!
         List<Archive.Entry> sortedEntryList = new ArrayList<Archive.Entry>(entry.getChildren());
@@ -139,17 +139,17 @@ public class ValidatePackageMojo extends AbstractValidateMojo {
         
         for (Archive.Entry childEntry : sortedEntryList) {
             if (childEntry.isDirectory()) {
-                validateInputStream(null, entryPath.resolve(childEntry.getName()), packagePath, context, executor);
-                validateEntry(archive, childEntry, entryPath.resolve(childEntry.getName()), packagePath, context, executor);
+                validateInputStream(validationHelper, null, entryPath.resolve(childEntry.getName()), packagePath, context, executor);
+                validateEntry(validationHelper, archive, childEntry, entryPath.resolve(childEntry.getName()), packagePath, context, executor);
             } else {
                 try (InputStream input = archive.openInputStream(childEntry)) {
-                    validateInputStream(input, entryPath.resolve(childEntry.getName()), packagePath, context, executor);
+                    validateInputStream(validationHelper, input, entryPath.resolve(childEntry.getName()), packagePath, context, executor);
                 }
             }
         }
     }
 
-    private void validateInputStream(@Nullable InputStream inputStream, Path entryPath, Path packagePath, ArchiveValidationContextImpl context,
+    private void validateInputStream(ValidationHelper validationHelper, @Nullable InputStream inputStream, Path entryPath, Path packagePath, ArchiveValidationContextImpl context,
             ValidationExecutor executor) throws IOException, SAXException, ParserConfigurationException {
         Collection<ValidationViolation> messages = new LinkedList<>();
         if (entryPath.startsWith(Constants.META_INF)) {
@@ -171,7 +171,7 @@ public class ValidatePackageMojo extends AbstractValidateMojo {
                         .createValidationExecutor(subPackageValidationContext, true, enforceRecursiveSubpackageValidation, getValidatorSettingsForPackage(subPackageValidationContext.getProperties().getId(), true));
                 if (subPackageValidationExecutor != null) {
                     validationHelper.printUsedValidators(getLog(), executor, subPackageValidationContext, false);
-                    validateArchive(subArchive, subPackagePath, subPackageValidationContext, subPackageValidationExecutor);
+                    validateArchive(validationHelper, subArchive, subPackagePath, subPackageValidationContext, subPackageValidationExecutor);
                 } else {
                     getLog().debug("Skip validating sub package as no validator is interested in it.");
                 }
diff --git a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidationHelper.java b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidationHelper.java
index 7c6f7c9..c7bc96d 100644
--- a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidationHelper.java
+++ b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/ValidationHelper.java
@@ -16,22 +16,31 @@
  */
 package org.apache.jackrabbit.filevault.maven.packaging;
 
+import java.io.Closeable;
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
 import java.nio.file.Path;
+import java.text.MessageFormat;
 import java.util.Collection;
 import java.util.Map;
 
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.vault.validation.ValidationExecutor;
 import org.apache.jackrabbit.vault.validation.ValidationViolation;
 import org.apache.jackrabbit.vault.validation.spi.ValidationContext;
+import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
 import org.apache.jackrabbit.vault.validation.spi.Validator;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.logging.Log;
 import org.sonatype.plexus.build.incremental.BuildContext;
 import org.sonatype.plexus.build.incremental.DefaultBuildContext;
 
-public class ValidationHelper {
+public class ValidationHelper implements Closeable {
 
     /**
      * Set to {@code true} if at least one {@link ValidationViolation} has been given out
@@ -42,6 +51,8 @@ public class ValidationHelper {
      * Set to {@code true} if at least one validation violation with severity {@link ValidationMessageSeverity#ERROR} has been given out
      */
     private int noOfEmittedValidationMessagesWithLevelError = 0;
+    
+    private CSVPrinter csvPrinter = null;
 
     protected ValidationHelper() {
     }
@@ -53,8 +64,9 @@ public class ValidationHelper {
      * @param log
      * @param buildContext
      * @param baseDirectory the directory to which all absolute paths should be made relative (i.e. the Maven basedir)
+     * @throws IOException 
      */
-    public void printMessages(Collection<ValidationViolation> violations, Log log, BuildContext buildContext, Path baseDirectory) {
+    public void printMessages(Collection<ValidationViolation> violations, Log log, BuildContext buildContext, Path baseDirectory) throws IOException {
         for (ValidationViolation violation : violations) {
             final int buildContextSeverity;
                 switch (violation.getSeverity()) {
@@ -83,16 +95,22 @@ public class ValidationHelper {
                         buildContextSeverity = -1;
                         break;
             }
-            // only emit via build context inside eclipse, otherwise log from above is better!
-            if (buildContextSeverity > 0 && !(buildContext instanceof DefaultBuildContext)) {
-                File file;
-                if (violation.getAbsoluteFilePath() != null) {
-                    file = violation.getAbsoluteFilePath().toFile();
-                } else {
-                    // take the base path
-                    file = baseDirectory.toFile();
+               
+            if (buildContextSeverity > 0) {
+                // only emit via build context inside eclipse, otherwise log from above is better!
+                if (!(buildContext instanceof DefaultBuildContext)) {
+                    Path file;
+                    if (violation.getAbsoluteFilePath() != null) {
+                        file = violation.getAbsoluteFilePath();
+                    } else {
+                        // take the base path
+                        file = baseDirectory;
+                    }
+                    buildContext.addMessage(file.toFile(), violation.getLine(), violation.getColumn(), getMessage(violation), buildContextSeverity, violation.getThrowable());
+                }
+                if (!buildContext.isIncremental() && csvPrinter != null) {
+                    printToCsvFile(violation);
                 }
-                buildContext.addMessage(file, violation.getLine(), violation.getColumn(), getMessage(violation), buildContextSeverity, violation.getThrowable());
             }
         }
     }
@@ -160,4 +178,20 @@ public class ValidationHelper {
             throw new MojoFailureException("Found " + noOfEmittedValidationMessagesWithLevelError + " violation(s) (with severity=ERROR). Check above errors for details");
         }
     }
+
+    public void setCsvFile(File csvReportFile, Charset charset, CSVFormat format) throws IOException {
+        csvPrinter = new CSVPrinter(new OutputStreamWriter(new FileOutputStream(csvReportFile), charset), format);
+        csvPrinter.printRecord("Severity", "Validator ID", "Message", "File", "Line:Column", "Node Path");
+    }
+
+    private void printToCsvFile(ValidationViolation violation) throws IOException {
+        csvPrinter.printRecord(violation.getSeverity(), violation.getValidatorId(), violation.getMessage(), violation.getAbsoluteFilePath(), MessageFormat.format("{0}:{1}", violation.getLine(), violation.getColumn()), violation.getNodePath());
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (csvPrinter != null) {
+            csvPrinter.close();
+        }
+    }
 }
diff --git a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojoTest.java b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojoTest.java
index 44c39b0..21063ad 100644
--- a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojoTest.java
+++ b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/AbstractValidateMojoTest.java
@@ -16,8 +16,6 @@
  */
 package org.apache.jackrabbit.filevault.maven.packaging;
 
-import static org.junit.Assert.assertThat;
-
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -28,6 +26,7 @@ import org.apache.jackrabbit.vault.packaging.PackageId;
 import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.artifact.InvalidArtifactRTException;
 import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -36,7 +35,7 @@ public class AbstractValidateMojoTest {
 
     @Test
     public void testValidMapWithIgnoredArtifacts() {
-        Assert.assertThat(AbstractValidateMojo.resolveMap(Arrays.asList("group1:name1=ignore", "group2:name2=groupId2:artifactId2")), 
+        MatcherAssert.assertThat(AbstractValidateMojo.resolveMap(Arrays.asList("group1:name1=ignore", "group2:name2=groupId2:artifactId2")), 
                 Matchers.allOf(
                     Matchers.hasEntry(Dependency.fromString("group1:name1"), AbstractValidateMojo.IGNORE_ARTIFACT),
                     Matchers.hasEntry(Dependency.fromString("group2:name2"), new DefaultArtifact("groupId2", "artifactId2", "", "", "", "", null)),
@@ -45,7 +44,7 @@ public class AbstractValidateMojoTest {
 
     @Test
     public void testValidMap() {
-        Assert.assertThat(AbstractValidateMojo.resolveMap(Arrays.asList("group1:name1=groupId1:artifactId1", "group2:name2=groupId2:artifactId2")), 
+        MatcherAssert.assertThat(AbstractValidateMojo.resolveMap(Arrays.asList("group1:name1=groupId1:artifactId1", "group2:name2=groupId2:artifactId2")), 
                 Matchers.allOf(
                     Matchers.hasEntry(Dependency.fromString("group1:name1"), new DefaultArtifact("groupId1", "artifactId1", "", "", "", "", null)),
                     Matchers.hasEntry(Dependency.fromString("group2:name2"), new DefaultArtifact("groupId2", "artifactId2", "", "", "", "", null)),
@@ -77,21 +76,21 @@ public class AbstractValidateMojoTest {
         Map<String, ValidatorSettings> expectedValidatorSettings = new HashMap<>();
         expectedValidatorSettings.put("id1", new ValidatorSettings().addOption("id1", "foo"));
         expectedValidatorSettings.put("id2", new ValidatorSettings().addOption("id2", "foo"));
-        Assert.assertThat(actualValidatorSettings, Matchers.equalTo(expectedValidatorSettings));
+        MatcherAssert.assertThat(actualValidatorSettings, Matchers.equalTo(expectedValidatorSettings));
         
         actualValidatorSettings = AbstractValidateMojo.getValidatorSettingsForPackage(new SystemStreamLog(), validatorsSettings, PackageId.fromString("mygroup:myname:1.0.0"), true);
         expectedValidatorSettings.put("id3", new ValidatorSettings().addOption("id3", "foo"));
-        Assert.assertThat(actualValidatorSettings, Matchers.equalTo(expectedValidatorSettings));
+        MatcherAssert.assertThat(actualValidatorSettings, Matchers.equalTo(expectedValidatorSettings));
         
         actualValidatorSettings = AbstractValidateMojo.getValidatorSettingsForPackage(new SystemStreamLog(), null, PackageId.fromString("mygroup:myname:1.0.0"), true);
         expectedValidatorSettings.clear();
-        Assert.assertThat(actualValidatorSettings, Matchers.equalTo(expectedValidatorSettings));
+        MatcherAssert.assertThat(actualValidatorSettings, Matchers.equalTo(expectedValidatorSettings));
     }
 
     @Test
     public void testDotContentXmlFirstComparator() {
         List<String> list = Arrays.asList("someEntryA", ".content.xml", "someEntryB", ".content.xml");
         list.sort(new AbstractValidateMojo.DotContentXmlFirstComparator());
-        assertThat(list, Matchers.contains(".content.xml", ".content.xml", "someEntryA", "someEntryB"));
+        MatcherAssert.assertThat(list, Matchers.contains(".content.xml", ".content.xml", "someEntryA", "someEntryB"));
     }
 }
diff --git a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java
index 2355ce9..5b2f0d8 100644
--- a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java
+++ b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java
@@ -38,6 +38,7 @@ import org.apache.jackrabbit.vault.packaging.PackageType;
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.archiver.jar.ManifestException;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -114,11 +115,11 @@ public class GenerateMetadataMojoTest {
                     if (expectedAttributeValuePattern == null) {
                         Assert.fail("Found unexpected attribute " + attribute.getKey() + " in Manifest");
                     }
-                    Assert.assertThat("Found unexpected attribute value for " + attribute.getKey(), (String)attribute.getValue(), Matchers.matchesPattern(expectedAttributeValuePattern));
+                    MatcherAssert.assertThat("Found unexpected attribute value for " + attribute.getKey(), (String)attribute.getValue(), Matchers.matchesPattern(expectedAttributeValuePattern));
                     expectedAttributes.remove(attribute.getKey().toString());
                 }
             }
-            Assert.assertThat("Not found expected attributes in manifest", expectedAttributes, Matchers.anEmptyMap());
+            MatcherAssert.assertThat("Not found expected attributes in manifest", expectedAttributes, Matchers.anEmptyMap());
         } finally {
             outputFile.delete();
         }
diff --git a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/SimpleEmbeddedTest.java b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/SimpleEmbeddedTest.java
index 36b959d..e8ef77e 100644
--- a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/SimpleEmbeddedTest.java
+++ b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/SimpleEmbeddedTest.java
@@ -22,8 +22,8 @@ import java.util.List;
 import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.DefaultArtifact;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -50,19 +50,19 @@ public class SimpleEmbeddedTest {
     @Test
     public void testGroupIdOnlyFilter() throws ConfigurationException {
         embedded.setGroupId("mygroupid");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(0), artifacts.get(1), artifacts.get(4), artifacts.get(5), artifacts.get(6)));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(0), artifacts.get(1), artifacts.get(4), artifacts.get(5), artifacts.get(6)));
     }
 
     @Test
     public void testArtifactIdOnlyFilter() throws ConfigurationException {
         embedded.setArtifactId("artifact1");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(0), artifacts.get(3), artifacts.get(4)));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(0), artifacts.get(3), artifacts.get(4)));
     }
 
     @Test
     public void testTypeBundleOnlyFilter() throws ConfigurationException {
         embedded.setType("bundle");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.contains(artifacts.get(4), artifacts.get(5), artifacts.get(6)));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.contains(artifacts.get(4), artifacts.get(5), artifacts.get(6)));
     }
 
     @Test
@@ -70,21 +70,21 @@ public class SimpleEmbeddedTest {
         // in addition filter for jar
         embedded.setType("jar");
         embedded.setType("bundle");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.toArray()));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.toArray()));
     }
 
     @Test
     public void testClassifierOnlyFilter() throws ConfigurationException {
         // in addition filter for jar
         embedded.setClassifier("myclassifier");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.contains(artifacts.get(6)));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.contains(artifacts.get(6)));
     }
 
     @Test
     public void testScopeOnlyFilter() {
         // should contain all artifacts with scope "compile", "runtime" or "system"
         embedded.setScope("compile");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(0), artifacts.get(1), artifacts.get(5), artifacts.get(6)));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(0), artifacts.get(1), artifacts.get(5), artifacts.get(6)));
     }
 
     @Test
@@ -92,7 +92,7 @@ public class SimpleEmbeddedTest {
         embedded.setType("bundle");
         embedded.setArtifactId("artifact1");
         embedded.setGroupId("mygroupid");
-        Assert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(4)));
+        MatcherAssert.assertThat(embedded.getMatchingArtifacts(artifacts), Matchers.containsInAnyOrder(artifacts.get(4)));
     }
 
     public final static class SimpleArtifact extends DefaultArtifact {
diff --git a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/VaultMojoTest.java b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/VaultMojoTest.java
index 7536fe4..84e7fce 100644
--- a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/VaultMojoTest.java
+++ b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/VaultMojoTest.java
@@ -25,6 +25,7 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.jackrabbit.filevault.maven.packaging.it.ProjectBuilder;
 import org.codehaus.plexus.archiver.util.DefaultFileSet;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -37,7 +38,7 @@ public class VaultMojoTest {
         Set<String> excludes = Collections.emptySet();
         File sourceDirectory = new File(ProjectBuilder.TEST_PROJECTS_ROOT, "filter-tests/filter-not-covering-all-files/jcr_root");
         Collection<File> uncoveredFiles = VaultMojo.getUncoveredFiles(sourceDirectory, excludes, prefix, Collections.emptySet());
-        Assert.assertThat(uncoveredFiles, Matchers.contains(new File(sourceDirectory, "apps/.content.xml")));
+        MatcherAssert.assertThat(uncoveredFiles, Matchers.contains(new File(sourceDirectory, "apps/.content.xml")));
     }
 
     @Test
@@ -46,7 +47,7 @@ public class VaultMojoTest {
         File sourceDirectory = new File(ProjectBuilder.TEST_PROJECTS_ROOT, "filter-tests/filter-not-covering-all-files/jcr_root");
         Set<String> entryNames = Collections.singleton(new File("jcr_root/apps/.content.xml").getPath());
         Collection<File> uncoveredFiles = VaultMojo.getUncoveredFiles(sourceDirectory, excludes, "", entryNames);
-        Assert.assertThat(uncoveredFiles, Matchers.empty());
+        MatcherAssert.assertThat(uncoveredFiles, Matchers.empty());
     }
 
     @Test
diff --git a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/DefaultProjectIT.java b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/DefaultProjectIT.java
index c8c8445..6b385f3 100644
--- a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/DefaultProjectIT.java
+++ b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/DefaultProjectIT.java
@@ -34,6 +34,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.NullOutputStream;
 import org.apache.jackrabbit.util.ISO8601;
 import org.apache.maven.it.VerificationException;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.number.OrderingComparison;
 import org.junit.Assert;
 import org.junit.Test;
@@ -118,8 +119,8 @@ public class DefaultProjectIT {
         Calendar date = ISO8601.parse(createdDate);
         assertNotNull("The created date is not compliant to the ISO8601 profile defined in https://www.w3.org/TR/NOTE-datetime", date);
         // check actual value
-        assertThat(date, OrderingComparison.greaterThan(dateBeforeRun));
-        assertThat(date, OrderingComparison.lessThan(dateAfterRun));
+        MatcherAssert.assertThat(date, OrderingComparison.greaterThan(dateBeforeRun));
+        MatcherAssert.assertThat(date, OrderingComparison.lessThan(dateAfterRun));
     
     }
 
diff --git a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/ProjectBuilder.java b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/ProjectBuilder.java
index f0ab5b3..3a858ce 100644
--- a/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/ProjectBuilder.java
+++ b/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/it/ProjectBuilder.java
@@ -20,7 +20,6 @@ import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -56,12 +55,11 @@ import org.apache.maven.model.Model;
 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
 import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.shared.utils.io.FileUtils;
-import org.apache.maven.shared.utils.io.IOUtil;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.hamcrest.Description;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.hamcrest.TypeSafeMatcher;
-import org.junit.Assert;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -294,7 +292,7 @@ public class ProjectBuilder {
         Properties properties;
         try (ZipFile zip = new ZipFile(testPackageFile)) {
             ZipEntry propertiesFile = zip.getEntry("META-INF/vault/properties.xml");
-            assertThat(propertiesFile, notNullValue());
+            MatcherAssert.assertThat(propertiesFile, notNullValue());
 
             properties = new Properties();
             properties.loadFromXML(zip.getInputStream(propertiesFile));
@@ -362,7 +360,7 @@ public class ProjectBuilder {
             if (entry == null) {
                 fail("Could not find entry with name " + name + " in package " + testPackageFile);
             }
-            Assert.assertThat(entry, new JarEntryMatcher(name, jar, expectedChecksum));
+            MatcherAssert.assertThat(entry, new JarEntryMatcher(name, jar, expectedChecksum));
         }
         return this;
     }
@@ -404,7 +402,7 @@ public class ProjectBuilder {
 
     public ProjectBuilder verifyExpectedFilesOrder() throws IOException {
         List<String> expectedEntriesInOrder= Files.readAllLines(expectedOrderFile.toPath(), StandardCharsets.UTF_8);
-        assertThat("Order of entries within package", pkgZipEntries, Matchers.containsInRelativeOrder(expectedEntriesInOrder.toArray()));
+        MatcherAssert.assertThat("Order of entries within package", pkgZipEntries, Matchers.containsInRelativeOrder(expectedEntriesInOrder.toArray()));
         return this;
     }
 
@@ -415,7 +413,7 @@ public class ProjectBuilder {
         try (ZipFile zip = new ZipFile(testPackageFile)) {
             ZipEntry entry = zip.getEntry("META-INF/vault/filter.xml");
             assertNotNull("package has a filter.xml", entry);
-            String result = IOUtil.toString(zip.getInputStream(entry), "utf-8");
+            String result = IOUtils.toString(zip.getInputStream(entry), StandardCharsets.UTF_8);
             String expected = FileUtils.fileRead(expectedFilterFile);
             assertEquals("filter.xml is correct", normalizeWhitespace(expected), normalizeWhitespace(result));
         }
@@ -452,7 +450,7 @@ public class ProjectBuilder {
                 expectedLogLine = matcher.replaceAll(Matcher.quoteReplacement(placeholderValues[placeholderIndex]));
             }
             // update list
-            assertThat("Could not find the expected log line in the output '" + logTxtFile +"'", actualLogLines, Matchers.hasItem(expectedLogLine));
+            MatcherAssert.assertThat("Could not find the expected log line in the output '" + logTxtFile +"'", actualLogLines, Matchers.hasItem(expectedLogLine));
         }
         // support not and exists
         return this;