com.atlassian.maven.plugin.clover.CloverInstrumentInternalMojo Maven / Gradle / Ivy
package com.atlassian.maven.plugin.clover;
/*
* 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 com.atlassian.clover.ant.groovy.GroovycSupport;
import com.atlassian.clover.cfg.instr.InstrumentationConfig;
import com.atlassian.clover.remote.DistributedConfig;
import com.atlassian.maven.plugin.clover.internal.AbstractCloverInstrumentMojo;
import com.atlassian.maven.plugin.clover.internal.CompilerConfiguration;
import com.atlassian.maven.plugin.clover.internal.instrumentation.MainInstrumenter;
import com.atlassian.maven.plugin.clover.internal.instrumentation.TestInstrumenter;
import com.atlassian.maven.plugin.clover.internal.scanner.LanguageFileExtensionFilter;
import com.atlassian.maven.plugin.clover.internal.scanner.MainSourceScanner;
import com.atlassian.maven.plugin.clover.internal.scanner.TestSourceScanner;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/*
* TRICKY PART HOW JAVA AND GROOVY SOURCE FOLDERS ARE HANDLED
*
* PROBLEM DIMENSIONS:
* #1 language:
* -> java only
* -> java + groovy
* -> groovy only
* #2 source folders:
* -> src/xxx/java
* -> src/xxx/groovy
* -> generated-sources/xxx
* #3 location of java source files:
* -> in src/xxx/java
* -> in src/xxx/groovy - NOT SUPPORTED BY CLOVER (see reasons below)
* #4 location of groovy source files:
* -> src/xxx/java
* -> src/xxx/groovy
* #5 definition of groovy source folders
* -> by , parameters in POM
* -> by add-source, add-test-source goals in build-helper-maven-plugin
* -> by extensions=true option in groovy-eclipse-compiler
* -> not defined at all (but src/xxx/groovy location is then internally added by gmaven or groovy-eclipse-plugin)
* #6 groovy plugins
* -> gmaven
* -> groovy-eclipse-plugin
* #7 instrumentation scope
* -> non-generated sources
* -> all sources
* #8 java/groovy compilation
* -> separated (maven-compiler compiles java, gmaven compiles groovy)
* -> joint compilation (groovy-eclipse-plugin compiles both java and groovy)
* #9 build lifecycle
* -> non-forked (clover:setup)
* -> forked (clover:instrument)
*
* =====================================================================================================================
* 1) includeAllSourceRoots = false, java+groovy in 'src/(main|test)/java'
*
* -> source directories are read from getCompileSourceRoots()
* -> *.java files are instrumented in the source and saved in 'src-(test-)instrumented'
* -> *.groovy are copied "as is" to 'src-(test-)instrumented' too
* -> source roots are overridden:
* 'src/main/java' -> 'src-instrumented'
* 'src/test/java' -> 'src-test-instrumented'
* -> groovyc compiles sources from source roots listed above:
* -> *.java files are already instrumented in the source, compile "as is"
* -> *.groovy files are being instrumented in the AST
*
* =====================================================================================================================
* 1b) includeAllSourceRoots = true, java+groovy in 'src/(main|test)/java', generated sources in
* 'target/generated-(test-)sources'
*
* -> as for case 1) but 'generated-(test-)sources' are instrumented too and stored in 'src-(test-)instrumented'
*
* =====================================================================================================================
* 2) includeAllSourceRoots = false, java in 'src/(main|test)/java', groovy in 'src/(main|test)/(java|groovy)'
*
* -> build-helper-maven-plugin adds 'src/(main|test)/groovy' as extra source root
* -> source directories are read from getCompileSourceRoots()
* -> *.java files are instrumented in the source and saved in 'src-(test-)instrumented'
* -> *.groovy files
* from 'src/(main|test)/java' are copied to 'src-(test-)instrumented'
* from 'src/(main|test)/groovy' are not copied anywhere
* -> source roots are switched:
* 'src/main/java' -> 'src-instrumented'
* 'src/test/java' -> 'src-test-instrumented'
* 'src/main/groovy' -> (unchanged)
* 'src/test/groovy' -> (unchanged)
* -> groovyc compiles sources from all source roots listed above
* -> *.java files are already instrumented in the source, compile "as is"
* -> *.groovy files are instrumented in the AST
*
* =====================================================================================================================
* 2b) includeAllSourceRoots = true, java in 'src/(main|test)/java', groovy in 'src/(main|test)/(java|groovy)',
* generated sources in 'target/generated-(test-)sources
*
* -> as for case 2) but 'generated-(test-)sources' are instrumented too and stored in 'src-(test-)instrumented'
*
* =====================================================================================================================
* 3) includeAllSourceRoots = false, java in 'src/(main|test)/java', groovy in 'src/(main|test)/(java|groovy)'
*
* -> the 'src/(main|test)/groovy' is NOT added as extra source root
* -> so that getCompileSourceRoots() does not return it in the list
* -> groovy-eclipse-plugin will add the 'src/(main|test)/groovy' location internally (typically after the
* clover:setup goal is finished)
* -> source directories are read from getCompileSourceRoots()
* -> GroovyMain/TestSourceScanner contains additional hardcoded location for 'src/(main|test)/groovy'
* -> *.java files are instrumented in the source and saved in 'src-(test-)instrumented'
* -> *.groovy files
* from 'src/(main|test)/java' are copied to 'src-(test-)instrumented'
* from 'src/(main|test)/groovy' are not copied anywhere
* -> source roots are switched:
* 'src/main/java' -> 'src-instrumented'
* 'src/test/java' -> 'src-test-instrumented'
* -> groovyc compiles sources from all source roots listed above
* -> *.java files are already instrumented, compile "as is"
* -> *.groovy files are instrumented in the AST
* -> groovy-eclipse-plugin internally adds 'src/(main|test)/groovy' to the list of source roots
*
* =====================================================================================================================
* 3b) includeAllSourceRoots = true, java in 'src/(main|test)/java', groovy in 'src/(main|test)/(java|groovy)'
* generated sources in 'target/generated-(test-)sources
*
* -> as for case 3) but 'generated-(test-)sources' are instrumented too and stored in 'src-(test-)instrumented'
*
* =====================================================================================================================
* 4) includeAllSourceRoots = false, no java code, groovy in 'src/(main|test)/groovy',
* sourceDirectory/testSourceDirectory are used on POM
*
* -> the 'src/(main|test)/groovy' is added as sourceDirectory and testSourceDirectory
* -> so that getProject().getBuild().getSourceDirectory() returns it
* -> so that getProject().getCompileSourceRoots() returns it
* -> *.groovy files are not copied anywhere
* -> source roots are NOT switched
* -> groovyc compiles sources from original source roots ('src/(main|test)/groovy')
*
* =====================================================================================================================
* 4b) includeAllSourceRoots = true, no java code, groovy in 'src/(main|test)/groovy',
* sourceDirectory/testSourceDirectory are used on POM
*
* -> as for case 4) but 'generated-(test-)sources' are passed to groovyc
*
* =====================================================================================================================
* 5) includeAllSourceRoots = false, java in src/xxx/java, no groovy code, no groovy plugin
*
* -> standard behaviour, 'src/(main|test)/java' is instrumented into 'target/clover/src-(test-)instrumented'
* and compiled
*
* =====================================================================================================================
* 5b) includeAllSourceRoots = true, java in src/xxx/java, no groovy code, no groovy plugin
*
* -> standard behaviour, 'src/(main|test)/java' as well as 'target/generated-(test-)sources' are instrumented
* into 'target/clover/src-(test-)instrumented' and compiled
*/
/**
* Instrument source roots.
* Note 1: Do not call this MOJO directly. It is meant to be called in a custom forked lifecycle by the other
* Clover plugin MOJOs.
* Note 2: We bind this mojo to the "validate" phase so that it executes prior to any other mojos
*
* @goal instrumentInternal
* @phase validate
* @requiresDependencyResolution test
*/
public class CloverInstrumentInternalMojo extends AbstractCloverInstrumentMojo {
public static final String CLOVER_CORE_GROUP_ID = "org.openclover";
public static final String CLOVER_CORE_ARTIFACT_ID = "clover";
/**
* List of all artifacts for this Clover plugin provided by Maven. This is used internally to get a handle on
* the Clover JAR artifact.
* Note: This is passed by Maven and must not be configured by the user.
*
* @parameter expression="${plugin.artifacts}"
* @required
*/
private List pluginArtifacts;
/**
* @parameter expression="${component.org.apache.maven.artifact.factory.ArtifactFactory}"
* @required
* @readonly
*/
private ArtifactFactory artifactFactory;
/**
* Artifact resolver used to find clovered artifacts (artifacts with a clover classifier).
*
* @component role="org.apache.maven.artifact.resolver.ArtifactResolver"
* @required
* @readonly
*/
private ArtifactResolver artifactResolver;
/**
* Local maven repository.
*
* @parameter expression="${localRepository}"
* @required
*/
private ArtifactRepository localRepository;
/**
* Remote repositories used for the project.
*
* @parameter expression="${project.remoteArtifactRepositories}"
*/
protected List repositories;
// HACK: this allows us to reset the source directories to the originals
private static Map originalSrcMap = new HashMap();
private static Map originalSrcTestMap = new HashMap();
public static String getOriginalSrcDir(final String module) {
return originalSrcMap.get(module);
}
public static String getOriginalSrcTestDir(final String module) {
return originalSrcTestMap.get(module);
}
/**
* {@inheritDoc}
*
* @see com.atlassian.maven.plugin.clover.internal.AbstractCloverMojo#execute()
*/
@Override
public void execute() throws MojoExecutionException {
if (skip) {
getLog().info("Skipping clover instrumentation.");
return;
}
super.execute();
configureTestFailureIgnore();
resetSrcDirsOriginal(getProject().getArtifact(), this);
final File outDir = new File(this.cloverOutputDirectory, getSrcName());
final String cloverOutputSourceDirectory = outDir.getPath();
final String cloverOutputTestSourceDirectory = new File(this.cloverOutputDirectory, getSrcTestName()).getPath();
new File(resolveCloverDatabase()).getParentFile().mkdirs();
logArtifacts("before changes");
// Instrument both the main sources and the test sources if the user has configured it
final MainInstrumenter mainInstrumenter = new MainInstrumenter(this, cloverOutputSourceDirectory);
final TestInstrumenter testInstrumenter = new TestInstrumenter(this, cloverOutputTestSourceDirectory);
if (isJavaProject()) {
mainInstrumenter.instrument();
if (this.includesTestSourceRoots) {
testInstrumenter.instrument();
}
}
// add clover.jar to classpath
addCloverDependencyToCompileClasspath();
// deal with '-clover' artifacts in dependencies
swizzleCloverDependencies();
// Modify Maven model so that it points to the new source directories and to the clovered
// artifacts instead of the original values.
final String originalSrcDir = mainInstrumenter.redirectSourceDirectories();
originalSrcMap.put(getProject().getArtifact().getId(), originalSrcDir);
if (this.includesTestSourceRoots) {
final String originalSrcTestDir = testInstrumenter.redirectSourceDirectories();
originalSrcTestMap.put(getProject().getArtifact().getId(), originalSrcTestDir);
}
// add instrumentation of groovy sources
injectGrover(outDir);
redirectOutputDirectories();
redirectArtifact();
logArtifacts("after changes");
}
@Override
protected boolean shouldRedirectArtifacts() {
return true;
}
@Override
protected boolean shouldRedirectOutputDirectories() {
return true;
}
/**
* Sets several properties related with test failures for Surefire, Failsafe, PMD and Checkstyle plugins.
* Thanks to this, the build in default or forked lifecycle can continue and we can generate Clover report
* even in presence of test failures.
*/
private void configureTestFailureIgnore() {
if (setTestFailureIgnore) {
getLog().debug("Configuring testFailureIgnore=true and failOnViolation=false");
final Properties properties = getProject().getProperties();
properties.put("maven.test.failure.ignore", "true"); // surefire and failsafe
properties.put("checkstyle.failOnViolation", "false");
properties.put("pmd.failOnViolation", "false"); // pmd:check
properties.put("cpd.failOnViolation", "false"); // pmd:cpd-check
}
}
/**
* @param outDir - output directory for temporary artifacts
*/
private void injectGrover(final File outDir) {
if (skipGroverJar) {
getLog().info("Generation of Clover Groovy configuration is disabled. No Groovy instrumentation will occur.");
return;
}
// create the groovy config for Clover's ASTTransformer
InstrumentationConfig config = new InstrumentationConfig();
config.setProjectName(this.getProject().getName());
config.setInitstring(this.resolveCloverDatabase());
config.setTmpDir(outDir);
final List includeFiles = calcIncludedFilesForGroovy();
getLog().debug("Clover including the following files for Groovy instrumentation: " + includeFiles);
config.setIncludedFiles(includeFiles);
config.setEnabled(true);
config.setEncoding(getEncoding());
//Don't pass in an instance of DistributedCoverage because it can't be deserialised
//by Grover (ClassNotFoundException within the groovyc compiler)
config.setDistributedConfig(getDistributedCoverage() == null ? null : new DistributedConfig(getDistributedCoverage().getConfigString()));
try {
File groverJar = GroovycSupport.extractGroverJar(this.groverJar, false);
File groverConfigDir = GroovycSupport.newConfigDir(config, new File(getProject().getBuild().getOutputDirectory()));
final Resource groverConfigResource = new Resource();
groverConfigResource.setDirectory(groverConfigDir.getPath());
getProject().addResource(groverConfigResource);
// get the clover artifact, and use the same version number for grover...
Artifact cloverArtifact = findCloverArtifact(this.pluginArtifacts);
// add grover to the compilation classpath
final Artifact groverArtifact = artifactFactory.createBuildArtifact(cloverArtifact.getGroupId(), "grover", cloverArtifact.getVersion(), "jar");
groverArtifact.setFile(groverJar);
groverArtifact.setScope(Artifact.SCOPE_SYSTEM);
addArtifactDependency(groverArtifact);
} catch (IOException e) {
getLog().error("Could not create Clover Groovy configuration file. No Groovy instrumentation will occur. " + e.getMessage(), e);
}
}
/**
* @return List<File>
* @see com.atlassian.maven.plugin.clover.internal.instrumentation.AbstractInstrumenter#instrument()
* @see #redirectOutputDirectories()
* @see Groovy-Eclipse+compiler+plugin+for+Maven
*/
protected List calcIncludedFilesForGroovy() {
final MainSourceScanner groovyMainScanner = new MainSourceScanner(this, getProject().getBuild().getOutputDirectory());
final List mainGroovyFiles = extractIncludes(
groovyMainScanner.getSourceFilesToInstrument(LanguageFileExtensionFilter.GROOVY_LANGUAGE, false));
final TestSourceScanner groovyTestScanner = new TestSourceScanner(this, getProject().getBuild().getOutputDirectory());
final List testGroovyFiles = extractIncludes(
groovyTestScanner.getSourceFilesToInstrument(LanguageFileExtensionFilter.GROOVY_LANGUAGE, false));
// combine lists
final List allSources = new ArrayList(mainGroovyFiles);
allSources.addAll(testGroovyFiles);
return allSources;
}
private ArrayList extractIncludes(final Map srcFiles) {
final ArrayList includeFiles = new ArrayList();
for (final String dirName : srcFiles.keySet()) {
final String[] includes = srcFiles.get(dirName);
for (final String include : includes) {
includeFiles.add(new File(dirName, include));
}
}
return includeFiles;
}
public static void resetSrcDirsOriginal(final Artifact artifact, final CompilerConfiguration config) {
if (originalSrcMap.containsKey(artifact.getId())) {
final String sourceDirectory = originalSrcMap.get(artifact.getId());
MainInstrumenter mainInstrumenter = new MainInstrumenter(config, sourceDirectory);
mainInstrumenter.redirectSourceDirectories();
}
if (originalSrcTestMap.containsKey(artifact.getId())) {
final String testDirectory = originalSrcTestMap.get(artifact.getId());
TestInstrumenter instrumenter = new TestInstrumenter(config, testDirectory);
instrumenter.redirectSourceDirectories();
}
}
protected String getSrcTestName() {
return "src-test";
}
protected String getSrcName() {
return "src";
}
private boolean isJavaProject() {
final ArtifactHandler artifactHandler = getProject().getArtifact().getArtifactHandler();
if (!"java".equals(artifactHandler.getLanguage())) {
getLog().debug("The reported language of this project is " + artifactHandler.getLanguage() + ", attempting to instrument sources anyway.");
}
return true;
}
protected void redirectOutputDirectories() {
if (shouldRedirectOutputDirectories()) {
// Explicitly set the output directory to be the Clover one so that all other plugins executing
// thereafter output files in the Clover output directory and not in the main output directory.
getProject().getBuild().setDirectory(this.cloverOutputDirectory);
// TODO: Ugly hack below. Changing the directory should be enough for changing the values of all other
// properties depending on it!
getProject().getBuild().setOutputDirectory(new File(this.cloverOutputDirectory, "classes").getPath());
getProject().getBuild().setTestOutputDirectory(new File(this.cloverOutputDirectory, "test-classes").getPath());
}
}
/**
* Modify main artifact to add a "clover" classifier to it so that it's not mixed with the main artifact of
* a normal build.
*/
protected void redirectArtifact() {
if (shouldRedirectArtifacts()) {
// Only redirect main artifact for non-pom projects
if (!getProject().getPackaging().equals("pom")) {
Artifact oldArtifact = getProject().getArtifact();
Artifact newArtifact = this.artifactFactory.createArtifactWithClassifier(oldArtifact.getGroupId(),
oldArtifact.getArtifactId(), oldArtifact.getVersion(), oldArtifact.getType(), "clover");
getProject().setArtifact(newArtifact);
final String finalName =
getProject().getBuild().getFinalName() == null ?
(getProject().getArtifactId() + "-" + getProject().getVersion())
: getProject().getBuild().getFinalName();
getProject().getBuild().setFinalName(finalName + (useCloverClassifier ? "-clover" : ""));
}
}
}
/**
* Browse through all project dependencies and try to find a clovered version of the dependency. If found
* replace the main depedencency by the clovered version.
*/
private void swizzleCloverDependencies() {
final Set swizzledDependencyArtifacts = swizzleCloverDependencies(getProject().getDependencyArtifacts());
// only swizzle the difference between artifacts and dependency artifacts to ensure no dupes
final Set artifacts = getProject().getArtifacts();
final Set dependencyArtifacts = getProject().getDependencyArtifacts();
artifacts.removeAll(dependencyArtifacts);
final Set swizzledArtifacts = swizzleCloverDependencies(artifacts);
swizzledArtifacts.addAll(swizzledDependencyArtifacts);
getProject().setDependencyArtifacts(swizzledDependencyArtifacts);
getProject().setArtifacts(swizzledArtifacts);
}
protected Set swizzleCloverDependencies(final Set artifacts) {
Set resolvedArtifacts = new LinkedHashSet();
for (Artifact artifact : artifacts) {
// Do not try to find Clovered versions for artifacts with classifiers. This is because Maven only
// supports a single classifier per artifact and thus if we replace the original classifier with
// a Clover classifier the artifact will fail to perform properly as intended originally. This is a
// limitation.
if (artifact.getClassifier() == null) {
Artifact cloveredArtifact = this.artifactFactory.createArtifactWithClassifier(artifact.getGroupId(),
artifact.getArtifactId(), artifact.getVersion(), artifact.getType(), "clover");
// Try to resolve the artifact with a clover classifier. If it doesn't exist, simply add the original
// artifact. If found, use the clovered artifact.
try {
this.artifactResolver.resolve(cloveredArtifact, new ArrayList(), localRepository);
// Set the same scope as the main artifact as this is not set by createArtifactWithClassifier.
cloveredArtifact.setScope(artifact.getScope());
// Check the timestamp of the artifact. If the found clovered version is older than the
// non-clovered one we need to use the non-clovered version. This is to handle use case such as:
// - Say you have a module B that depends on a module A
// - You run Clover on A
// - You make modifications on A such that B would fail if not built with the latest version of A
// - You try to run the Clover plugin on B. The build would fail if we didn't pick the latest
// version between the original A version and the clovered version.
//
// We provide a 'fudge-factor' of 2 seconds, as the clover artifact is created first.
if (cloveredArtifact.getFile().lastModified() + cloveredArtifactExpiryInMillis < artifact.getFile().lastModified()) {
getLog().warn("Using [" + artifact.getId() + "], built on " + new Date(artifact.getFile().lastModified()) +
" even though a Clovered version exists "
+ "but it's older (lastModified: " + new Date(cloveredArtifact.getFile().lastModified())
+ " ) and could fail the build. Please consider running Clover again on that "
+ "dependency's project.");
resolvedArtifacts.add(artifact);
} else {
resolvedArtifacts.add(cloveredArtifact);
}
} catch (ArtifactResolutionException e) {
getLog().warn("Skipped dependency [" + artifact.getId() + "] due to resolution error: " + e.getMessage());
resolvedArtifacts.add(artifact);
} catch (ArtifactNotFoundException e) {
getLog().debug("Skipped dependency [" + artifact.getId() + "] as the clovered artifact could not be found");
resolvedArtifacts.add(artifact);
}
} else {
getLog().debug("Skipped dependency [" + artifact.getId() + "] as it has a classifier");
resolvedArtifacts.add(artifact);
}
}
return resolvedArtifacts;
}
protected Artifact findCloverArtifact(final List pluginArtifacts) {
Artifact cloverArtifact = null;
Iterator artifactsIterator = pluginArtifacts.iterator();
while (artifactsIterator.hasNext() && cloverArtifact == null) {
Artifact artifact = artifactsIterator.next();
// We identify the clover JAR by checking the groupId and artifactId.
if (CLOVER_CORE_GROUP_ID.equals(artifact.getGroupId())
&& CLOVER_CORE_ARTIFACT_ID.equals(artifact.getArtifactId())) {
cloverArtifact = artifact;
}
}
return cloverArtifact;
}
private void addCloverDependencyToCompileClasspath()
throws MojoExecutionException {
Artifact cloverArtifact = findCloverArtifact(this.pluginArtifacts);
if (cloverArtifact == null) {
throw new MojoExecutionException(
"Couldn't find [" + CLOVER_CORE_GROUP_ID + ":" + CLOVER_CORE_ARTIFACT_ID + "] artifact in plugin dependencies");
}
final String jarScope = scope == null ? Artifact.SCOPE_PROVIDED : scope;
cloverArtifact = artifactFactory.createArtifact(cloverArtifact.getGroupId(), cloverArtifact.getArtifactId(),
cloverArtifact.getVersion(), jarScope, cloverArtifact.getType());
try {
this.artifactResolver.resolve(cloverArtifact, repositories, localRepository);
} catch (AbstractArtifactResolutionException e) {
throw new MojoExecutionException("Could not resolve the clover artifact ( " +
cloverArtifact.getId() +
" ) in the localRepository: " + localRepository.getUrl(), e);
}
addArtifactDependency(cloverArtifact);
}
private void addArtifactDependency(final Artifact cloverArtifact) {
// TODO: use addArtifacts when it's implemented, see http://jira.codehaus.org/browse/MNG-2197
Set set = new LinkedHashSet(getProject().getDependencyArtifacts());
set.add(cloverArtifact);
getProject().setDependencyArtifacts(set);
}
private void logArtifacts(final String message) {
if (getLog().isDebugEnabled()) {
getLog().debug("[Clover] List of dependency artifacts " + message + ":");
logArtifacts(getProject().getDependencyArtifacts());
getLog().debug("[Clover] List of artifacts " + message + ":");
logArtifacts(getProject().getArtifacts());
}
}
private void logArtifacts(final Set artifacts) {
for (Artifact artifact : artifacts) {
getLog().debug("[Clover] Artifact [" + artifact.getId() + "], scope = [" + artifact.getScope() + "]");
}
}
protected void setArtifactFactory(final ArtifactFactory artifactFactory) {
this.artifactFactory = artifactFactory;
}
protected void setArtifactResolver(final ArtifactResolver artifactResolver) {
this.artifactResolver = artifactResolver;
}
}