Skip to content

Commit 68b814c

Browse files
committed
Merge branch '#54.configuration.cache'
* #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
2 parents cdcc1ed + 1a1ec76 commit 68b814c

23 files changed

+231
-125
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Explanation: v2.0 removes deprecated rendering API (= `net.sourceforge.pmd.cpd.R
5353
| [v2.0][] | 4.10.3 - 5.5 | >= 6.1.0 | >= 8 |
5454
| [v3.0][] | 5.6 - 5.x | >= 6.10.0 | >= 8 |
5555
| [v3.1][] | >= 5.6 | >= 6.10.0 | >= 8 |
56+
| [v3.2][] | >= 6.6 | >= 6.10.0 | >= 8 |
5657

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

@@ -159,7 +160,7 @@ source = subprojects*.sourceSets*.main*.java*.srcDirs
159160
or
160161
```groovy
161162
source = subprojects*.sourceSets*.main*.java*.srcDirs + subprojects*.sourceSets*.test*.java*.srcDirs
162-
```
163+
```
163164
or
164165
```groovy
165166
cpdCheck {

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ dependencies {
4646

4747
integTestImplementation "org.assertj:assertj-core:3.13.2"
4848
integTestImplementation "org.junit.vintage:junit-vintage-engine:5.5.2"
49-
integTestImplementation("org.spockframework:spock-core:1.3-groovy-2.4") {
49+
integTestImplementation("org.spockframework:spock-core:1.3-groovy-2.5") {
5050
exclude module: "groovy-all"
5151
}
5252
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

gradlew

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
154154
else
155155
eval `echo args$i`="\"$arg\""
156156
fi
157-
i=$((i+1))
157+
i=`expr $i + 1`
158158
done
159159
case $i in
160-
(0) set -- ;;
161-
(1) set -- "$args0" ;;
162-
(2) set -- "$args0" "$args1" ;;
163-
(3) set -- "$args0" "$args1" "$args2" ;;
164-
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165-
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166-
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167-
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168-
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169-
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
160+
0) set -- ;;
161+
1) set -- "$args0" ;;
162+
2) set -- "$args0" "$args1" ;;
163+
3) set -- "$args0" "$args1" "$args2" ;;
164+
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165+
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166+
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167+
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168+
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169+
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170170
esac
171171
fi
172172

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

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

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

src/integTest/groovy/de/aaschmid/gradle/plugins/cpd/test/CpdAcceptanceTest.groovy

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,4 +658,45 @@ class CpdAcceptanceTest extends IntegrationBaseSpec {
658658
secondResult.output.contains("BUILD SUCCESSFUL")
659659
!(secondResult.output =~ /CPD found duplicate code\. See the report at file:\/\/.*\/cpdCheck.vs/)
660660
}
661+
662+
@Issue("https://github.com/aaschmid/gradle-cpd-plugin/issues/54")
663+
def "Cpd task can be loaded from the configuration cache"() {
664+
given:
665+
buildFileWithPluginAndRepos() << """
666+
cpdCheck{
667+
reports{
668+
csv.enabled = true
669+
xml.enabled = false
670+
}
671+
source files(${testPath(JAVA, 'de/aaschmid/clazz')})
672+
}
673+
""".stripIndent()
674+
675+
when:
676+
def result = runWithoutDebug('--configuration-cache', 'cpdCheck')
677+
678+
then:
679+
result.task(':cpdCheck').outcome == SUCCESS
680+
result.output.contains('BUILD SUCCESSFUL')
681+
result.output.contains('Configuration cache entry stored.')
682+
683+
def report = file('build/reports/cpd/cpdCheck.csv')
684+
report.exists()
685+
report.text == "lines,tokens,occurrences\n" // empty
686+
687+
when:
688+
report.delete() // remove report in order to force re-execution of `cpdCheck`
689+
690+
and:
691+
def result2 = runWithoutDebug('--configuration-cache', 'cpdCheck')
692+
693+
then:
694+
result2.task(':cpdCheck').outcome == SUCCESS
695+
result2.output.contains("BUILD SUCCESSFUL")
696+
result2.output.contains('Configuration cache entry reused.')
697+
698+
def report2 = file('build/reports/cpd/cpdCheck.csv')
699+
report2.exists()
700+
report.text == "lines,tokens,occurrences\n" // empty
701+
}
661702
}

src/integTest/groovy/de/aaschmid/gradle/plugins/cpd/test/IntegrationBaseSpec.groovy

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ abstract class IntegrationBaseSpec extends Specification {
8484
}
8585
}
8686

87+
protected BuildResult runWithoutDebug(String... arguments) {
88+
try {
89+
return GradleRunner.create()
90+
.withProjectDir(testProjectDir.root)
91+
.withArguments(arguments)
92+
.withPluginClasspath()
93+
.withDebug(false) // `true` fails if `--configuration-cache`, see https://github.com/gradle/gradle/issues/14125
94+
.build()
95+
} catch (UnexpectedBuildResultException e) {
96+
return e.buildResult
97+
}
98+
}
99+
87100
/**
88101
* As the Gradle test kit does not support the old plugin mechanism, this method generates a {@code buildscript}
89102
* code block with the same dependencies as {@link org.gradle.testkit.runner.GradleRunner#withPluginClasspath()} or

src/main/java/de/aaschmid/gradle/plugins/cpd/Cpd.java

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,30 @@
1010
import de.aaschmid.gradle.plugins.cpd.internal.worker.CpdWorkParameters;
1111
import de.aaschmid.gradle.plugins.cpd.internal.worker.CpdWorkParameters.Report;
1212
import groovy.lang.Closure;
13+
import groovy.lang.DelegatesTo;
1314
import org.gradle.api.Action;
1415
import org.gradle.api.InvalidUserDataException;
1516
import org.gradle.api.file.FileCollection;
1617
import org.gradle.api.file.FileTree;
17-
import org.gradle.api.internal.CollectionCallbackActionDecorator;
18+
import org.gradle.api.model.ObjectFactory;
19+
import org.gradle.api.plugins.quality.PmdReports;
20+
import org.gradle.api.provider.ProviderFactory;
1821
import org.gradle.api.reporting.Reporting;
1922
import org.gradle.api.reporting.SingleFileReport;
2023
import org.gradle.api.tasks.CacheableTask;
2124
import org.gradle.api.tasks.Classpath;
2225
import org.gradle.api.tasks.Input;
2326
import org.gradle.api.tasks.InputFiles;
27+
import org.gradle.api.tasks.Internal;
2428
import org.gradle.api.tasks.Nested;
29+
import org.gradle.api.tasks.Optional;
2530
import org.gradle.api.tasks.PathSensitive;
2631
import org.gradle.api.tasks.PathSensitivity;
2732
import org.gradle.api.tasks.SkipWhenEmpty;
2833
import org.gradle.api.tasks.SourceTask;
2934
import org.gradle.api.tasks.TaskAction;
3035
import org.gradle.api.tasks.VerificationTask;
31-
import org.gradle.internal.reflect.Instantiator;
36+
import org.gradle.util.ClosureBackedAction;
3237
import org.gradle.workers.WorkerExecutor;
3338

3439

@@ -71,26 +76,27 @@
7176
@CacheableTask
7277
public class Cpd extends SourceTask implements VerificationTask, Reporting<CpdReports> {
7378

79+
private final ProviderFactory providerFactory;
7480
private final WorkerExecutor workerExecutor;
75-
private final CpdReportsImpl reports;
81+
private final CpdReports reports;
7682

7783
private String encoding;
7884
private boolean ignoreAnnotations;
7985
private boolean ignoreFailures;
8086
private boolean ignoreIdentifiers;
8187
private boolean ignoreLiterals;
8288
private String language;
83-
private int minimumTokenCount;
89+
private Integer minimumTokenCount;
8490
private FileCollection pmdClasspath;
8591
private boolean skipDuplicateFiles;
8692
private boolean skipLexicalErrors;
8793
private boolean skipBlocks;
8894
private String skipBlocksPattern;
8995

90-
9196
@Inject
92-
public Cpd(CollectionCallbackActionDecorator callbackActionDecorator, Instantiator instantiator, WorkerExecutor workerExecutor) {
93-
this.reports = instantiator.newInstance(CpdReportsImpl.class, this, callbackActionDecorator);
97+
public Cpd(ObjectFactory objectFactory, ProviderFactory providerFactory, WorkerExecutor workerExecutor) {
98+
this.providerFactory = providerFactory;
99+
this.reports = objectFactory.newInstance(CpdReportsImpl.class, this);
94100
this.workerExecutor = workerExecutor;
95101
}
96102

@@ -104,20 +110,17 @@ public void run() {
104110
}
105111

106112
private void checkTaskState() {
107-
if (getEncoding() == null) {
108-
throw new InvalidUserDataException(String.format("Task '%s' requires 'encoding' but was: %s.", getName(), getEncoding()));
109-
}
110113
if (getMinimumTokenCount() <= 0) {
111114
throw new InvalidUserDataException(String.format("Task '%s' requires 'minimumTokenCount' to be greater than zero.", getName()));
112115
}
113-
if (reports.getEnabled().isEmpty()) {
116+
if (getReports().getEnabled().isEmpty()) {
114117
throw new InvalidUserDataException(String.format("Task '%s' requires at least one enabled report.", getName()));
115118
}
116119
}
117120

118121
private Action<CpdWorkParameters> getCpdWorkParameters() {
119122
return parameters -> {
120-
parameters.getEncoding().set(getEncoding());
123+
parameters.getEncoding().set(getEncodingOrFallback());
121124
parameters.getIgnoreAnnotations().set(getIgnoreAnnotations());
122125
parameters.getIgnoreFailures().set(getIgnoreFailures());
123126
parameters.getIgnoreIdentifiers().set(getIgnoreIdentifiers());
@@ -150,7 +153,7 @@ private List<Report> createReportParameters(CpdReports reports) {
150153
boolean trimLeadingCommonSourceWhitespaces = ((CpdTextFileReport) report).getTrimLeadingCommonSourceWhitespaces();
151154
result.add(new Report.Text(report.getDestination(), lineSeparator, trimLeadingCommonSourceWhitespaces));
152155

153-
} else if (report instanceof CpdVsFileReport) {
156+
} else if (report.getName().equals("vs")) {
154157
result.add(new Report.Vs(report.getDestination()));
155158

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

167170
// VisibleForTesting
168-
String getXmlRendererEncoding(CpdXmlFileReport report) {
169-
String encoding = report.getEncoding();
171+
@Internal
172+
String getEncodingOrFallback() {
173+
String encoding = getEncoding();
170174
if (encoding == null) {
171-
encoding = getEncoding();
175+
encoding = providerFactory.systemProperty("file.encoding").forUseAtConfigurationTime().get();
172176
}
177+
return encoding;
178+
}
179+
180+
// VisibleForTesting
181+
String getXmlRendererEncoding(CpdXmlFileReport report) {
182+
String encoding = report.getEncoding();
173183
if (encoding == null) {
174-
encoding = System.getProperty("file.encoding");
184+
return getEncodingOrFallback();
175185
}
176186
return encoding;
177187
}
@@ -185,8 +195,8 @@ public FileTree getSource() {
185195
}
186196

187197
@Override
188-
public CpdReports reports(Closure closure) {
189-
return (CpdReports) reports.configure(closure);
198+
public CpdReports reports(@DelegatesTo(value = CpdReports.class, strategy = Closure.DELEGATE_FIRST) Closure closure) {
199+
return reports(new ClosureBackedAction<>(closure));
190200
}
191201

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

204-
205214
/**
206215
* The character set encoding (e.g., UTF-8) to use when reading the source code files but also when producing the report; defaults to
207216
* {@link CpdExtension#getEncoding()}.
@@ -211,6 +220,7 @@ public CpdReports reports(Action<? super CpdReports> action) {
211220
* @return the charset encoding
212221
*/
213222
@Input
223+
@Optional
214224
public String getEncoding() {
215225
return encoding;
216226
}
@@ -311,11 +321,11 @@ public void setLanguage(String language) {
311321
* @return the minimum token cound
312322
*/
313323
@Input
314-
public int getMinimumTokenCount() {
324+
public Integer getMinimumTokenCount() {
315325
return minimumTokenCount;
316326
}
317327

318-
public void setMinimumTokenCount(int minimumTokenCount) {
328+
public void setMinimumTokenCount(Integer minimumTokenCount) {
319329
this.minimumTokenCount = minimumTokenCount;
320330
}
321331

src/main/java/de/aaschmid/gradle/plugins/cpd/CpdExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
public class CpdExtension extends CodeQualityExtension {
2525

26-
private String encoding = System.getProperty("file.encoding");
26+
private String encoding;
2727
private boolean ignoreAnnotations = false;
2828
private boolean ignoreIdentifiers = false;
2929
private boolean ignoreLiterals = false;

src/main/java/de/aaschmid/gradle/plugins/cpd/CpdPlugin.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,23 @@
99
import org.gradle.api.Task;
1010
import org.gradle.api.artifacts.Configuration;
1111
import org.gradle.api.execution.TaskExecutionGraph;
12+
import org.gradle.api.file.ProjectLayout;
13+
import org.gradle.api.file.RegularFile;
1214
import org.gradle.api.internal.ConventionMapping;
1315
import org.gradle.api.internal.IConventionAware;
1416
import org.gradle.api.logging.Logger;
1517
import org.gradle.api.logging.Logging;
1618
import org.gradle.api.plugins.JavaBasePlugin;
1719
import org.gradle.api.plugins.JavaPluginConvention;
1820
import org.gradle.api.plugins.ReportingBasePlugin;
21+
import org.gradle.api.provider.Provider;
22+
import org.gradle.api.provider.ProviderFactory;
1923
import org.gradle.api.reporting.ReportingExtension;
2024
import org.gradle.api.tasks.TaskProvider;
2125
import org.gradle.language.base.plugins.LifecycleBasePlugin;
2226

2327
import static java.util.Collections.reverseOrder;
28+
import static org.gradle.api.internal.lambdas.SerializableLambdas.action;
2429

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

126+
ProjectLayout layout = project.getLayout();
127+
ProviderFactory providers = project.getProviders();
121128
task.getReports().all(report -> {
122-
ConventionMapping reportMapping = ((IConventionAware) report).getConventionMapping();
123-
reportMapping.map("enabled", () -> "xml".equals(report.getName()));
124-
reportMapping.map("destination", () -> new File(extension.getReportsDir(), task.getName() + "." + report.getName()));
129+
report.getRequired().convention("xml".equals(report.getName()));
130+
report.getOutputLocation().convention(layout.getProjectDirectory().file(providers.provider(() ->
131+
new File(extension.getReportsDir(), task.getName() + "." + report.getName()).getAbsolutePath())));
125132
});
126133
});
127134
}

src/main/java/de/aaschmid/gradle/plugins/cpd/CpdReports.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public interface CpdReports extends ReportContainer<SingleFileReport> {
4848
* @return The CPD (single file) 'vs' report
4949
*/
5050
@Nested
51-
CpdVsFileReport getVs();
51+
SingleFileReport getVs();
5252

5353
/**
5454
* @return The CPD (single file) 'XML' report

0 commit comments

Comments
 (0)