pmdtester 1.0.0.pre.beta3 → 1.1.2
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 +67 -0
- data/.ci/files/env.gpg +1 -0
- data/.ci/inc/install-openjdk.inc +26 -0
- data/.ci/manual-integration-tests.sh +20 -0
- data/.github/workflows/build.yml +39 -0
- data/.github/workflows/manual-integration-tests.yml +32 -0
- data/.gitignore +9 -0
- data/.hoerc +1 -1
- data/.rubocop.yml +13 -2
- data/.rubocop_todo.yml +7 -8
- data/.ruby-version +1 -0
- data/Gemfile +1 -12
- data/History.md +104 -0
- data/Manifest.txt +30 -6
- data/README.rdoc +110 -60
- data/Rakefile +27 -15
- 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 +12 -4
- data/lib/pmdtester/builders/liquid_renderer.rb +73 -0
- data/lib/pmdtester/builders/pmd_report_builder.rb +134 -60
- 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 +94 -48
- data/lib/pmdtester/builders/simple_progress_logger.rb +27 -0
- data/lib/pmdtester/builders/summary_report_builder.rb +62 -117
- data/lib/pmdtester/cmd.rb +15 -1
- data/lib/pmdtester/collection_by_file.rb +55 -0
- data/lib/pmdtester/parsers/options.rb +25 -2
- data/lib/pmdtester/parsers/pmd_report_document.rb +79 -27
- data/lib/pmdtester/parsers/projects_parser.rb +2 -4
- data/lib/pmdtester/pmd_branch_detail.rb +36 -12
- data/lib/pmdtester/pmd_configerror.rb +62 -0
- data/lib/pmdtester/pmd_error.rb +34 -34
- data/lib/pmdtester/pmd_report_detail.rb +10 -13
- data/lib/pmdtester/pmd_tester_utils.rb +57 -0
- data/lib/pmdtester/pmd_violation.rb +66 -26
- data/lib/pmdtester/project.rb +28 -23
- data/lib/pmdtester/report_diff.rb +194 -70
- data/lib/pmdtester/resource_locator.rb +4 -0
- data/lib/pmdtester/runner.rb +81 -54
- data/pmdtester.gemspec +64 -0
- 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 +132 -0
- data/resources/js/bootstrap.min.js +7 -0
- data/resources/js/code-snippets.js +73 -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 +122 -38
- data/.travis.yml +0 -22
- data/lib/pmdtester/builders/diff_builder.rb +0 -30
- data/lib/pmdtester/builders/diff_report_builder.rb +0 -225
- data/lib/pmdtester/builders/html_report_builder.rb +0 -33
- data/resources/css/maven-base.css +0 -155
- data/resources/css/maven-theme.css +0 -171
@@ -1,78 +1,91 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
+
require 'rufus-scheduler'
|
4
5
|
|
5
6
|
module PmdTester
|
6
7
|
# Building pmd xml reports according to a list of standard
|
7
8
|
# projects and branch of pmd source code
|
8
9
|
class PmdReportBuilder
|
9
10
|
include PmdTester
|
10
|
-
|
11
|
-
|
11
|
+
|
12
|
+
def initialize(projects, options, branch_config, branch_name)
|
12
13
|
@projects = projects
|
13
|
-
@local_git_repo = local_git_repo
|
14
|
-
@
|
14
|
+
@local_git_repo = options.local_git_repo
|
15
|
+
@threads = options.threads
|
16
|
+
@error_recovery = options.error_recovery
|
17
|
+
@branch_config = branch_config
|
18
|
+
@pmd_branch_name = branch_name
|
15
19
|
@pwd = Dir.getwd
|
16
20
|
|
17
|
-
@pmd_branch_details = PmdBranchDetail.new(pmd_branch_name)
|
21
|
+
@pmd_branch_details = PmdBranchDetail.new(@pmd_branch_name)
|
22
|
+
@project_builder = ProjectBuilder.new(@projects)
|
18
23
|
end
|
19
24
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
when 'hg'
|
25
|
-
reset_cmd = "hg up #{tag}"
|
26
|
-
end
|
25
|
+
def get_pmd_binary_file
|
26
|
+
logger.info "#{@pmd_branch_name}: Start packaging PMD"
|
27
|
+
Dir.chdir(@local_git_repo) do
|
28
|
+
build_branch_sha = Cmd.execute("git rev-parse #{@pmd_branch_name}^{commit}")
|
27
29
|
|
28
|
-
|
29
|
-
end
|
30
|
+
checkout_build_branch # needs a clean working tree, otherwise fails
|
30
31
|
|
31
|
-
|
32
|
-
logger.info 'Cloning projects started'
|
32
|
+
raise "Wrong branch #{get_last_commit_sha}" unless build_branch_sha == get_last_commit_sha
|
33
33
|
|
34
|
-
|
35
|
-
logger.
|
36
|
-
|
37
|
-
|
38
|
-
if File.
|
39
|
-
logger.
|
34
|
+
distro_path = saved_distro_path(build_branch_sha)
|
35
|
+
logger.debug "#{@pmd_branch_name}: PMD Version is #{@pmd_version} " \
|
36
|
+
"(sha=#{build_branch_sha})"
|
37
|
+
logger.debug "#{@pmd_branch_name}: distro_path=#{distro_path}"
|
38
|
+
if File.directory?(distro_path)
|
39
|
+
logger.info "#{@pmd_branch_name}: Skipping packaging - saved version exists " \
|
40
|
+
" in #{distro_path}"
|
40
41
|
else
|
41
|
-
|
42
|
+
build_pmd(into_dir: distro_path)
|
42
43
|
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
logger.info "Cloning #{project.name} completed"
|
45
|
+
# we're still on the build branch
|
46
|
+
@pmd_branch_details.branch_last_sha = build_branch_sha
|
47
|
+
@pmd_branch_details.branch_last_message = get_last_commit_message
|
48
48
|
end
|
49
|
+
logger.info "#{@pmd_branch_name}: Packaging PMD completed"
|
49
50
|
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
52
|
+
# builds pmd on currently checked out branch
|
53
|
+
def build_pmd(into_dir:)
|
54
|
+
# in CI there might have been a build performed already. In that case
|
55
|
+
# we reuse the build result, otherwise we build PMD freshly
|
56
|
+
pmd_dist_target = "pmd-dist/target/pmd-bin-#{@pmd_version}.zip"
|
57
|
+
binary_exists = File.exist?(pmd_dist_target)
|
58
|
+
logger.debug "#{@pmd_branch_name}: Does the file #{pmd_dist_target} exist? #{binary_exists} (cwd: #{Dir.getwd})"
|
59
|
+
if binary_exists
|
60
|
+
# that's a warning, because we don't know, whether this build really
|
61
|
+
# belongs to the current branch or whether it's from a previous branch.
|
62
|
+
# In CI, that's not a problem, because the workspace is always fresh.
|
63
|
+
logger.warn "#{@pmd_branch_name}: Reusing already existing #{pmd_dist_target}"
|
64
|
+
else
|
65
|
+
logger.info "#{@pmd_branch_name}: Building PMD #{@pmd_version}..."
|
66
|
+
package_cmd = './mvnw clean package' \
|
67
|
+
' -Dmaven.test.skip=true' \
|
68
|
+
' -Dmaven.javadoc.skip=true' \
|
69
|
+
' -Dmaven.source.skip=true' \
|
70
|
+
' -Dcheckstyle.skip=true' \
|
71
|
+
' -Dpmd.skip=true' \
|
72
|
+
' -T1C'
|
62
73
|
Cmd.execute(package_cmd)
|
74
|
+
end
|
63
75
|
|
64
|
-
|
65
|
-
|
66
|
-
|
76
|
+
logger.info "#{@pmd_branch_name}: Extracting the zip"
|
77
|
+
Cmd.execute("unzip -qo #{pmd_dist_target} -d pmd-dist/target/exploded")
|
78
|
+
Cmd.execute("mv pmd-dist/target/exploded/pmd-bin-#{@pmd_version} #{into_dir}")
|
79
|
+
end
|
67
80
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
81
|
+
def determine_pmd_version
|
82
|
+
version_cmd = "./mvnw -q -Dexec.executable=\"echo\" -Dexec.args='${project.version}' " \
|
83
|
+
'--non-recursive org.codehaus.mojo:exec-maven-plugin:1.5.0:exec'
|
84
|
+
Cmd.execute(version_cmd)
|
72
85
|
end
|
73
86
|
|
74
87
|
def get_last_commit_sha
|
75
|
-
get_last_commit_sha_cmd = 'git rev-parse HEAD'
|
88
|
+
get_last_commit_sha_cmd = 'git rev-parse HEAD^{commit}'
|
76
89
|
Cmd.execute(get_last_commit_sha_cmd)
|
77
90
|
end
|
78
91
|
|
@@ -81,31 +94,55 @@ module PmdTester
|
|
81
94
|
Cmd.execute(get_last_commit_message_cmd)
|
82
95
|
end
|
83
96
|
|
84
|
-
def generate_pmd_report(
|
85
|
-
|
86
|
-
|
87
|
-
|
97
|
+
def generate_pmd_report(project)
|
98
|
+
error_recovery_options = @error_recovery ? 'PMD_JAVA_OPTS="-Dpmd.error_recovery -ea" ' : ''
|
99
|
+
run_path = "#{saved_distro_path(@pmd_branch_details.branch_last_sha)}/bin/run.sh"
|
100
|
+
pmd_cmd = "#{error_recovery_options}" \
|
101
|
+
"#{run_path} pmd -d #{project.local_source_path} -f xml " \
|
102
|
+
"-R #{project.get_config_path(@pmd_branch_name)} " \
|
103
|
+
"-r #{project.get_pmd_report_path(@pmd_branch_name)} " \
|
104
|
+
"-failOnViolation false -t #{@threads} " \
|
105
|
+
"#{project.auxclasspath}"
|
88
106
|
start_time = Time.now
|
89
|
-
|
107
|
+
if File.exist?(project.get_pmd_report_path(@pmd_branch_name))
|
108
|
+
logger.warn "#{@pmd_branch_name}: Skipping PMD run - report " \
|
109
|
+
"#{project.get_pmd_report_path(@pmd_branch_name)} already exists"
|
110
|
+
else
|
111
|
+
Cmd.execute(pmd_cmd)
|
112
|
+
end
|
90
113
|
end_time = Time.now
|
91
114
|
[end_time - start_time, end_time]
|
92
115
|
end
|
93
116
|
|
117
|
+
def generate_config_for(project)
|
118
|
+
logger.debug "Generating ruleset with excludes from #{@branch_config}"
|
119
|
+
doc = Nokogiri::XML(File.read(@branch_config))
|
120
|
+
ruleset = doc.at_css('ruleset')
|
121
|
+
ruleset.add_child("\n")
|
122
|
+
project.exclude_pattern.each do |exclude_pattern|
|
123
|
+
ruleset.add_child(" <exclude-pattern>#{exclude_pattern}</exclude-pattern>\n")
|
124
|
+
end
|
125
|
+
|
126
|
+
File.open(project.get_config_path(@pmd_branch_name), 'w') do |x|
|
127
|
+
x << doc.to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
logger.debug "Created file #{project.get_config_path(@pmd_branch_name)}"
|
131
|
+
end
|
132
|
+
|
94
133
|
def generate_pmd_reports
|
95
134
|
logger.info "Generating PMD report started -- branch #{@pmd_branch_name}"
|
96
|
-
get_pmd_binary_file
|
97
135
|
|
98
136
|
sum_time = 0
|
99
137
|
@projects.each do |project|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
138
|
+
progress_logger = SimpleProgressLogger.new("generating #{project.name}'s PMD report")
|
139
|
+
progress_logger.start
|
140
|
+
generate_config_for(project)
|
141
|
+
execution_time, end_time = generate_pmd_report(project)
|
142
|
+
progress_logger.stop
|
104
143
|
sum_time += execution_time
|
105
144
|
|
106
|
-
report_details = PmdReportDetail.new
|
107
|
-
report_details.execution_time = execution_time
|
108
|
-
report_details.timestamp = end_time
|
145
|
+
report_details = PmdReportDetail.new(execution_time: execution_time, timestamp: end_time)
|
109
146
|
report_details.save(project.get_report_info_path(@pmd_branch_name))
|
110
147
|
logger.info "#{project.name}'s PMD report was generated successfully"
|
111
148
|
end
|
@@ -116,9 +153,46 @@ module PmdTester
|
|
116
153
|
@pmd_branch_details
|
117
154
|
end
|
118
155
|
|
156
|
+
# returns the branch details
|
119
157
|
def build
|
120
|
-
|
158
|
+
@project_builder.clone_projects
|
159
|
+
@project_builder.build_projects
|
160
|
+
get_pmd_binary_file
|
121
161
|
generate_pmd_reports
|
122
162
|
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def checkout_build_branch
|
167
|
+
logger.info "#{@pmd_branch_name}: Checking out the branch"
|
168
|
+
# note that this would fail if the tree is dirty
|
169
|
+
Cmd.execute("git checkout #{@pmd_branch_name}")
|
170
|
+
|
171
|
+
# determine the version
|
172
|
+
@pmd_version = determine_pmd_version
|
173
|
+
|
174
|
+
return unless wd_has_dirty_git_changes
|
175
|
+
|
176
|
+
# working dir is dirty....
|
177
|
+
# we don't allow this because we need the SHA to address the zip file
|
178
|
+
logger.error "#{@pmd_branch_name}: Won\'t build without a clean working tree, " \
|
179
|
+
'commit your changes'
|
180
|
+
end
|
181
|
+
|
182
|
+
def work_dir
|
183
|
+
"#{@pwd}/target"
|
184
|
+
end
|
185
|
+
|
186
|
+
# path to the unzipped distribution
|
187
|
+
# e.g. <cwd>/pmd-bin-<version>-<branch>-<sha>
|
188
|
+
def saved_distro_path(build_sha)
|
189
|
+
"#{work_dir}/pmd-bin-#{@pmd_version}" \
|
190
|
+
"-#{PmdBranchDetail.branch_filename(@pmd_branch_name)}" \
|
191
|
+
"-#{build_sha}"
|
192
|
+
end
|
193
|
+
|
194
|
+
def wd_has_dirty_git_changes
|
195
|
+
!Cmd.execute('git status --porcelain').empty?
|
196
|
+
end
|
123
197
|
end
|
124
198
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
module PmdTester
|
7
|
+
# Clones and builds the projects, that are configured in the project-list.xml
|
8
|
+
class ProjectBuilder
|
9
|
+
include PmdTester
|
10
|
+
|
11
|
+
def initialize(projects)
|
12
|
+
@projects = projects
|
13
|
+
end
|
14
|
+
|
15
|
+
def clone_projects
|
16
|
+
logger.info 'Cloning projects started'
|
17
|
+
|
18
|
+
@projects.each do |project|
|
19
|
+
logger.info "Start cloning #{project.name} repository"
|
20
|
+
path = project.local_source_path
|
21
|
+
clone_cmd = "#{project.type} clone #{project.connection} #{path}"
|
22
|
+
if File.exist?(path)
|
23
|
+
logger.warn "Skipping clone, project path #{path} already exists"
|
24
|
+
else
|
25
|
+
Cmd.execute(clone_cmd)
|
26
|
+
end
|
27
|
+
|
28
|
+
Dir.chdir(path) do
|
29
|
+
execute_reset_cmd(project.type, project.tag)
|
30
|
+
end
|
31
|
+
logger.info "Cloning #{project.name} completed"
|
32
|
+
end
|
33
|
+
|
34
|
+
logger.info 'Cloning projects completed'
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_projects
|
38
|
+
logger.info 'Building projects started'
|
39
|
+
|
40
|
+
@projects.each do |project|
|
41
|
+
path = project.local_source_path
|
42
|
+
Dir.chdir(path) do
|
43
|
+
progress_logger = SimpleProgressLogger.new("building #{project.name} in #{path}")
|
44
|
+
progress_logger.start
|
45
|
+
prepare_project(project)
|
46
|
+
progress_logger.stop
|
47
|
+
end
|
48
|
+
logger.info "Building #{project.name} completed"
|
49
|
+
end
|
50
|
+
|
51
|
+
logger.info 'Building projects completed'
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def prepare_project(project)
|
57
|
+
# Note: current working directory is the project directory,
|
58
|
+
# where the source code has been cloned to
|
59
|
+
if project.build_command
|
60
|
+
logger.debug "Executing build-command: #{project.build_command}"
|
61
|
+
run_as_script(Dir.getwd, project.build_command)
|
62
|
+
end
|
63
|
+
if project.auxclasspath_command
|
64
|
+
logger.debug "Executing auxclasspath-command: #{project.auxclasspath_command}"
|
65
|
+
auxclasspath = run_as_script(Dir.getwd, project.auxclasspath_command)
|
66
|
+
project.auxclasspath = "-auxclasspath #{auxclasspath}"
|
67
|
+
else
|
68
|
+
project.auxclasspath = ''
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_as_script(path, command)
|
73
|
+
script = Tempfile.new(['pmd-regression-', '.sh'], path)
|
74
|
+
logger.debug "Creating script #{script.path}"
|
75
|
+
begin
|
76
|
+
script.write(command)
|
77
|
+
script.close
|
78
|
+
shell = 'sh -xe'
|
79
|
+
if command.start_with?('#!')
|
80
|
+
shell = command.lines[0].chomp[2..] # remove leading "#!"
|
81
|
+
end
|
82
|
+
stdout = Cmd.execute("#{shell} #{script.path}")
|
83
|
+
ensure
|
84
|
+
script.unlink
|
85
|
+
end
|
86
|
+
stdout
|
87
|
+
end
|
88
|
+
|
89
|
+
def execute_reset_cmd(type, tag)
|
90
|
+
case type
|
91
|
+
when 'git'
|
92
|
+
reset_cmd = "git checkout #{tag}; git reset --hard #{tag}"
|
93
|
+
when 'hg'
|
94
|
+
reset_cmd = "hg up #{tag}"
|
95
|
+
end
|
96
|
+
|
97
|
+
Cmd.execute(reset_cmd)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -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.transform_keys(&:to_s),
|
13
|
+
'error_counts' => rdiff.error_counts.to_h.transform_keys(&:to_s),
|
14
|
+
'configerror_counts' => rdiff.configerror_counts.to_h.transform_keys(&:to_s),
|
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
|