Skip to content

Commit

Permalink
Merge branch '#54.configuration.cache'
Browse files Browse the repository at this point in the history
* #54.configuration.cache:
  check-in acceptance test for configuration cache (#54)
  do not use Project within configuration lambda (#54)
  align report methods with internal quality tasks like PMD
  upgrade to Gradle 6.6 (#54)
  make encoding property compatible with configuration cache (#54)
  use primitive wrapper as otherwise it is not configuration cached (#54)
  fix configuration cache problem with reports (#54)
  upgrade to Gradle 6.1
  • Loading branch information
aaschmid committed Mar 28, 2021
2 parents cdcc1ed + 1a1ec76 commit 68b814c
Show file tree
Hide file tree
Showing 23 changed files with 231 additions and 125 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Explanation: v2.0 removes deprecated rendering API (= `net.sourceforge.pmd.cpd.R
| [v2.0][] | 4.10.3 - 5.5 | >= 6.1.0 | >= 8 |
| [v3.0][] | 5.6 - 5.x | >= 6.10.0 | >= 8 |
| [v3.1][] | >= 5.6 | >= 6.10.0 | >= 8 |
| [v3.2][] | >= 6.6 | >= 6.10.0 | >= 8 |

¹: Java version may additionally depend on [PMD][]s version which is might not be properly reflected here.

Expand Down Expand Up @@ -159,7 +160,7 @@ source = subprojects*.sourceSets*.main*.java*.srcDirs
or
```groovy
source = subprojects*.sourceSets*.main*.java*.srcDirs + subprojects*.sourceSets*.test*.java*.srcDirs
```
```
or
```groovy
cpdCheck {
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ dependencies {

integTestImplementation "org.assertj:assertj-core:3.13.2"
integTestImplementation "org.junit.vintage:junit-vintage-engine:5.5.2"
integTestImplementation("org.spockframework:spock-core:1.3-groovy-2.4") {
integTestImplementation("org.spockframework:spock-core:1.3-groovy-2.5") {
exclude module: "groovy-all"
}
}
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
29 changes: 12 additions & 17 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

Expand All @@ -175,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"
Original file line number Diff line number Diff line change
Expand Up @@ -658,4 +658,45 @@ class CpdAcceptanceTest extends IntegrationBaseSpec {
secondResult.output.contains("BUILD SUCCESSFUL")
!(secondResult.output =~ /CPD found duplicate code\. See the report at file:\/\/.*\/cpdCheck.vs/)
}

@Issue("https://github.com/aaschmid/gradle-cpd-plugin/issues/54")
def "Cpd task can be loaded from the configuration cache"() {
given:
buildFileWithPluginAndRepos() << """
cpdCheck{
reports{
csv.enabled = true
xml.enabled = false
}
source files(${testPath(JAVA, 'de/aaschmid/clazz')})
}
""".stripIndent()

when:
def result = runWithoutDebug('--configuration-cache', 'cpdCheck')

then:
result.task(':cpdCheck').outcome == SUCCESS
result.output.contains('BUILD SUCCESSFUL')
result.output.contains('Configuration cache entry stored.')

def report = file('build/reports/cpd/cpdCheck.csv')
report.exists()
report.text == "lines,tokens,occurrences\n" // empty

when:
report.delete() // remove report in order to force re-execution of `cpdCheck`

and:
def result2 = runWithoutDebug('--configuration-cache', 'cpdCheck')

then:
result2.task(':cpdCheck').outcome == SUCCESS
result2.output.contains("BUILD SUCCESSFUL")
result2.output.contains('Configuration cache entry reused.')

def report2 = file('build/reports/cpd/cpdCheck.csv')
report2.exists()
report.text == "lines,tokens,occurrences\n" // empty
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ abstract class IntegrationBaseSpec extends Specification {
}
}

protected BuildResult runWithoutDebug(String... arguments) {
try {
return GradleRunner.create()
.withProjectDir(testProjectDir.root)
.withArguments(arguments)
.withPluginClasspath()
.withDebug(false) // `true` fails if `--configuration-cache`, see https://github.com/gradle/gradle/issues/14125
.build()
} catch (UnexpectedBuildResultException e) {
return e.buildResult
}
}

/**
* As the Gradle test kit does not support the old plugin mechanism, this method generates a {@code buildscript}
* code block with the same dependencies as {@link org.gradle.testkit.runner.GradleRunner#withPluginClasspath()} or
Expand Down
54 changes: 32 additions & 22 deletions src/main/java/de/aaschmid/gradle/plugins/cpd/Cpd.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,30 @@
import de.aaschmid.gradle.plugins.cpd.internal.worker.CpdWorkParameters;
import de.aaschmid.gradle.plugins.cpd.internal.worker.CpdWorkParameters.Report;
import groovy.lang.Closure;
import groovy.lang.DelegatesTo;
import org.gradle.api.Action;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.internal.CollectionCallbackActionDecorator;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.quality.PmdReports;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.reporting.Reporting;
import org.gradle.api.reporting.SingleFileReport;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationTask;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.util.ClosureBackedAction;
import org.gradle.workers.WorkerExecutor;


Expand Down Expand Up @@ -71,26 +76,27 @@
@CacheableTask
public class Cpd extends SourceTask implements VerificationTask, Reporting<CpdReports> {

private final ProviderFactory providerFactory;
private final WorkerExecutor workerExecutor;
private final CpdReportsImpl reports;
private final CpdReports reports;

private String encoding;
private boolean ignoreAnnotations;
private boolean ignoreFailures;
private boolean ignoreIdentifiers;
private boolean ignoreLiterals;
private String language;
private int minimumTokenCount;
private Integer minimumTokenCount;
private FileCollection pmdClasspath;
private boolean skipDuplicateFiles;
private boolean skipLexicalErrors;
private boolean skipBlocks;
private String skipBlocksPattern;


@Inject
public Cpd(CollectionCallbackActionDecorator callbackActionDecorator, Instantiator instantiator, WorkerExecutor workerExecutor) {
this.reports = instantiator.newInstance(CpdReportsImpl.class, this, callbackActionDecorator);
public Cpd(ObjectFactory objectFactory, ProviderFactory providerFactory, WorkerExecutor workerExecutor) {
this.providerFactory = providerFactory;
this.reports = objectFactory.newInstance(CpdReportsImpl.class, this);
this.workerExecutor = workerExecutor;
}

Expand All @@ -104,20 +110,17 @@ public void run() {
}

private void checkTaskState() {
if (getEncoding() == null) {
throw new InvalidUserDataException(String.format("Task '%s' requires 'encoding' but was: %s.", getName(), getEncoding()));
}
if (getMinimumTokenCount() <= 0) {
throw new InvalidUserDataException(String.format("Task '%s' requires 'minimumTokenCount' to be greater than zero.", getName()));
}
if (reports.getEnabled().isEmpty()) {
if (getReports().getEnabled().isEmpty()) {
throw new InvalidUserDataException(String.format("Task '%s' requires at least one enabled report.", getName()));
}
}

private Action<CpdWorkParameters> getCpdWorkParameters() {
return parameters -> {
parameters.getEncoding().set(getEncoding());
parameters.getEncoding().set(getEncodingOrFallback());
parameters.getIgnoreAnnotations().set(getIgnoreAnnotations());
parameters.getIgnoreFailures().set(getIgnoreFailures());
parameters.getIgnoreIdentifiers().set(getIgnoreIdentifiers());
Expand Down Expand Up @@ -150,7 +153,7 @@ private List<Report> createReportParameters(CpdReports reports) {
boolean trimLeadingCommonSourceWhitespaces = ((CpdTextFileReport) report).getTrimLeadingCommonSourceWhitespaces();
result.add(new Report.Text(report.getDestination(), lineSeparator, trimLeadingCommonSourceWhitespaces));

} else if (report instanceof CpdVsFileReport) {
} else if (report.getName().equals("vs")) {
result.add(new Report.Vs(report.getDestination()));

} else if (report instanceof CpdXmlFileReport) {
Expand All @@ -165,13 +168,20 @@ private List<Report> createReportParameters(CpdReports reports) {
}

// VisibleForTesting
String getXmlRendererEncoding(CpdXmlFileReport report) {
String encoding = report.getEncoding();
@Internal
String getEncodingOrFallback() {
String encoding = getEncoding();
if (encoding == null) {
encoding = getEncoding();
encoding = providerFactory.systemProperty("file.encoding").forUseAtConfigurationTime().get();
}
return encoding;
}

// VisibleForTesting
String getXmlRendererEncoding(CpdXmlFileReport report) {
String encoding = report.getEncoding();
if (encoding == null) {
encoding = System.getProperty("file.encoding");
return getEncodingOrFallback();
}
return encoding;
}
Expand All @@ -185,8 +195,8 @@ public FileTree getSource() {
}

@Override
public CpdReports reports(Closure closure) {
return (CpdReports) reports.configure(closure);
public CpdReports reports(@DelegatesTo(value = CpdReports.class, strategy = Closure.DELEGATE_FIRST) Closure closure) {
return reports(new ClosureBackedAction<>(closure));
}

@Override
Expand All @@ -201,7 +211,6 @@ public CpdReports reports(Action<? super CpdReports> action) {
return this.reports;
}


/**
* The character set encoding (e.g., UTF-8) to use when reading the source code files but also when producing the report; defaults to
* {@link CpdExtension#getEncoding()}.
Expand All @@ -211,6 +220,7 @@ public CpdReports reports(Action<? super CpdReports> action) {
* @return the charset encoding
*/
@Input
@Optional
public String getEncoding() {
return encoding;
}
Expand Down Expand Up @@ -311,11 +321,11 @@ public void setLanguage(String language) {
* @return the minimum token cound
*/
@Input
public int getMinimumTokenCount() {
public Integer getMinimumTokenCount() {
return minimumTokenCount;
}

public void setMinimumTokenCount(int minimumTokenCount) {
public void setMinimumTokenCount(Integer minimumTokenCount) {
this.minimumTokenCount = minimumTokenCount;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*/
public class CpdExtension extends CodeQualityExtension {

private String encoding = System.getProperty("file.encoding");
private String encoding;
private boolean ignoreAnnotations = false;
private boolean ignoreIdentifiers = false;
private boolean ignoreLiterals = false;
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/de/aaschmid/gradle/plugins/cpd/CpdPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,23 @@
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.execution.TaskExecutionGraph;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.file.RegularFile;
import org.gradle.api.internal.ConventionMapping;
import org.gradle.api.internal.IConventionAware;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.plugins.ReportingBasePlugin;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.reporting.ReportingExtension;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;

import static java.util.Collections.reverseOrder;
import static org.gradle.api.internal.lambdas.SerializableLambdas.action;

/**
* A plugin for the finding duplicate code using <a href="http://pmd.sourceforge.net/cpd-usage.html">CPD</a> source code analyzer (which is
Expand Down Expand Up @@ -118,10 +123,12 @@ private void setupTaskDefaults(Project project, CpdExtension extension) {
ConventionMapping extensionMapping = ((IConventionAware) extension).getConventionMapping();
extensionMapping.map("reportsDir", () -> project.getExtensions().getByType(ReportingExtension.class).file("cpd"));

ProjectLayout layout = project.getLayout();
ProviderFactory providers = project.getProviders();
task.getReports().all(report -> {
ConventionMapping reportMapping = ((IConventionAware) report).getConventionMapping();
reportMapping.map("enabled", () -> "xml".equals(report.getName()));
reportMapping.map("destination", () -> new File(extension.getReportsDir(), task.getName() + "." + report.getName()));
report.getRequired().convention("xml".equals(report.getName()));
report.getOutputLocation().convention(layout.getProjectDirectory().file(providers.provider(() ->
new File(extension.getReportsDir(), task.getName() + "." + report.getName()).getAbsolutePath())));
});
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public interface CpdReports extends ReportContainer<SingleFileReport> {
* @return The CPD (single file) 'vs' report
*/
@Nested
CpdVsFileReport getVs();
SingleFileReport getVs();

/**
* @return The CPD (single file) 'XML' report
Expand Down
14 changes: 0 additions & 14 deletions src/main/java/de/aaschmid/gradle/plugins/cpd/CpdVsFileReport.java

This file was deleted.

0 comments on commit 68b814c

Please sign in to comment.