pmdtester 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/build.yml +9 -7
- data/.github/workflows/manual-integration-tests.yml +9 -7
- data/.github/workflows/publish-release.yml +9 -9
- data/.hoerc +1 -1
- data/.rubocop_todo.yml +1 -14
- data/.vscode/launch.json +32 -0
- data/History.md +54 -0
- data/Manifest.txt +13 -0
- data/README.rdoc +77 -30
- data/Rakefile +11 -11
- data/config/custom.jfc +1126 -0
- data/config/project-list-with-cpd.xml +268 -0
- data/config/projectlist_1_2_0.xsd +1 -1
- data/config/projectlist_1_3_0.xsd +53 -0
- data/lib/pmdtester/builders/cpd_project_hasher.rb +70 -0
- data/lib/pmdtester/builders/liquid_renderer.rb +111 -16
- data/lib/pmdtester/builders/pmd_report_builder.rb +139 -41
- data/lib/pmdtester/builders/project_hasher.rb +24 -25
- data/lib/pmdtester/builders/rule_set_builder.rb +43 -11
- data/lib/pmdtester/builders/summary_report_builder.rb +6 -1
- data/lib/pmdtester/cmd.rb +24 -9
- data/lib/pmdtester/cpd_report_diff.rb +99 -0
- data/lib/pmdtester/jfr_summary.rb +119 -0
- data/lib/pmdtester/location.rb +38 -0
- data/lib/pmdtester/parsers/cpd_report_document.rb +241 -0
- data/lib/pmdtester/parsers/options.rb +19 -0
- data/lib/pmdtester/parsers/pmd_report_document.rb +14 -1
- data/lib/pmdtester/parsers/projects_parser.rb +1 -1
- data/lib/pmdtester/pmd_branch_detail.rb +29 -9
- data/lib/pmdtester/pmd_report_detail.rb +54 -13
- data/lib/pmdtester/pmd_tester_utils.rb +45 -17
- data/lib/pmdtester/pmd_violation.rb +15 -6
- data/lib/pmdtester/project.rb +63 -3
- data/lib/pmdtester/report_diff.rb +5 -13
- data/lib/pmdtester/runner.rb +185 -37
- data/lib/pmdtester/system_info.rb +58 -0
- data/lib/pmdtester/word_differ.rb +132 -0
- data/lib/pmdtester.rb +8 -1
- data/pmdtester.gemspec +17 -17
- data/resources/css/pmd-tester.css +15 -0
- data/resources/js/project-report.js +293 -112
- data/resources/project_cpd_report.html +144 -0
- data/resources/project_diff_report.html +151 -18
- data/resources/project_index.html +12 -3
- data/resources/project_pmd_report.html +17 -2
- metadata +63 -43
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
|
|
3
|
+
<projectlist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
4
|
+
xsi:noNamespaceSchemaLocation="projectlist_1_3_0.xsd">
|
|
5
|
+
<description>Standard Projects</description>
|
|
6
|
+
|
|
7
|
+
<project>
|
|
8
|
+
<name>checkstyle</name>
|
|
9
|
+
<type>git</type>
|
|
10
|
+
<connection>https://github.com/checkstyle/checkstyle</connection>
|
|
11
|
+
<tag>checkstyle-9.1</tag>
|
|
12
|
+
|
|
13
|
+
<exclude-pattern>.*/target/test-classes/com/puppycrawl/tools/checkstyle/.*</exclude-pattern>
|
|
14
|
+
<exclude-pattern>.*/target/generated-sources/.*</exclude-pattern>
|
|
15
|
+
<exclude-pattern>.*/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/javaparser/InputJavaParserNoFreezeOnDeeplyNestedLambdas.java</exclude-pattern>
|
|
16
|
+
|
|
17
|
+
<build-command><![CDATA[#!/usr/bin/env bash
|
|
18
|
+
if test -e classpath.txt; then
|
|
19
|
+
exit
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
set -e
|
|
23
|
+
|
|
24
|
+
# Make sure to use java11. This is already installed by build.yml/publish-snapshot.yml/publish-release.yml
|
|
25
|
+
export JAVA_HOME=${HOME}/openjdk11
|
|
26
|
+
export PATH=$JAVA_HOME/bin:$PATH
|
|
27
|
+
|
|
28
|
+
mvn test-compile -B
|
|
29
|
+
mvn dependency:build-classpath -DincludeScope=test -Dmdep.outputFile=classpath.txt -B
|
|
30
|
+
]]></build-command>
|
|
31
|
+
<auxclasspath-command>echo -n "${HOME}/openjdk11/lib/jrt-fs.jar:$(pwd)/target/classes:$(pwd)/target/test-classes:"; cat classpath.txt</auxclasspath-command>
|
|
32
|
+
<cpd-options>
|
|
33
|
+
<language>java</language>
|
|
34
|
+
<minimum-tokens>50</minimum-tokens>
|
|
35
|
+
<max-memory>4g</max-memory>
|
|
36
|
+
<directories>
|
|
37
|
+
<!-- this avoids analyzing src/test/resources-noncompilable ... -->
|
|
38
|
+
<directory>src/main/java</directory>
|
|
39
|
+
<directory>src/test/java</directory>
|
|
40
|
+
</directories>
|
|
41
|
+
</cpd-options>
|
|
42
|
+
</project>
|
|
43
|
+
|
|
44
|
+
<project>
|
|
45
|
+
<name>spring-framework</name>
|
|
46
|
+
<type>git</type>
|
|
47
|
+
<connection>https://github.com/spring-projects/spring-framework</connection>
|
|
48
|
+
<tag>v5.3.13</tag>
|
|
49
|
+
|
|
50
|
+
<exclude-pattern>.*/build/generated-sources/.*</exclude-pattern>
|
|
51
|
+
<exclude-pattern>.*/build/resources/.*</exclude-pattern>
|
|
52
|
+
|
|
53
|
+
<build-command><![CDATA[#!/usr/bin/env bash
|
|
54
|
+
## Skip gradle execution
|
|
55
|
+
if test -e classpath.txt; then
|
|
56
|
+
exit
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
set -e
|
|
60
|
+
|
|
61
|
+
# Make sure to use java11. This is already installed by build.yml/publish-snapshot.yml/publish-release.yml
|
|
62
|
+
export JAVA_HOME=${HOME}/openjdk11
|
|
63
|
+
export PATH=$JAVA_HOME/bin:$PATH
|
|
64
|
+
|
|
65
|
+
## Patches
|
|
66
|
+
# keep the tabs!!
|
|
67
|
+
# Patch 1: See https://github.com/spring-projects/spring-framework/commit/381b7d035a16d430b8783b7390c1677c9e7d1f68
|
|
68
|
+
# and https://github.com/spring-projects/spring-framework/commit/9e1ed6c7718d38c4b9fe5f75921abad33264307c
|
|
69
|
+
(cat <<EOF
|
|
70
|
+
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
|
|
71
|
+
index 37f5884e67..53022443ee 100644
|
|
72
|
+
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
|
|
73
|
+
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
|
|
74
|
+
@@ -539,7 +539,9 @@ public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationA
|
|
75
|
+
*/
|
|
76
|
+
@SuppressWarnings({"deprecation", "cast"})
|
|
77
|
+
protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
|
|
78
|
+
- return determineRequiredStatus(
|
|
79
|
+
+ // Cast to (AnnotationAttributes) is required. Otherwise, the :spring-beans:compileGroovy
|
|
80
|
+
+ // task fails in the Gradle build.
|
|
81
|
+
+ return determineRequiredStatus((AnnotationAttributes)
|
|
82
|
+
ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType())));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
EOF
|
|
86
|
+
) | patch --strip=1
|
|
87
|
+
|
|
88
|
+
# Patch 2: Ignore compiler warnings
|
|
89
|
+
(cat <<EOF
|
|
90
|
+
diff --git a/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java
|
|
91
|
+
index f2424c549e..b6ec8b04da 100644
|
|
92
|
+
--- a/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java
|
|
93
|
+
+++ b/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java
|
|
94
|
+
@@ -51,7 +51,7 @@ public class CompilerConventionsPlugin implements Plugin<Project> {
|
|
95
|
+
COMPILER_ARGS.addAll(commonCompilerArgs);
|
|
96
|
+
COMPILER_ARGS.addAll(Arrays.asList(
|
|
97
|
+
"-Xlint:varargs", "-Xlint:fallthrough", "-Xlint:rawtypes", "-Xlint:deprecation",
|
|
98
|
+
- "-Xlint:unchecked", "-Werror"
|
|
99
|
+
+ "-Xlint:unchecked"//, "-Werror"
|
|
100
|
+
));
|
|
101
|
+
TEST_COMPILER_ARGS = new ArrayList<>();
|
|
102
|
+
TEST_COMPILER_ARGS.addAll(commonCompilerArgs);
|
|
103
|
+
diff --git a/spring-beans/spring-beans.gradle b/spring-beans/spring-beans.gradle
|
|
104
|
+
index e3f6f73b76..48c4d9e3fb 100644
|
|
105
|
+
--- a/spring-beans/spring-beans.gradle
|
|
106
|
+
+++ b/spring-beans/spring-beans.gradle
|
|
107
|
+
@@ -23,7 +23,7 @@ sourceSets {
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
compileGroovy {
|
|
111
|
+
- options.compilerArgs += "-Werror"
|
|
112
|
+
+// options.compilerArgs += "-Werror"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// This module also builds Kotlin code and the compileKotlin task naturally depends on
|
|
116
|
+
EOF
|
|
117
|
+
) | patch --strip=1
|
|
118
|
+
|
|
119
|
+
# Patch 3: Add task createSquishClasspath
|
|
120
|
+
(cat <<EOF
|
|
121
|
+
diff --git a/build.gradle b/build.gradle
|
|
122
|
+
index 6021fa574d..15d29ed699 100644
|
|
123
|
+
--- a/build.gradle
|
|
124
|
+
+++ b/build.gradle
|
|
125
|
+
@@ -431,3 +431,19 @@ configure(rootProject) {
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
+
|
|
130
|
+
+// see https://stackoverflow.com/questions/28986968/generate-classpath-from-all-multiproject-gradle-build-dependencies
|
|
131
|
+
+task createSquishClasspath {
|
|
132
|
+
+ doLast {
|
|
133
|
+
+ def dependencies = new LinkedHashSet()
|
|
134
|
+
+ dependencies.addAll(moduleProjects.configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.file.flatten())
|
|
135
|
+
+ dependencies.addAll(moduleProjects.configurations.testCompileClasspath.resolvedConfiguration.resolvedArtifacts.file.flatten())
|
|
136
|
+
+
|
|
137
|
+
+ def paths = new ArrayList()
|
|
138
|
+
+ paths.addAll(moduleProjects.jar.outputs.files.asPath)
|
|
139
|
+
+ paths.addAll(moduleProjects.sourceSets.test.output.resourcesDir)
|
|
140
|
+
+ paths.addAll(moduleProjects.sourceSets.test.output.classesDirs.files.flatten())
|
|
141
|
+
+ paths.addAll(dependencies)
|
|
142
|
+
+ println paths.join(File.pathSeparator)
|
|
143
|
+
+ }
|
|
144
|
+
+}
|
|
145
|
+
EOF
|
|
146
|
+
) | patch --strip=1
|
|
147
|
+
|
|
148
|
+
# Patch 4: Add https://maven.repository.redhat.com/ga/ as repository in order to resolve
|
|
149
|
+
# dependency com.ibm.websphere/uow/6.0.2.17
|
|
150
|
+
# See https://spring.io/blog/2020/10/29/notice-of-permissions-changes-to-repo-spring-io-fall-and-winter-2020
|
|
151
|
+
(cat <<EOF
|
|
152
|
+
diff --git a/build.gradle b/build.gradle
|
|
153
|
+
index 6021fa57..8319ff76 100644
|
|
154
|
+
--- a/build.gradle
|
|
155
|
+
+++ b/build.gradle
|
|
156
|
+
@@ -291,6 +291,7 @@ configure(allprojects) { project ->
|
|
157
|
+
}
|
|
158
|
+
repositories {
|
|
159
|
+
mavenCentral()
|
|
160
|
+
+ maven { url "https://maven.repository.redhat.com/ga/" }
|
|
161
|
+
maven { url "https://repo.spring.io/libs-spring-framework-build" }
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
EOF
|
|
165
|
+
) | patch --strip=1
|
|
166
|
+
|
|
167
|
+
./gradlew --console=plain --build-cache --no-daemon --max-workers=4 build testClasses -x test -x javadoc -x api -x asciidoctor -x asciidoctorPdf
|
|
168
|
+
./gradlew --console=plain --build-cache --no-daemon --max-workers=4 createSquishClasspath -q > classpath.txt
|
|
169
|
+
]]></build-command>
|
|
170
|
+
<auxclasspath-command>echo -n "${HOME}/openjdk11/lib/jrt-fs.jar:"; cat classpath.txt</auxclasspath-command>
|
|
171
|
+
<cpd-options>
|
|
172
|
+
<language>java</language>
|
|
173
|
+
<minimum-tokens>150</minimum-tokens>
|
|
174
|
+
<max-memory>4g</max-memory>
|
|
175
|
+
</cpd-options>
|
|
176
|
+
</project>
|
|
177
|
+
|
|
178
|
+
<project>
|
|
179
|
+
<name>openjdk-11</name>
|
|
180
|
+
<type>git</type>
|
|
181
|
+
<connection>https://github.com/openjdk/jdk</connection>
|
|
182
|
+
<tag>jdk-11+28</tag>
|
|
183
|
+
<src-subpath>src/java.base</src-subpath>
|
|
184
|
+
<auxclasspath-command>echo -n "${HOME}/openjdk11/lib/jrt-fs.jar"</auxclasspath-command>
|
|
185
|
+
<cpd-options>
|
|
186
|
+
<language>java</language>
|
|
187
|
+
<minimum-tokens>150</minimum-tokens>
|
|
188
|
+
<max-memory>4g</max-memory>
|
|
189
|
+
<directories>
|
|
190
|
+
<directory>src/java.base</directory>
|
|
191
|
+
</directories>
|
|
192
|
+
</cpd-options>
|
|
193
|
+
</project>
|
|
194
|
+
|
|
195
|
+
<project>
|
|
196
|
+
<name>Schedul-o-matic-9000</name>
|
|
197
|
+
<type>git</type>
|
|
198
|
+
<connection>https://github.com/SalesforceLabs/Schedul-o-matic-9000</connection>
|
|
199
|
+
<tag>6b1229ba43b38931fbbab5924bc9b9611d19a786</tag>
|
|
200
|
+
<cpd-options>
|
|
201
|
+
<language>apex</language>
|
|
202
|
+
<minimum-tokens>100</minimum-tokens>
|
|
203
|
+
<max-memory>512m</max-memory>
|
|
204
|
+
</cpd-options>
|
|
205
|
+
</project>
|
|
206
|
+
|
|
207
|
+
<project>
|
|
208
|
+
<name>fflib-apex-common</name>
|
|
209
|
+
<type>git</type>
|
|
210
|
+
<connection>https://github.com/apex-enterprise-patterns/fflib-apex-common</connection>
|
|
211
|
+
<tag>7e0891efb86d23de62811af56d87d0959082a322</tag>
|
|
212
|
+
<cpd-options>
|
|
213
|
+
<language>apex</language>
|
|
214
|
+
<minimum-tokens>100</minimum-tokens>
|
|
215
|
+
<max-memory>512m</max-memory>
|
|
216
|
+
</cpd-options>
|
|
217
|
+
</project>
|
|
218
|
+
|
|
219
|
+
<project>
|
|
220
|
+
<name>apex-link</name>
|
|
221
|
+
<type>git</type>
|
|
222
|
+
<connection>https://github.com/nawforce/apex-link</connection>
|
|
223
|
+
<tag>v2.3.0</tag>
|
|
224
|
+
<src-subpath>samples</src-subpath>
|
|
225
|
+
<cpd-options>
|
|
226
|
+
<language>apex</language>
|
|
227
|
+
<minimum-tokens>100</minimum-tokens>
|
|
228
|
+
<max-memory>512m</max-memory>
|
|
229
|
+
</cpd-options>
|
|
230
|
+
</project>
|
|
231
|
+
|
|
232
|
+
<project>
|
|
233
|
+
<name>java-regression-tests</name>
|
|
234
|
+
<type>git</type>
|
|
235
|
+
<connection>https://github.com/pmd/java-regression-tests</connection>
|
|
236
|
+
<tag>main</tag>
|
|
237
|
+
<auxclasspath-command>realpath java-regression-tests-*.jar</auxclasspath-command>
|
|
238
|
+
<cpd-options>
|
|
239
|
+
<language>java</language>
|
|
240
|
+
<minimum-tokens>100</minimum-tokens>
|
|
241
|
+
<max-memory>512m</max-memory>
|
|
242
|
+
</cpd-options>
|
|
243
|
+
</project>
|
|
244
|
+
|
|
245
|
+
<project>
|
|
246
|
+
<name>OracleDBUtils</name>
|
|
247
|
+
<type>git</type>
|
|
248
|
+
<connection>https://github.com/Qualtagh/OracleDBUtils</connection>
|
|
249
|
+
<tag>0513fe6b053b31e6c09ac6f86eb2064733ecf32d</tag>
|
|
250
|
+
<cpd-options>
|
|
251
|
+
<language>plsql</language>
|
|
252
|
+
<minimum-tokens>100</minimum-tokens>
|
|
253
|
+
<max-memory>512m</max-memory>
|
|
254
|
+
</cpd-options>
|
|
255
|
+
</project>
|
|
256
|
+
|
|
257
|
+
<project>
|
|
258
|
+
<name>alsa-firmware</name>
|
|
259
|
+
<type>git</type>
|
|
260
|
+
<connection>https://github.com/alsa-project/alsa-firmware</connection>
|
|
261
|
+
<tag>v1.2.1</tag>
|
|
262
|
+
<cpd-options>
|
|
263
|
+
<language>cpp</language>
|
|
264
|
+
<minimum-tokens>100</minimum-tokens>
|
|
265
|
+
<max-memory>4g</max-memory>
|
|
266
|
+
</cpd-options>
|
|
267
|
+
</project>
|
|
268
|
+
</projectlist>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
<!-- version 1.3.0 -->
|
|
3
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
4
|
+
<xs:element name="projectlist">
|
|
5
|
+
<xs:complexType>
|
|
6
|
+
<xs:sequence>
|
|
7
|
+
<xs:element name="description" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
|
8
|
+
<xs:element name="project" type="project" minOccurs="1" maxOccurs="unbounded"/>
|
|
9
|
+
</xs:sequence>
|
|
10
|
+
</xs:complexType>
|
|
11
|
+
</xs:element>
|
|
12
|
+
<xs:complexType name="project">
|
|
13
|
+
<xs:sequence>
|
|
14
|
+
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
|
15
|
+
<xs:element name="type" minOccurs="1" maxOccurs="1">
|
|
16
|
+
<xs:simpleType>
|
|
17
|
+
<xs:restriction base="xs:string">
|
|
18
|
+
<xs:enumeration value="git"/>
|
|
19
|
+
</xs:restriction>
|
|
20
|
+
</xs:simpleType>
|
|
21
|
+
</xs:element>
|
|
22
|
+
<xs:element name="connection" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
|
23
|
+
<xs:element name="webview-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
|
24
|
+
<xs:element name="tag" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
|
25
|
+
<xs:element name="src-subpath" type="xs:string" minOccurs="0" maxOccurs="1" default=".">
|
|
26
|
+
<xs:annotation>
|
|
27
|
+
<xs:documentation>
|
|
28
|
+
Value of the -dir option for the PMD run.
|
|
29
|
+
The value must be a directory path relative to the root directory of the clone.
|
|
30
|
+
Defaults to just '.', ie the entire directory.
|
|
31
|
+
</xs:documentation>
|
|
32
|
+
</xs:annotation>
|
|
33
|
+
</xs:element>
|
|
34
|
+
<xs:element name="exclude-pattern" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
|
35
|
+
<xs:element name="build-command" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
|
36
|
+
<xs:element name="auxclasspath-command" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
|
37
|
+
<xs:element name="cpd-options" type="cpd-options" minOccurs="0" maxOccurs="1"/>
|
|
38
|
+
</xs:sequence>
|
|
39
|
+
</xs:complexType>
|
|
40
|
+
<xs:complexType name="cpd-options">
|
|
41
|
+
<xs:sequence>
|
|
42
|
+
<xs:element name="language" type="xs:string" minOccurs="0" maxOccurs="1" default="java"/>
|
|
43
|
+
<xs:element name="minimum-tokens" type="xs:integer" minOccurs="0" maxOccurs="1" default="100"/>
|
|
44
|
+
<xs:element name="max-memory" type="xs:string" minOccurs="0" maxOccurs="1" default="512m"/>
|
|
45
|
+
<xs:element name="directories" type="directories" minOccurs="0" maxOccurs="1"/>
|
|
46
|
+
</xs:sequence>
|
|
47
|
+
</xs:complexType>
|
|
48
|
+
<xs:complexType name="directories">
|
|
49
|
+
<xs:sequence>
|
|
50
|
+
<xs:element name="directory" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
|
|
51
|
+
</xs:sequence>
|
|
52
|
+
</xs:complexType>
|
|
53
|
+
</xs:schema>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PmdTester
|
|
4
|
+
# Turn a CPD project report into a hash that can be rendered somewhere else
|
|
5
|
+
module CpdProjectHasher
|
|
6
|
+
include PmdTester
|
|
7
|
+
|
|
8
|
+
def cpd_report_diff_to_h(cpd_rdiff)
|
|
9
|
+
{
|
|
10
|
+
'duplication_counts' => cpd_rdiff.duplication_counts.to_h.transform_keys(&:to_s),
|
|
11
|
+
'error_counts' => cpd_rdiff.error_counts.to_h.transform_keys(&:to_s),
|
|
12
|
+
|
|
13
|
+
'base_details' => cpd_rdiff.base_report.report_details.to_h,
|
|
14
|
+
'patch_details' => cpd_rdiff.patch_report.report_details.to_h,
|
|
15
|
+
'diff_execution_time' => PmdReportDetail.convert_seconds(cpd_rdiff.patch_report.report_details.execution_time -
|
|
16
|
+
cpd_rdiff.base_report.report_details.execution_time)
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def duplications_to_hash(project, duplications, is_diff)
|
|
21
|
+
filename_index = {}
|
|
22
|
+
duplications.each do |d|
|
|
23
|
+
d.files.each do |f|
|
|
24
|
+
local_path = project.get_local_path(f.path)
|
|
25
|
+
filename_index[local_path] = filename_index.size unless filename_index.include?(local_path)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
duplications_table = duplications.map do |d|
|
|
30
|
+
make_duplication_table(project, filename_index, d, is_diff)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
'file_index' => filename_index.keys,
|
|
35
|
+
'duplications' => duplications_table
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def cpd_errors_to_h(project)
|
|
40
|
+
errors = project.cpd_report_diff.error_diffs
|
|
41
|
+
errors.map { |e| error_to_hash(e, project) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def make_duplication_table(project, filename_index, duplication, is_diff)
|
|
47
|
+
locations = duplication.files.map do |f|
|
|
48
|
+
[filename_index[project.get_local_path(f.path)], f.location.beginline, f.location.endline, f.location.to_s]
|
|
49
|
+
end
|
|
50
|
+
type = if !is_diff || duplication.added?
|
|
51
|
+
'+'
|
|
52
|
+
elsif duplication.changed?
|
|
53
|
+
'~'
|
|
54
|
+
else
|
|
55
|
+
'-'
|
|
56
|
+
end
|
|
57
|
+
[locations, duplication.lines, duplication.tokens, duplication.codefragment,
|
|
58
|
+
type] + generate_old_duplication_info(project, filename_index, duplication, is_diff)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def generate_old_duplication_info(project, filename_index, duplication, is_diff)
|
|
62
|
+
return [] unless is_diff && duplication.changed?
|
|
63
|
+
|
|
64
|
+
old_files = duplication.old_files.map do |f|
|
|
65
|
+
[filename_index[project.get_local_path(f.path)], f.location.beginline, f.location.endline, f.location.to_s]
|
|
66
|
+
end
|
|
67
|
+
[duplication.old_lines, duplication.old_tokens, old_files]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -12,7 +12,7 @@ module PmdTester
|
|
|
12
12
|
def render_liquid(template_path, env)
|
|
13
13
|
to_render = File.read(ResourceLocator.resource(template_path))
|
|
14
14
|
includes = Liquid::LocalFileSystem.new(ResourceLocator.resource('_includes'), '%s.html')
|
|
15
|
-
Liquid::
|
|
15
|
+
Liquid::Environment.default.file_system = includes
|
|
16
16
|
template = Liquid::Template.parse(to_render, error_mode: :strict)
|
|
17
17
|
template.render!(env, { strict_variables: true })
|
|
18
18
|
end
|
|
@@ -43,6 +43,7 @@ module PmdTester
|
|
|
43
43
|
class LiquidProjectRenderer
|
|
44
44
|
include PmdTester
|
|
45
45
|
include ProjectHasher
|
|
46
|
+
include CpdProjectHasher
|
|
46
47
|
include LiquidRenderer
|
|
47
48
|
|
|
48
49
|
def write_project_index(project, root)
|
|
@@ -50,28 +51,65 @@ module PmdTester
|
|
|
50
51
|
'diff' => report_diff_to_h(project.report_diff),
|
|
51
52
|
'error_diffs' => errors_to_h(project),
|
|
52
53
|
'configerror_diffs' => configerrors_to_h(project),
|
|
54
|
+
'cpd_diff' => cpd_report_diff_to_h(project.cpd_report_diff),
|
|
55
|
+
'cpd_error_diffs' => cpd_errors_to_h(project),
|
|
53
56
|
'project_name' => project.name
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
# Renders index.html using liquid
|
|
57
60
|
write_file("#{root}/index.html", render_liquid('project_diff_report.html', liquid_env))
|
|
61
|
+
write_pmd_diff_report(project, root)
|
|
62
|
+
write_pmd_full_report(project, root)
|
|
63
|
+
write_cpd_diff_report(project, root)
|
|
64
|
+
write_cpd_full_report(project, root)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def write_pmd_diff_report(project, root)
|
|
58
70
|
# generate array of violations in json
|
|
59
|
-
write_file("#{root}/
|
|
71
|
+
write_file("#{root}/diff_pmd_data.js", dump_violations_json(project))
|
|
60
72
|
# copy original pmd reports
|
|
61
73
|
copy_file("#{root}/base_pmd_report.xml", project.report_diff.base_report.file)
|
|
62
74
|
copy_file("#{root}/patch_pmd_report.xml", project.report_diff.patch_report.file)
|
|
63
|
-
|
|
64
|
-
copy_file("#{root}/
|
|
65
|
-
|
|
66
|
-
copy_file("#{root}/
|
|
67
|
-
|
|
75
|
+
write_pmd_stdout_stderr(root, project.report_diff)
|
|
76
|
+
copy_file("#{root}/base_pmd_recording.jfr",
|
|
77
|
+
project.report_diff.base_report.report_details.jfr_summary.recording_path)
|
|
78
|
+
copy_file("#{root}/patch_pmd_recording.jfr",
|
|
79
|
+
project.report_diff.patch_report.report_details.jfr_summary.recording_path)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def write_pmd_full_report(project, root)
|
|
68
83
|
# render full pmd reports
|
|
69
84
|
write_file("#{root}/base_pmd_report.html",
|
|
70
85
|
render_liquid('project_pmd_report.html', pmd_report_liquid_env(project, BASE)))
|
|
71
|
-
write_file("#{root}/
|
|
86
|
+
write_file("#{root}/base_pmd_data.js", dump_violations_json(project, BASE))
|
|
72
87
|
write_file("#{root}/patch_pmd_report.html",
|
|
73
88
|
render_liquid('project_pmd_report.html', pmd_report_liquid_env(project, PATCH)))
|
|
74
|
-
write_file("#{root}/
|
|
89
|
+
write_file("#{root}/patch_pmd_data.js", dump_violations_json(project, PATCH))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def write_cpd_diff_report(project, root)
|
|
93
|
+
# generate array of cpd duplications in json
|
|
94
|
+
write_file("#{root}/diff_cpd_data.js", dump_cpd_duplications_json(project, 'diff'))
|
|
95
|
+
# copy original cpd reports
|
|
96
|
+
copy_file("#{root}/base_cpd_report.xml", project.cpd_report_diff.base_report.file)
|
|
97
|
+
copy_file("#{root}/patch_cpd_report.xml", project.cpd_report_diff.patch_report.file)
|
|
98
|
+
write_cpd_stdout_stderr(root, project.cpd_report_diff)
|
|
99
|
+
copy_file("#{root}/base_cpd_recording.jfr",
|
|
100
|
+
project.cpd_report_diff.base_report.report_details.jfr_summary.recording_path)
|
|
101
|
+
copy_file("#{root}/patch_cpd_recording.jfr",
|
|
102
|
+
project.cpd_report_diff.patch_report.report_details.jfr_summary.recording_path)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def write_cpd_full_report(project, root)
|
|
106
|
+
# render full cpd reports
|
|
107
|
+
write_file("#{root}/base_cpd_report.html",
|
|
108
|
+
render_liquid('project_cpd_report.html', cpd_report_liquid_env(project, BASE)))
|
|
109
|
+
write_file("#{root}/base_cpd_data.js", dump_cpd_duplications_json(project, BASE))
|
|
110
|
+
write_file("#{root}/patch_cpd_report.html",
|
|
111
|
+
render_liquid('project_cpd_report.html', cpd_report_liquid_env(project, PATCH)))
|
|
112
|
+
write_file("#{root}/patch_cpd_data.js", dump_cpd_duplications_json(project, PATCH))
|
|
75
113
|
end
|
|
76
114
|
|
|
77
115
|
def dump_violations_json(project, branch = 'diff')
|
|
@@ -89,18 +127,47 @@ module PmdTester
|
|
|
89
127
|
**violations_to_hash(project, violations_by_file, branch == 'diff')
|
|
90
128
|
}
|
|
91
129
|
|
|
92
|
-
project_data = JSON.
|
|
93
|
-
"let
|
|
130
|
+
project_data = JSON.generate(h, object_nl: "\n")
|
|
131
|
+
"let pmd_report = #{project_data}"
|
|
94
132
|
end
|
|
95
133
|
|
|
96
|
-
|
|
134
|
+
def dump_cpd_duplications_json(project, branch)
|
|
135
|
+
duplications = if branch == BASE
|
|
136
|
+
project.cpd_report_diff.base_report.duplications
|
|
137
|
+
elsif branch == PATCH
|
|
138
|
+
project.cpd_report_diff.patch_report.duplications
|
|
139
|
+
else
|
|
140
|
+
project.cpd_report_diff.duplication_diffs
|
|
141
|
+
end
|
|
142
|
+
h = {
|
|
143
|
+
'source_link_base' => project.webview_url,
|
|
144
|
+
'source_link_template' => link_template(project),
|
|
145
|
+
**duplications_to_hash(project, duplications, branch == 'diff')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
"let cpd_report = #{JSON.generate(h, object_nl: "\n")}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def write_pmd_stdout_stderr(root, report_diff)
|
|
152
|
+
write_file("#{root}/base_pmd_stdout.txt", report_diff.base_report.report_details.stdout)
|
|
153
|
+
write_file("#{root}/base_pmd_stderr.txt", report_diff.base_report.report_details.stderr)
|
|
154
|
+
write_file("#{root}/patch_pmd_stdout.txt", report_diff.patch_report.report_details.stdout)
|
|
155
|
+
write_file("#{root}/patch_pmd_stderr.txt", report_diff.patch_report.report_details.stderr)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def write_cpd_stdout_stderr(root, cpd_report_diff)
|
|
159
|
+
write_file("#{root}/base_cpd_stdout.txt", cpd_report_diff.base_report.report_details.stdout)
|
|
160
|
+
write_file("#{root}/base_cpd_stderr.txt", cpd_report_diff.base_report.report_details.stderr)
|
|
161
|
+
write_file("#{root}/patch_cpd_stdout.txt", cpd_report_diff.patch_report.report_details.stdout)
|
|
162
|
+
write_file("#{root}/patch_cpd_stderr.txt", cpd_report_diff.patch_report.report_details.stderr)
|
|
163
|
+
end
|
|
97
164
|
|
|
98
165
|
def copy_file(target_file, source_file)
|
|
99
166
|
if File.exist? source_file
|
|
100
167
|
FileUtils.cp(source_file, target_file)
|
|
101
168
|
logger&.info "Written #{target_file}"
|
|
102
169
|
else
|
|
103
|
-
logger&.warn "
|
|
170
|
+
logger&.warn "Cannot write #{target_file}. Source file #{source_file} not found"
|
|
104
171
|
end
|
|
105
172
|
end
|
|
106
173
|
|
|
@@ -117,20 +184,48 @@ module PmdTester
|
|
|
117
184
|
}
|
|
118
185
|
end
|
|
119
186
|
|
|
187
|
+
def cpd_report_liquid_env(project, branch)
|
|
188
|
+
report = if branch == BASE
|
|
189
|
+
project.cpd_report_diff.base_report
|
|
190
|
+
else
|
|
191
|
+
project.cpd_report_diff.patch_report
|
|
192
|
+
end
|
|
193
|
+
{
|
|
194
|
+
'project_name' => project.name,
|
|
195
|
+
'branch' => branch,
|
|
196
|
+
'cpd_report' => cpd_report_to_h(project, report)
|
|
197
|
+
}
|
|
198
|
+
end
|
|
199
|
+
|
|
120
200
|
def report_to_h(project, report)
|
|
121
201
|
{
|
|
122
202
|
'violation_counts' => report.violations_by_file.total_size,
|
|
123
203
|
'error_counts' => report.errors_by_file.total_size,
|
|
124
204
|
'configerror_counts' => report.configerrors_by_rule.values.flatten.length,
|
|
125
205
|
|
|
126
|
-
'execution_time' =>
|
|
127
|
-
'timestamp' => report.timestamp,
|
|
128
|
-
'exit_code' => report.exit_code,
|
|
206
|
+
'execution_time' => report.report_details.execution_time_formatted,
|
|
207
|
+
'timestamp' => report.report_details.timestamp,
|
|
208
|
+
'exit_code' => report.report_details.exit_code,
|
|
209
|
+
'jfr_summary' => report.report_details.jfr_summary.to_h_for_liquid,
|
|
129
210
|
|
|
130
211
|
'rules' => report.rule_summaries,
|
|
131
212
|
'errors' => report.errors_by_file.all_values.map { |e| error_to_hash(e, project) },
|
|
132
213
|
'configerrors' => report.configerrors_by_rule.values.flatten.map { |e| configerror_to_hash(e) }
|
|
133
214
|
}
|
|
134
215
|
end
|
|
216
|
+
|
|
217
|
+
def cpd_report_to_h(project, cpd_report)
|
|
218
|
+
{
|
|
219
|
+
'duplication_counts' => cpd_report.duplications.length,
|
|
220
|
+
'error_counts' => cpd_report.errors.length,
|
|
221
|
+
|
|
222
|
+
'execution_time' => cpd_report.report_details.execution_time_formatted,
|
|
223
|
+
'timestamp' => cpd_report.report_details.timestamp,
|
|
224
|
+
'exit_code' => cpd_report.report_details.exit_code,
|
|
225
|
+
'jfr_summary' => cpd_report.report_details.jfr_summary.to_h_for_liquid,
|
|
226
|
+
|
|
227
|
+
'errors' => cpd_report.errors.map { |e| error_to_hash(e, project) }
|
|
228
|
+
}
|
|
229
|
+
end
|
|
135
230
|
end
|
|
136
231
|
end
|