pmdtester 1.0.0.pre.beta3 → 1.0.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/.hoerc +1 -1
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +7 -8
- data/.travis.yml +20 -2
- data/Gemfile +1 -12
- data/History.md +37 -0
- data/Manifest.txt +6 -0
- data/README.rdoc +72 -46
- data/Rakefile +23 -13
- data/lib/pmdtester.rb +8 -1
- data/lib/pmdtester/builders/diff_builder.rb +8 -7
- data/lib/pmdtester/builders/diff_report/configerrors.rb +50 -0
- data/lib/pmdtester/builders/diff_report/errors.rb +71 -0
- data/lib/pmdtester/builders/diff_report/violations.rb +77 -0
- data/lib/pmdtester/builders/diff_report_builder.rb +23 -149
- data/lib/pmdtester/builders/html_report_builder.rb +23 -0
- data/lib/pmdtester/builders/pmd_report_builder.rb +69 -23
- data/lib/pmdtester/builders/rule_set_builder.rb +3 -2
- data/lib/pmdtester/builders/simple_progress_logger.rb +27 -0
- data/lib/pmdtester/builders/summary_report_builder.rb +19 -5
- data/lib/pmdtester/cmd.rb +15 -1
- data/lib/pmdtester/parsers/options.rb +6 -2
- data/lib/pmdtester/parsers/pmd_report_document.rb +11 -5
- data/lib/pmdtester/pmd_branch_detail.rb +17 -3
- data/lib/pmdtester/pmd_configerror.rb +63 -0
- data/lib/pmdtester/pmd_violation.rb +2 -0
- data/lib/pmdtester/project.rb +35 -3
- data/lib/pmdtester/report_diff.rb +67 -21
- data/lib/pmdtester/runner.rb +40 -15
- data/pmdtester.gemspec +73 -0
- metadata +62 -25
@@ -5,17 +5,18 @@ require 'nokogiri'
|
|
5
5
|
module PmdTester
|
6
6
|
# Building difference between two pmd xml files
|
7
7
|
class DiffBuilder
|
8
|
+
include PmdTester
|
8
9
|
# The schema of pmd xml report refers to
|
9
10
|
# http://pmd.sourceforge.net/report_2_0_0.xsd
|
10
11
|
def build(base_report_filename, patch_report_filename, base_info, patch_info, filter_set = nil)
|
11
12
|
report_diffs = ReportDiff.new
|
12
13
|
base_details, patch_details = report_diffs.calculate_details(base_info, patch_info)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
report_diffs.
|
18
|
-
report_diffs.
|
14
|
+
base_report = parse_pmd_report(base_report_filename, BASE, base_details.working_dir,
|
15
|
+
filter_set)
|
16
|
+
patch_report = parse_pmd_report(patch_report_filename, PATCH, patch_details.working_dir)
|
17
|
+
report_diffs.calculate_violations(base_report.violations, patch_report.violations)
|
18
|
+
report_diffs.calculate_errors(base_report.errors, patch_report.errors)
|
19
|
+
report_diffs.calculate_configerrors(base_report.configerrors, patch_report.configerrors)
|
19
20
|
|
20
21
|
report_diffs
|
21
22
|
end
|
@@ -24,7 +25,7 @@ module PmdTester
|
|
24
25
|
doc = PmdReportDocument.new(branch, working_dir, filter_set)
|
25
26
|
parser = Nokogiri::XML::SAX::Parser.new(doc)
|
26
27
|
parser.parse_file(report_filename) unless report_filename.nil?
|
27
|
-
|
28
|
+
doc
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Contains methods to write out html for the configuration errors.
|
4
|
+
# This mixin is used by DiffReportBuilder.
|
5
|
+
module DiffReportBuilderConfigErrors
|
6
|
+
def build_configerrors_section(doc, configerrors_diffs)
|
7
|
+
doc.div(class: 'section', id: 'configerrors') do
|
8
|
+
doc.h2 'Configuration Errors:'
|
9
|
+
|
10
|
+
doc.h3 PmdTester::HtmlReportBuilder::NO_DIFFERENCES_MESSAGE if configerrors_diffs.empty?
|
11
|
+
configerrors_diffs.each do |key, value|
|
12
|
+
doc.div(class: 'section') do
|
13
|
+
doc.h3 key
|
14
|
+
build_configerrors_table(doc, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_configerrors_table(doc, errors)
|
21
|
+
doc.table(class: 'bodyTable', border: '0') do
|
22
|
+
build_configerrors_table_head(doc)
|
23
|
+
build_configerrors_table_body(doc, errors)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_configerrors_table_head(doc)
|
28
|
+
build_table_head(doc, '', 'Rule', 'Message')
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_configerrors_table_body(doc, errors)
|
32
|
+
doc.tbody do
|
33
|
+
errors.each { |pmd_configerror| build_configerrors_table_row(doc, pmd_configerror) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_configerrors_table_row(doc, pmd_configerror)
|
38
|
+
doc.tr(class: pmd_configerror.branch == PmdTester::BASE ? 'b' : 'a') do
|
39
|
+
build_table_anchor_column(doc, 'C', increment_configerror_index)
|
40
|
+
|
41
|
+
doc.td pmd_configerror.rulename
|
42
|
+
doc.td pmd_configerror.msg
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def increment_configerror_index
|
47
|
+
@configerror_index ||= 0 # init with 0
|
48
|
+
@configerror_index += 1
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Contains methods to write out html for the errors.
|
4
|
+
# This mixin is used by DiffReportBuilder.
|
5
|
+
module DiffReportBuilderErrors
|
6
|
+
def build_errors_section(doc, error_diffs)
|
7
|
+
doc.div(class: 'section', id: 'Errors') do
|
8
|
+
doc.h2 'Errors:'
|
9
|
+
|
10
|
+
doc.h3 PmdTester::HtmlReportBuilder::NO_DIFFERENCES_MESSAGE if error_diffs.empty?
|
11
|
+
error_diffs.each do |key, value|
|
12
|
+
doc.div(class: 'section') do
|
13
|
+
build_filename_h3(doc, key)
|
14
|
+
build_errors_table(doc, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_errors_table(doc, errors)
|
21
|
+
doc.table(class: 'bodyTable', border: '0') do
|
22
|
+
build_errors_table_head(doc)
|
23
|
+
build_errors_table_body(doc, errors)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_errors_table_head(doc)
|
28
|
+
build_table_head(doc, '', 'Message', 'Details')
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_errors_table_body(doc, errors)
|
32
|
+
if PmdTester::ReportDiff.comparable?(errors)
|
33
|
+
# we have only two errors and those are from base and patch, so we
|
34
|
+
# can compare them and display a nice diff
|
35
|
+
pmd_error_a = errors[0]
|
36
|
+
pmd_error_b = errors[1]
|
37
|
+
diff_a = Differ.diff_by_line(pmd_error_a.text, pmd_error_b.text).format_as(:html)
|
38
|
+
diff_b = Differ.diff_by_line(pmd_error_b.text, pmd_error_a.text).format_as(:html)
|
39
|
+
doc.tbody do
|
40
|
+
build_errors_table_row(doc, pmd_error_a, diff_a)
|
41
|
+
build_errors_table_row(doc, pmd_error_b, diff_b)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
# many errors, just report them one by one
|
45
|
+
doc.tbody do
|
46
|
+
errors.each { |pmd_error| build_errors_table_row(doc, pmd_error) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_errors_table_row(doc, pmd_error, text = nil)
|
52
|
+
doc.tr(class: pmd_error.branch == PmdTester::BASE ? 'b' : 'a') do
|
53
|
+
build_table_anchor_column(doc, 'B', increment_error_index)
|
54
|
+
|
55
|
+
text = pmd_error.text if text.nil?
|
56
|
+
|
57
|
+
# The error message
|
58
|
+
doc.td pmd_error.msg
|
59
|
+
doc.td do
|
60
|
+
doc.pre do
|
61
|
+
doc << text
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def increment_error_index
|
68
|
+
@error_index ||= 0 # init with 0
|
69
|
+
@error_index += 1
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Contains methods to write out html for the violations.
|
4
|
+
# This mixin is used by DiffReportBuilder.
|
5
|
+
module DiffReportBuilderViolations
|
6
|
+
def build_violations_section(doc, violation_diffs)
|
7
|
+
doc.div(class: 'section', id: 'Violations') do
|
8
|
+
doc.h2 'Violations:'
|
9
|
+
|
10
|
+
doc.h3 PmdTester::HtmlReportBuilder::NO_DIFFERENCES_MESSAGE if violation_diffs.empty?
|
11
|
+
violation_diffs.each do |key, value|
|
12
|
+
doc.div(class: 'section') do
|
13
|
+
build_filename_h3(doc, key)
|
14
|
+
build_violation_table(doc, key, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_violation_table(doc, key, value)
|
21
|
+
doc.table(class: 'bodyTable', border: '0') do
|
22
|
+
build_violation_table_head(doc)
|
23
|
+
build_violation_table_body(doc, key, value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def build_violation_table_head(doc)
|
28
|
+
build_table_head(doc, '', 'Priority', 'Rule', 'Message', 'Line')
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_violation_table_body(doc, key, value)
|
32
|
+
doc.tbody do
|
33
|
+
value.each do |pmd_violation|
|
34
|
+
build_violation_table_row(doc, key, pmd_violation)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_violation_table_row(doc, key, pmd_violation)
|
40
|
+
doc.tr(class: pmd_violation.branch == PmdTester::BASE ? 'b' : 'a') do
|
41
|
+
build_table_anchor_column(doc, 'A', increment_violation_index)
|
42
|
+
|
43
|
+
violation = pmd_violation.attrs
|
44
|
+
|
45
|
+
# The priority of the rule
|
46
|
+
doc.td violation['priority']
|
47
|
+
|
48
|
+
# The rule that trigger the violation
|
49
|
+
doc.td do
|
50
|
+
doc.a(href: (violation['externalInfoUrl']).to_s) { doc.text violation['rule'] }
|
51
|
+
end
|
52
|
+
|
53
|
+
# The violation message
|
54
|
+
doc.td pmd_violation.text
|
55
|
+
|
56
|
+
# The begin line of the violation
|
57
|
+
line = violation['beginline']
|
58
|
+
|
59
|
+
# The link to the source file
|
60
|
+
doc.td do
|
61
|
+
link = get_link_to_source(violation, key)
|
62
|
+
doc.a(href: link.to_s) { doc.text line }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_link_to_source(violation, key)
|
68
|
+
l_str = @project.type == 'git' ? 'L' : 'l'
|
69
|
+
line_str = "##{l_str}#{violation['beginline']}"
|
70
|
+
@project.get_webview_url(key) + line_str
|
71
|
+
end
|
72
|
+
|
73
|
+
def increment_violation_index
|
74
|
+
@violation_index ||= 0 # init with 0
|
75
|
+
@violation_index += 1
|
76
|
+
end
|
77
|
+
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'nokogiri'
|
4
|
+
require 'differ'
|
4
5
|
|
5
6
|
module PmdTester
|
6
7
|
# Building diff report for a single project
|
7
8
|
class DiffReportBuilder < HtmlReportBuilder
|
8
9
|
include PmdTester
|
9
|
-
|
10
|
+
include DiffReportBuilderViolations
|
11
|
+
include DiffReportBuilderErrors
|
12
|
+
include DiffReportBuilderConfigErrors
|
10
13
|
|
11
14
|
def build(project)
|
12
15
|
@project = project
|
@@ -26,11 +29,13 @@ module PmdTester
|
|
26
29
|
def build_body(doc)
|
27
30
|
violation_diffs = @report_diff.violation_diffs
|
28
31
|
error_diffs = @report_diff.error_diffs
|
32
|
+
configerrors_diffs = @report_diff.configerrors_diffs
|
29
33
|
doc.body(class: 'composite') do
|
30
34
|
doc.div(id: 'contentBox') do
|
31
35
|
build_summary_section(doc)
|
32
36
|
build_violations_section(doc, violation_diffs)
|
33
37
|
build_errors_section(doc, error_diffs)
|
38
|
+
build_configerrors_section(doc, configerrors_diffs)
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
@@ -44,15 +49,7 @@ module PmdTester
|
|
44
49
|
|
45
50
|
def build_summary_table(doc)
|
46
51
|
doc.table(class: 'bodyTable', border: '0') do
|
47
|
-
doc
|
48
|
-
doc.tr do
|
49
|
-
doc.th 'Item'
|
50
|
-
doc.th 'Base'
|
51
|
-
doc.th 'Patch'
|
52
|
-
doc.th 'Difference'
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
52
|
+
build_table_head(doc, 'Item', 'Base', 'Patch', 'Difference')
|
56
53
|
build_summary_table_body(doc)
|
57
54
|
end
|
58
55
|
end
|
@@ -60,9 +57,15 @@ module PmdTester
|
|
60
57
|
def build_summary_table_body(doc)
|
61
58
|
doc.tbody do
|
62
59
|
build_summary_row(doc, 'number of errors', @report_diff.base_errors_size,
|
63
|
-
@report_diff.patch_errors_size, @report_diff.
|
60
|
+
@report_diff.patch_errors_size, @report_diff.removed_errors_size,
|
61
|
+
@report_diff.new_errors_size)
|
64
62
|
build_summary_row(doc, 'number of violations', @report_diff.base_violations_size,
|
65
|
-
@report_diff.patch_violations_size, @report_diff.
|
63
|
+
@report_diff.patch_violations_size, @report_diff.removed_violations_size,
|
64
|
+
@report_diff.new_violations_size)
|
65
|
+
build_summary_row(doc, 'number of config errors', @report_diff.base_configerrors_size,
|
66
|
+
@report_diff.patch_configerrors_size,
|
67
|
+
@report_diff.removed_configerrors_size,
|
68
|
+
@report_diff.new_configerrors_size)
|
66
69
|
build_summary_row(doc, 'execution time', @report_diff.base_execution_time,
|
67
70
|
@report_diff.patch_execution_time, @report_diff.diff_execution_time)
|
68
71
|
build_summary_row(doc, 'timestamp', @report_diff.base_timestamp,
|
@@ -70,12 +73,18 @@ module PmdTester
|
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
73
|
-
def build_summary_row(doc, item, base, patch, diff)
|
76
|
+
def build_summary_row(doc, item, base, patch, *diff)
|
74
77
|
doc.tr do
|
75
78
|
doc.td(class: 'c') { doc.text item }
|
76
79
|
doc.td(class: 'b') { doc.text base }
|
77
80
|
doc.td(class: 'a') { doc.text patch }
|
78
|
-
doc.td(class: 'c')
|
81
|
+
doc.td(class: 'c') do
|
82
|
+
if diff.size == 1
|
83
|
+
doc.text diff[0]
|
84
|
+
else
|
85
|
+
build_table_content_for(doc, diff[0], diff[1])
|
86
|
+
end
|
87
|
+
end
|
79
88
|
end
|
80
89
|
end
|
81
90
|
|
@@ -86,140 +95,5 @@ module PmdTester
|
|
86
95
|
end
|
87
96
|
end
|
88
97
|
end
|
89
|
-
|
90
|
-
def build_violations_section(doc, violation_diffs)
|
91
|
-
doc.div(class: 'section', id: 'Violations') do
|
92
|
-
doc.h2 'Violations:'
|
93
|
-
|
94
|
-
doc.h3 NO_DIFFERENCES_MESSAGE if violation_diffs.empty?
|
95
|
-
violation_diffs.each do |key, value|
|
96
|
-
doc.div(class: 'section') do
|
97
|
-
build_filename_h3(doc, key)
|
98
|
-
build_violation_table(doc, key, value)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def build_violation_table(doc, key, value)
|
105
|
-
doc.table(class: 'bodyTable', border: '0') do
|
106
|
-
build_violation_table_head(doc)
|
107
|
-
build_violation_table_body(doc, key, value)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def build_violation_table_head(doc)
|
112
|
-
doc.thead do
|
113
|
-
doc.tr do
|
114
|
-
doc.th
|
115
|
-
doc.th 'priority'
|
116
|
-
doc.th 'Rule'
|
117
|
-
doc.th 'Message'
|
118
|
-
doc.th 'Line'
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def build_violation_table_body(doc, key, value)
|
124
|
-
doc.tbody do
|
125
|
-
a_index = 1
|
126
|
-
value.each do |pmd_violation|
|
127
|
-
build_violation_table_row(doc, key, pmd_violation, a_index)
|
128
|
-
a_index += 1
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def build_violation_table_row(doc, key, pmd_violation, a_index)
|
134
|
-
doc.tr(class: pmd_violation.branch == 'base' ? 'b' : 'a') do
|
135
|
-
# The anchor
|
136
|
-
doc.td do
|
137
|
-
doc.a(id: "A#{a_index}", href: "#A#{a_index}") { doc.text '#' }
|
138
|
-
end
|
139
|
-
|
140
|
-
violation = pmd_violation.attrs
|
141
|
-
|
142
|
-
# The priority of the rule
|
143
|
-
doc.td violation['priority']
|
144
|
-
|
145
|
-
# The rule that trigger the violation
|
146
|
-
doc.td do
|
147
|
-
doc.a(href: (violation['externalInfoUrl']).to_s) { doc.text violation['rule'] }
|
148
|
-
end
|
149
|
-
|
150
|
-
# The violation message
|
151
|
-
doc.td pmd_violation.text
|
152
|
-
|
153
|
-
# The begin line of the violation
|
154
|
-
line = violation['beginline']
|
155
|
-
|
156
|
-
# The link to the source file
|
157
|
-
doc.td do
|
158
|
-
link = get_link_to_source(violation, key)
|
159
|
-
doc.a(href: link.to_s) { doc.text line }
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def get_link_to_source(violation, key)
|
165
|
-
l_str = @project.type == 'git' ? 'L' : 'l'
|
166
|
-
line_str = "##{l_str}#{violation['beginline']}"
|
167
|
-
@project.get_webview_url(key) + line_str
|
168
|
-
end
|
169
|
-
|
170
|
-
def build_errors_section(doc, error_diffs)
|
171
|
-
doc.div(class: 'section', id: 'Errors') do
|
172
|
-
doc.h2 do
|
173
|
-
doc.text 'Errors:'
|
174
|
-
end
|
175
|
-
|
176
|
-
doc.h3 NO_DIFFERENCES_MESSAGE if error_diffs.empty?
|
177
|
-
error_diffs.each do |key, value|
|
178
|
-
doc.div(class: 'section') do
|
179
|
-
build_filename_h3(doc, key)
|
180
|
-
build_errors_table(doc, value)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def build_errors_table(doc, errors)
|
187
|
-
doc.table(class: 'bodyTable', border: '0') do
|
188
|
-
build_errors_table_head(doc)
|
189
|
-
build_errors_table_body(doc, errors)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def build_errors_table_head(doc)
|
194
|
-
doc.thead do
|
195
|
-
doc.tr do
|
196
|
-
doc.th
|
197
|
-
doc.th 'Message'
|
198
|
-
doc.th 'Details'
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def build_errors_table_body(doc, errors)
|
204
|
-
doc.tbody do
|
205
|
-
b_index = 1
|
206
|
-
errors.each do |pmd_error|
|
207
|
-
doc.tr(class: pmd_error.branch == 'base' ? 'b' : 'a') do
|
208
|
-
# The anchor
|
209
|
-
doc.td do
|
210
|
-
doc.a(id: "B#{b_index}", href: "#B#{b_index}") { doc.text '#' }
|
211
|
-
end
|
212
|
-
|
213
|
-
# The error message
|
214
|
-
doc.td pmd_error.msg
|
215
|
-
|
216
|
-
# Details of error
|
217
|
-
doc.td pmd_error.text
|
218
|
-
|
219
|
-
b_index += 1
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
98
|
end
|
225
99
|
end
|