pmdtester 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ci/build.sh +91 -0
- data/.ci/files/env.gpg +1 -0
- data/.github/workflows/build.yml +39 -0
- data/.gitignore +9 -0
- data/.hoerc +1 -1
- data/.rubocop.yml +6 -2
- data/.ruby-version +1 -0
- data/History.md +40 -0
- data/Manifest.txt +24 -9
- data/README.rdoc +45 -30
- data/Rakefile +5 -3
- data/config/all-java.xml +1 -1
- data/config/design.xml +1 -1
- data/config/projectlist_1_0_0.xsd +2 -1
- data/config/projectlist_1_1_0.xsd +31 -0
- data/lib/pmdtester.rb +8 -7
- data/lib/pmdtester/builders/liquid_renderer.rb +73 -0
- data/lib/pmdtester/builders/pmd_report_builder.rb +102 -78
- data/lib/pmdtester/builders/project_builder.rb +100 -0
- data/lib/pmdtester/builders/project_hasher.rb +126 -0
- data/lib/pmdtester/builders/rule_set_builder.rb +92 -47
- data/lib/pmdtester/builders/simple_progress_logger.rb +4 -4
- data/lib/pmdtester/builders/summary_report_builder.rb +62 -131
- data/lib/pmdtester/collection_by_file.rb +55 -0
- data/lib/pmdtester/parsers/options.rb +19 -0
- data/lib/pmdtester/parsers/pmd_report_document.rb +74 -29
- data/lib/pmdtester/parsers/projects_parser.rb +2 -4
- data/lib/pmdtester/pmd_branch_detail.rb +29 -19
- data/lib/pmdtester/pmd_configerror.rb +23 -24
- data/lib/pmdtester/pmd_error.rb +34 -34
- data/lib/pmdtester/pmd_report_detail.rb +9 -12
- data/lib/pmdtester/pmd_tester_utils.rb +55 -0
- data/lib/pmdtester/pmd_violation.rb +66 -28
- data/lib/pmdtester/project.rb +21 -48
- data/lib/pmdtester/report_diff.rb +179 -111
- data/lib/pmdtester/resource_locator.rb +4 -0
- data/lib/pmdtester/runner.rb +66 -64
- data/pmdtester.gemspec +27 -36
- data/resources/_includes/diff_pill_row.html +6 -0
- data/resources/css/bootstrap.min.css +7 -0
- data/resources/css/datatables.min.css +36 -0
- data/resources/css/pmd-tester.css +131 -0
- data/resources/js/bootstrap.min.js +7 -0
- data/resources/js/code-snippets.js +66 -0
- data/resources/js/datatables.min.js +726 -0
- data/resources/js/jquery-3.2.1.slim.min.js +4 -0
- data/resources/js/jquery.min.js +2 -0
- data/resources/js/popper.min.js +5 -0
- data/resources/js/project-report.js +136 -0
- data/resources/project_diff_report.html +205 -0
- data/resources/project_index.html +102 -0
- metadata +64 -20
- data/.travis.yml +0 -40
- data/lib/pmdtester/builders/diff_builder.rb +0 -31
- data/lib/pmdtester/builders/diff_report/configerrors.rb +0 -50
- data/lib/pmdtester/builders/diff_report/errors.rb +0 -71
- data/lib/pmdtester/builders/diff_report/violations.rb +0 -77
- data/lib/pmdtester/builders/diff_report_builder.rb +0 -99
- data/lib/pmdtester/builders/html_report_builder.rb +0 -56
- data/resources/css/maven-base.css +0 -155
- data/resources/css/maven-theme.css +0 -171
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'differ'
|
4
|
+
|
5
|
+
module PmdTester
|
6
|
+
# Turn a project report into a hash that can be rendered somewhere else
|
7
|
+
module ProjectHasher
|
8
|
+
include PmdTester
|
9
|
+
|
10
|
+
def report_diff_to_h(rdiff)
|
11
|
+
{
|
12
|
+
'violation_counts' => rdiff.violation_counts.to_h,
|
13
|
+
'error_counts' => rdiff.error_counts.to_h,
|
14
|
+
'configerror_counts' => rdiff.configerror_counts.to_h,
|
15
|
+
|
16
|
+
'base_execution_time' => PmdReportDetail.convert_seconds(rdiff.base_report.exec_time),
|
17
|
+
'patch_execution_time' => PmdReportDetail.convert_seconds(rdiff.patch_report.exec_time),
|
18
|
+
'diff_execution_time' => PmdReportDetail.convert_seconds(rdiff.patch_report.exec_time -
|
19
|
+
rdiff.base_report.exec_time),
|
20
|
+
|
21
|
+
'base_timestamp' => rdiff.base_report.timestamp,
|
22
|
+
'patch_timestamp' => rdiff.patch_report.timestamp,
|
23
|
+
|
24
|
+
'rule_diffs' => rdiff.rule_summaries
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def errors_to_h(project)
|
29
|
+
errors = project.report_diff.error_diffs_by_file.values.flatten
|
30
|
+
errors.map { |e| error_to_hash(e, project) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def configerrors_to_h(project)
|
34
|
+
configerrors = project.report_diff.configerror_diffs_by_rule.values.flatten
|
35
|
+
configerrors.map { |e| configerror_to_hash(e) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def violations_to_hash(project)
|
39
|
+
filename_index = []
|
40
|
+
all_vs = []
|
41
|
+
project.report_diff.violation_diffs_by_file.each do |file, vs|
|
42
|
+
file_ref = filename_index.size
|
43
|
+
filename_index.push(project.get_local_path(file))
|
44
|
+
vs.each do |v|
|
45
|
+
all_vs.push(make_violation_hash(file_ref, v))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
{
|
50
|
+
'file_index' => filename_index,
|
51
|
+
'violations' => all_vs
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def link_template(project)
|
56
|
+
l_str = project.type == 'git' ? 'L' : 'l'
|
57
|
+
"#{project.webview_url}/{file}##{l_str}{line}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def violation_type(violation)
|
61
|
+
if violation.changed?
|
62
|
+
'~'
|
63
|
+
elsif violation.branch == 'patch'
|
64
|
+
'+'
|
65
|
+
else
|
66
|
+
'-'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def make_violation_hash(file_ref, violation)
|
71
|
+
h = {
|
72
|
+
't' => violation_type(violation),
|
73
|
+
'l' => violation.line,
|
74
|
+
'f' => file_ref,
|
75
|
+
'r' => violation.rule_name,
|
76
|
+
'm' => violation.changed? ? diff_fragments(violation) : violation.message
|
77
|
+
}
|
78
|
+
h['ol'] = violation.old_line if violation.changed? && violation.line != violation.old_line
|
79
|
+
h
|
80
|
+
end
|
81
|
+
|
82
|
+
def diff_fragments(violation)
|
83
|
+
diff = Differ.diff_by_word(violation.message, violation.old_message)
|
84
|
+
diff.format_as(:html)
|
85
|
+
end
|
86
|
+
|
87
|
+
def error_to_hash(error, project)
|
88
|
+
escaped_stacktrace = sanitize_stacktrace(error)
|
89
|
+
old_stacktrace = error.old_error.nil? ? nil : sanitize_stacktrace(error.old_error)
|
90
|
+
|
91
|
+
{
|
92
|
+
'file_url' => project.get_webview_url(error.filename),
|
93
|
+
'stack_trace_html' => escaped_stacktrace,
|
94
|
+
'old_stack_trace_html' => old_stacktrace,
|
95
|
+
'short_message' => error.short_message,
|
96
|
+
'short_filename' => error.short_filename,
|
97
|
+
'filename' => error.filename,
|
98
|
+
'change_type' => change_type(error)
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def sanitize_stacktrace(error)
|
103
|
+
CGI.escapeHTML(error.stack_trace)
|
104
|
+
.gsub(error.filename, '<span class="meta-var">$FILE</span>')
|
105
|
+
.gsub(/\w++(?=\(\w++\.java:\d++\))/, '<span class="stack-trace-method">\\0</span>')
|
106
|
+
end
|
107
|
+
|
108
|
+
def configerror_to_hash(configerror)
|
109
|
+
{
|
110
|
+
'rule' => configerror.rulename,
|
111
|
+
'message' => configerror.msg,
|
112
|
+
'change_type' => change_type(configerror)
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
def change_type(item)
|
117
|
+
if item.branch == BASE
|
118
|
+
'removed'
|
119
|
+
elsif item.changed?
|
120
|
+
'changed'
|
121
|
+
else
|
122
|
+
'added'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -9,8 +9,9 @@ module PmdTester
|
|
9
9
|
# Attention: we only consider java rulesets now.
|
10
10
|
class RuleSetBuilder
|
11
11
|
include PmdTester
|
12
|
-
|
13
|
-
|
12
|
+
ALL_CATEGORIES = Set['bestpractices.xml', 'codestyle.xml', 'design.xml', 'documentation.xml',
|
13
|
+
'errorprone.xml', 'multithreading.xml', 'performance.xml',
|
14
|
+
'security.xml'].freeze
|
14
15
|
PATH_TO_PMD_JAVA_BASED_RULES =
|
15
16
|
'pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule'
|
16
17
|
PATH_TO_PMD_XPATH_BASED_RULES = 'pmd-java/src/main/resources/category/java'
|
@@ -25,19 +26,35 @@ module PmdTester
|
|
25
26
|
|
26
27
|
def build
|
27
28
|
filenames = diff_filenames
|
28
|
-
|
29
|
-
output_filter_set(
|
30
|
-
build_config_file(
|
31
|
-
logger.debug "Dynamic configuration: #{[
|
32
|
-
|
29
|
+
rule_refs = get_rule_refs(filenames)
|
30
|
+
output_filter_set(rule_refs)
|
31
|
+
build_config_file(rule_refs)
|
32
|
+
logger.debug "Dynamic configuration: #{[rule_refs]}"
|
33
|
+
rule_refs
|
33
34
|
end
|
34
35
|
|
35
|
-
def output_filter_set(
|
36
|
-
if
|
37
|
-
|
38
|
-
|
36
|
+
def output_filter_set(rule_refs)
|
37
|
+
if rule_refs == ALL_CATEGORIES
|
38
|
+
if @options.mode == Options::ONLINE
|
39
|
+
@options.filter_set = Set[]
|
40
|
+
doc = File.open(@options.patch_config) { |f| Nokogiri::XML(f) }
|
41
|
+
rules = doc.css('ruleset rule')
|
42
|
+
rules.each do |r|
|
43
|
+
ref = r.attributes['ref'].content
|
44
|
+
ref.delete_prefix!('category/java/')
|
45
|
+
@options.filter_set.add(ref)
|
46
|
+
end
|
47
|
+
|
48
|
+
logger.debug "Using filter based on patch config #{@options.patch_config}: " \
|
49
|
+
"#{@options.filter_set}"
|
50
|
+
else
|
51
|
+
# if `rule_refs` contains all categories, then no need to filter the baseline
|
52
|
+
logger.debug 'No filter when comparing patch to baseline'
|
53
|
+
@options.filter_set = nil
|
54
|
+
end
|
39
55
|
else
|
40
|
-
|
56
|
+
logger.debug "Filter is now #{rule_refs}"
|
57
|
+
@options.filter_set = rule_refs
|
41
58
|
end
|
42
59
|
end
|
43
60
|
|
@@ -53,58 +70,86 @@ module PmdTester
|
|
53
70
|
filenames.split("\n")
|
54
71
|
end
|
55
72
|
|
56
|
-
def
|
57
|
-
|
73
|
+
def get_rule_refs(filenames)
|
74
|
+
categories, rules = determine_categories_rules(filenames)
|
75
|
+
logger.debug "Categories: #{categories}"
|
76
|
+
logger.debug "Rules: #{rules}"
|
77
|
+
|
78
|
+
# filter out all individual rules that are already covered by a complete category
|
79
|
+
categories.each do |cat|
|
80
|
+
rules.delete_if { |e| e.start_with?(cat) }
|
81
|
+
end
|
82
|
+
|
83
|
+
refs = Set[]
|
84
|
+
refs.merge(categories)
|
85
|
+
refs.merge(rules)
|
86
|
+
refs
|
87
|
+
end
|
88
|
+
|
89
|
+
def determine_categories_rules(filenames)
|
90
|
+
categories = Set[]
|
91
|
+
rules = Set[]
|
58
92
|
filenames.each do |filename|
|
59
|
-
match_data =
|
60
|
-
|
61
|
-
|
93
|
+
match_data = check_single_filename(filename)
|
94
|
+
|
95
|
+
unless match_data.nil?
|
96
|
+
if match_data.size == 2
|
97
|
+
categories.add("#{match_data[1]}.xml")
|
98
|
+
else
|
99
|
+
rules.add("#{match_data[1]}.xml/#{match_data[2]}")
|
100
|
+
end
|
62
101
|
end
|
63
102
|
|
64
|
-
|
65
|
-
nil
|
66
|
-
else
|
67
|
-
match_data[1]
|
68
|
-
end
|
103
|
+
next unless match_data.nil?
|
69
104
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
rule_sets.add(category)
|
75
|
-
end
|
105
|
+
logger.debug "Change doesn't match specific rule/category - enable all rules"
|
106
|
+
categories = ALL_CATEGORIES
|
107
|
+
rules.clear
|
108
|
+
break
|
76
109
|
end
|
77
|
-
|
110
|
+
[categories, rules]
|
78
111
|
end
|
79
112
|
|
80
|
-
def
|
81
|
-
|
113
|
+
def check_single_filename(filename)
|
114
|
+
logger.debug "Checking #{filename}"
|
115
|
+
match_data = %r{#{PATH_TO_PMD_JAVA_BASED_RULES}/([^/]+)/([^/]+)Rule.java}.match(filename)
|
116
|
+
match_data = %r{#{PATH_TO_PMD_XPATH_BASED_RULES}/([^/]+).xml}.match(filename) if match_data.nil?
|
117
|
+
logger.debug "Matches: #{match_data.inspect}"
|
118
|
+
match_data
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_config_file(rule_refs)
|
122
|
+
if rule_refs.empty?
|
82
123
|
logger.info NO_JAVA_RULES_CHANGED_MESSAGE
|
83
124
|
return
|
84
125
|
end
|
85
126
|
|
86
|
-
|
87
|
-
|
88
|
-
|
127
|
+
if rule_refs == ALL_CATEGORIES
|
128
|
+
logger.debug 'All rules are used. Not generating a dynamic ruleset.'
|
129
|
+
logger.debug "Using the configured/default ruleset base_config=#{@options.base_config} "\
|
130
|
+
"patch_config=#{@options.patch_config}"
|
131
|
+
return
|
89
132
|
end
|
90
133
|
|
91
|
-
|
92
|
-
description.content = 'The ruleset generated by PmdTester dynamically'
|
93
|
-
|
94
|
-
write_dynamic_file(doc)
|
134
|
+
write_dynamic_file(rule_refs)
|
95
135
|
end
|
96
136
|
|
97
|
-
def
|
98
|
-
|
99
|
-
|
137
|
+
def write_dynamic_file(rule_refs)
|
138
|
+
logger.debug "Generating dynamic configuration for: #{[rule_refs]}"
|
139
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
140
|
+
xml.ruleset('xmlns' => 'http://pmd.sourceforge.net/ruleset/2.0.0',
|
141
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
142
|
+
'xsi:schemaLocation' => 'http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd',
|
143
|
+
'name' => 'Dynamic PmdTester Ruleset') do
|
144
|
+
xml.description 'The ruleset generated by PmdTester dynamically'
|
145
|
+
rule_refs.each do |entry|
|
146
|
+
xml.rule('ref' => "category/java/#{entry}")
|
147
|
+
end
|
148
|
+
end
|
100
149
|
end
|
101
|
-
|
102
|
-
false
|
103
|
-
end
|
104
|
-
|
105
|
-
def write_dynamic_file(doc)
|
150
|
+
doc = builder.to_xml(indent: 4, encoding: 'UTF-8')
|
106
151
|
File.open(PATH_TO_DYNAMIC_CONFIG, 'w') do |x|
|
107
|
-
x << doc.
|
152
|
+
x << doc.gsub(/\n\s+\n/, "\n")
|
108
153
|
end
|
109
154
|
@options.base_config = PATH_TO_DYNAMIC_CONFIG
|
110
155
|
@options.patch_config = PATH_TO_DYNAMIC_CONFIG
|
@@ -6,16 +6,16 @@ module PmdTester
|
|
6
6
|
# Helper class that provides a simple progress logging
|
7
7
|
class SimpleProgressLogger
|
8
8
|
include PmdTester
|
9
|
-
def initialize(
|
10
|
-
@
|
9
|
+
def initialize(task_name)
|
10
|
+
@task_name = task_name
|
11
11
|
end
|
12
12
|
|
13
13
|
def start
|
14
|
-
logger.info "Starting
|
14
|
+
logger.info "Starting #{@task_name}"
|
15
15
|
message_counter = 1
|
16
16
|
@scheduler = Rufus::Scheduler.new
|
17
17
|
@scheduler.every '2m' do
|
18
|
-
logger.info "Still
|
18
|
+
logger.info "Still #{@task_name} (#{message_counter})..."
|
19
19
|
message_counter += 1
|
20
20
|
end
|
21
21
|
end
|
@@ -2,159 +2,90 @@
|
|
2
2
|
|
3
3
|
module PmdTester
|
4
4
|
# Building summary report to show the details about projects and pmd branchs
|
5
|
-
class SummaryReportBuilder
|
5
|
+
class SummaryReportBuilder
|
6
6
|
include PmdTester
|
7
|
-
|
8
|
-
|
9
|
-
PATCH_CONFIG_PATH = 'target/reports/diff/patch_config.xml'
|
10
|
-
INDEX_PATH = 'target/reports/diff/index.html'
|
11
|
-
|
12
|
-
def build(projects, base_name, patch_name)
|
13
|
-
@projects = projects
|
14
|
-
@base_details = get_branch_details(base_name)
|
15
|
-
@patch_details = get_branch_details(patch_name)
|
16
|
-
|
17
|
-
FileUtils.mkdir_p(REPORT_DIR) unless File.directory?(REPORT_DIR)
|
18
|
-
index = File.new(INDEX_PATH, 'w')
|
19
|
-
|
20
|
-
html_report = build_html_report('Summary report')
|
21
|
-
copy_css(REPORT_DIR)
|
22
|
-
|
23
|
-
index.puts html_report
|
24
|
-
index.close
|
25
|
-
|
26
|
-
logger.info 'Built summary report successfully!'
|
27
|
-
end
|
28
|
-
|
29
|
-
def get_branch_details(branch_name)
|
30
|
-
details = PmdBranchDetail.new(branch_name)
|
31
|
-
details.load
|
32
|
-
end
|
7
|
+
include LiquidRenderer
|
8
|
+
include ProjectHasher
|
33
9
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
10
|
+
REPORT_DIR = 'target/reports/diff'
|
11
|
+
BASE_CONFIG_NAME = 'base_config.xml'
|
12
|
+
PATCH_CONFIG_NAME = 'patch_config.xml'
|
38
13
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
build_branch_details_table(doc)
|
14
|
+
def write_all_projects(projects, base_details, patch_details)
|
15
|
+
projects.each do |project|
|
16
|
+
process_project(project, "#{REPORT_DIR}/#{project.name}")
|
43
17
|
end
|
44
|
-
|
18
|
+
logger.info 'Built all difference reports successfully!'
|
45
19
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
20
|
+
FileUtils.mkdir_p(REPORT_DIR)
|
21
|
+
write_structure(REPORT_DIR)
|
22
|
+
copy_configs(REPORT_DIR, base_details, patch_details)
|
23
|
+
write_index(REPORT_DIR, base_details, patch_details, projects)
|
24
|
+
logger.info "Built summary report successfully in #{REPORT_DIR}!"
|
51
25
|
end
|
52
26
|
|
53
|
-
|
54
|
-
doc.thead do
|
55
|
-
doc.tr do
|
56
|
-
doc.th 'Item'
|
57
|
-
doc.th 'base'
|
58
|
-
doc.th 'patch'
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
27
|
+
private
|
62
28
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
@patch_details.branch_name)
|
67
|
-
build_branch_table_row(doc, 'branch last commit sha', @base_details.branch_last_sha,
|
68
|
-
@patch_details.branch_last_sha)
|
69
|
-
build_branch_table_row(doc, 'branch last commit message', @base_details.branch_last_message,
|
70
|
-
@patch_details.branch_last_message)
|
71
|
-
build_branch_table_row(doc, 'total execution time', @base_details.format_execution_time,
|
72
|
-
@patch_details.format_execution_time)
|
73
|
-
build_branch_table_row(doc, 'jdk version', @base_details.jdk_version,
|
74
|
-
@patch_details.jdk_version)
|
75
|
-
build_branch_table_row(doc, 'language', @base_details.language,
|
76
|
-
@patch_details.language)
|
77
|
-
build_branch_config_table_row(doc)
|
78
|
-
end
|
29
|
+
def process_project(project, dir)
|
30
|
+
logger.info "Rendering #{project.name}..."
|
31
|
+
LiquidProjectRenderer.new.write_project_index(project, dir)
|
79
32
|
end
|
80
33
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
copy_branch_config_file(base_config_src_path, BASE_CONFIG_PATH)
|
86
|
-
doc.td(class: 'a') do
|
87
|
-
doc.a(href: './base_config.xml') { doc.text 'base config' }
|
88
|
-
end
|
89
|
-
patch_config_stc_path = @patch_details.target_branch_config_path
|
90
|
-
FileUtils.cp(patch_config_stc_path, PATCH_CONFIG_PATH)
|
91
|
-
doc.td(class: 'b') do
|
92
|
-
doc.a(href: './patch_config.xml') { doc.text 'patch config' }
|
93
|
-
end
|
94
|
-
end
|
34
|
+
def write_structure(target_root)
|
35
|
+
logger.info 'Copying resources...'
|
36
|
+
copy_resource('css', target_root)
|
37
|
+
copy_resource('js', target_root)
|
95
38
|
end
|
96
39
|
|
97
|
-
def
|
98
|
-
|
40
|
+
def copy_configs(target_root, base_details, patch_details)
|
41
|
+
copy_file(base_details.target_branch_config_path, "#{target_root}/#{BASE_CONFIG_NAME}")
|
42
|
+
copy_file(patch_details.target_branch_config_path, "#{target_root}/#{PATCH_CONFIG_NAME}")
|
99
43
|
end
|
100
44
|
|
101
|
-
def
|
102
|
-
|
103
|
-
doc.td(class: 'c') { doc.text item }
|
104
|
-
doc.td(class: 'a') { doc.text base }
|
105
|
-
doc.td(class: 'b') { doc.text patch }
|
106
|
-
end
|
45
|
+
def copy_file(src, dest)
|
46
|
+
FileUtils.cp(src, dest) if File.exist?(src)
|
107
47
|
end
|
108
48
|
|
109
|
-
def
|
110
|
-
|
111
|
-
|
112
|
-
|
49
|
+
def write_index(target_root, base_details, patch_details, projects)
|
50
|
+
projects = projects.map do |p|
|
51
|
+
{
|
52
|
+
'name' => p.name,
|
53
|
+
'tag' => p.tag,
|
54
|
+
'report_url' => "./#{p.name}/index.html",
|
55
|
+
**report_diff_to_h(p.report_diff)
|
56
|
+
}
|
113
57
|
end
|
114
|
-
end
|
115
58
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
59
|
+
env = {
|
60
|
+
'comparison_url' => create_comparison_url(base_details, patch_details),
|
61
|
+
'base' => to_liquid(base_details, BASE_CONFIG_NAME),
|
62
|
+
'patch' => to_liquid(patch_details, PATCH_CONFIG_NAME),
|
63
|
+
'projects' => projects
|
64
|
+
}
|
65
|
+
logger.info 'Writing /index.html...'
|
66
|
+
render_and_write('project_index.html', "#{target_root}/index.html", env)
|
121
67
|
end
|
122
68
|
|
123
|
-
def
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
doc.th 'project branch/tag'
|
128
|
-
doc.th 'removed|new errors size'
|
129
|
-
doc.th 'removed|new violations size'
|
130
|
-
doc.th 'removed|new configerrors size'
|
131
|
-
end
|
132
|
-
end
|
69
|
+
def create_comparison_url(base_details, patch_details)
|
70
|
+
base = CGI.escape(base_details.branch_name)
|
71
|
+
patch = CGI.escape(patch_details.branch_last_sha)
|
72
|
+
"https://github.com/pmd/pmd/compare/#{base}...#{patch}"
|
133
73
|
end
|
134
74
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
project.new_violations_size)
|
150
|
-
end
|
151
|
-
doc.td do
|
152
|
-
build_table_content_for(doc, project.removed_configerrors_size,
|
153
|
-
project.new_configerrors_size)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
75
|
+
def to_liquid(details, config_name)
|
76
|
+
{
|
77
|
+
'tree_url' => "https://github.com/pmd/pmd/tree/#{CGI.escape(details.branch_last_sha)}",
|
78
|
+
'name' => details.branch_name,
|
79
|
+
'tip' => {
|
80
|
+
'sha' => details.branch_last_sha,
|
81
|
+
'message' => details.branch_last_message
|
82
|
+
},
|
83
|
+
'execution_time' => PmdReportDetail.convert_seconds(details.execution_time),
|
84
|
+
'jdk_info' => details.jdk_version,
|
85
|
+
'locale' => details.language,
|
86
|
+
'config_url' => config_name,
|
87
|
+
'pr_number' => details.pull_request
|
88
|
+
}
|
158
89
|
end
|
159
90
|
end
|
160
91
|
end
|