pmdtester 1.0.1 → 1.1.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/.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
|