pmdtester 1.0.0.pre.beta2 → 1.1.1

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.ci/build.sh +67 -0
  3. data/.ci/files/env.gpg +1 -0
  4. data/.ci/inc/install-openjdk.inc +26 -0
  5. data/.ci/manual-integration-tests.sh +20 -0
  6. data/.github/workflows/build.yml +39 -0
  7. data/.github/workflows/manual-integration-tests.yml +32 -0
  8. data/.gitignore +9 -0
  9. data/.hoerc +1 -0
  10. data/.rubocop.yml +21 -2
  11. data/.rubocop_todo.yml +7 -8
  12. data/.ruby-version +1 -0
  13. data/Gemfile +1 -13
  14. data/History.md +108 -0
  15. data/Manifest.txt +60 -0
  16. data/README.rdoc +130 -7
  17. data/Rakefile +31 -17
  18. data/bin/pmdtester +1 -1
  19. data/config/all-java.xml +1 -1
  20. data/config/design.xml +1 -1
  21. data/config/projectlist_1_0_0.xsd +2 -1
  22. data/config/projectlist_1_1_0.xsd +31 -0
  23. data/lib/pmdtester.rb +48 -0
  24. data/lib/pmdtester/builders/liquid_renderer.rb +73 -0
  25. data/lib/pmdtester/builders/pmd_report_builder.rb +133 -64
  26. data/lib/pmdtester/builders/project_builder.rb +100 -0
  27. data/lib/pmdtester/builders/project_hasher.rb +126 -0
  28. data/lib/pmdtester/builders/rule_set_builder.rb +95 -51
  29. data/lib/pmdtester/builders/simple_progress_logger.rb +27 -0
  30. data/lib/pmdtester/builders/summary_report_builder.rb +62 -120
  31. data/lib/pmdtester/cmd.rb +15 -1
  32. data/lib/pmdtester/collection_by_file.rb +55 -0
  33. data/lib/pmdtester/parsers/options.rb +33 -10
  34. data/lib/pmdtester/parsers/pmd_report_document.rb +79 -29
  35. data/lib/pmdtester/parsers/projects_parser.rb +2 -6
  36. data/lib/pmdtester/pmd_branch_detail.rb +36 -13
  37. data/lib/pmdtester/pmd_configerror.rb +62 -0
  38. data/lib/pmdtester/pmd_error.rb +34 -34
  39. data/lib/pmdtester/pmd_report_detail.rb +10 -13
  40. data/lib/pmdtester/pmd_tester_utils.rb +57 -0
  41. data/lib/pmdtester/pmd_violation.rb +66 -26
  42. data/lib/pmdtester/project.rb +28 -25
  43. data/lib/pmdtester/report_diff.rb +194 -70
  44. data/lib/pmdtester/resource_locator.rb +4 -0
  45. data/lib/pmdtester/runner.rb +82 -57
  46. data/pmdtester.gemspec +64 -0
  47. data/resources/_includes/diff_pill_row.html +6 -0
  48. data/resources/css/bootstrap.min.css +7 -0
  49. data/resources/css/datatables.min.css +36 -0
  50. data/resources/css/pmd-tester.css +131 -0
  51. data/resources/js/bootstrap.min.js +7 -0
  52. data/resources/js/code-snippets.js +66 -0
  53. data/resources/js/datatables.min.js +726 -0
  54. data/resources/js/jquery-3.2.1.slim.min.js +4 -0
  55. data/resources/js/jquery.min.js +2 -0
  56. data/resources/js/popper.min.js +5 -0
  57. data/resources/js/project-report.js +136 -0
  58. data/resources/project_diff_report.html +205 -0
  59. data/resources/project_index.html +102 -0
  60. metadata +117 -44
  61. data/.travis.yml +0 -22
  62. data/lib/pmdtester/builders/diff_builder.rb +0 -35
  63. data/lib/pmdtester/builders/diff_report_builder.rb +0 -226
  64. data/lib/pmdtester/builders/html_report_builder.rb +0 -34
  65. data/lib/pmdtester/pmdtester.rb +0 -17
  66. data/resources/css/maven-base.css +0 -155
  67. data/resources/css/maven-theme.css +0 -171
@@ -1,149 +1,91 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './html_report_builder'
4
- require_relative '../pmd_branch_detail'
5
-
6
3
  module PmdTester
7
4
  # Building summary report to show the details about projects and pmd branchs
8
- class SummaryReportBuilder < HtmlReportBuilder
5
+ class SummaryReportBuilder
9
6
  include PmdTester
10
- REPORT_DIR = 'target/reports/diff'
11
- BASE_CONFIG_PATH = 'target/reports/diff/base_config.xml'
12
- PATCH_CONFIG_PATH = 'target/reports/diff/patch_config.xml'
13
- INDEX_PATH = 'target/reports/diff/index.html'
14
-
15
- def build(projects, base_name, patch_name)
16
- @projects = projects
17
- @base_details = get_branch_details(base_name)
18
- @patch_details = get_branch_details(patch_name)
19
-
20
- FileUtils.mkdir_p(REPORT_DIR) unless File.directory?(REPORT_DIR)
21
- index = File.new(INDEX_PATH, 'w')
7
+ include LiquidRenderer
8
+ include ProjectHasher
22
9
 
23
- html_report = build_html_report('Summary report')
24
- copy_css(REPORT_DIR)
25
-
26
- index.puts html_report
27
- index.close
28
-
29
- logger.info 'Built summary report successfully!'
30
- end
31
-
32
- def get_branch_details(branch_name)
33
- details = PmdBranchDetail.new(branch_name)
34
- details.load
35
- details
36
- end
37
-
38
- def build_body(doc)
39
- build_branch_details_section(doc)
40
- build_projects_section(doc)
41
- end
10
+ REPORT_DIR = 'target/reports/diff'
11
+ BASE_CONFIG_NAME = 'base_config.xml'
12
+ PATCH_CONFIG_NAME = 'patch_config.xml'
42
13
 
43
- def build_branch_details_section(doc)
44
- doc.div(class: 'section', id: 'branchdetails') do
45
- doc.h2 'Branch details:'
46
- 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}")
47
17
  end
48
- end
18
+ logger.info 'Built all difference reports successfully!'
49
19
 
50
- def build_branch_details_table(doc)
51
- doc.table(class: 'bodyTable', border: '0') do
52
- build_branch_table_head(doc)
53
- build_branch_table_body(doc)
54
- end
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}!"
55
25
  end
56
26
 
57
- def build_branch_table_head(doc)
58
- doc.thead do
59
- doc.tr do
60
- doc.th 'Item'
61
- doc.th 'base'
62
- doc.th 'patch'
63
- end
64
- end
65
- end
27
+ private
66
28
 
67
- def build_branch_table_body(doc)
68
- doc.tbody do
69
- build_branch_table_row(doc, 'branch name', @base_details.branch_name,
70
- @patch_details.branch_name)
71
- build_branch_table_row(doc, 'branch last commit sha', @base_details.branch_last_sha,
72
- @patch_details.branch_last_sha)
73
- build_branch_table_row(doc, 'branch last commit message', @base_details.branch_last_message,
74
- @patch_details.branch_last_message)
75
- build_branch_table_row(doc, 'total execution time', @base_details.format_execution_time,
76
- @patch_details.format_execution_time)
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 build_branch_config_table_row(doc)
82
- doc.tr do
83
- doc.td(class: 'c') { doc.text 'branch configuration' }
84
- base_config_src_path = @base_details.target_branch_config_path
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 copy_branch_config_file(src, dest)
98
- FileUtils.cp(src, dest) if File.exist?(src)
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 build_branch_table_row(doc, item, base, patch)
102
- doc.tr do
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 build_projects_section(doc)
110
- doc.div(class: 'section', id: 'projects') do
111
- doc.h2 'Projects:'
112
- build_projects_table(doc)
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
- def build_projects_table(doc)
117
- doc.table(class: 'bodyTable', border: '0') do
118
- build_projects_table_head(doc)
119
- build_projects_table_body(doc)
120
- end
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 build_projects_table_head(doc)
124
- doc.thead do
125
- doc.tr do
126
- doc.th 'project name'
127
- doc.th 'project branch/tag'
128
- doc.th 'diff exist?'
129
- doc.th 'introduce new errors?'
130
- end
131
- 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}"
132
73
  end
133
74
 
134
- def build_projects_table_body(doc)
135
- doc.tbody do
136
- @projects.each do |project|
137
- doc.tr do
138
- doc.td do
139
- doc.a(href: project.diff_report_index_ref_path) { doc.text project.name }
140
- end
141
- doc.td project.tag
142
- doc.td project.diffs_exist? ? 'Yes' : 'No'
143
- doc.td project.introduce_new_errors? ? 'Yes' : 'No'
144
- end
145
- end
146
- 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
+ }
147
89
  end
148
90
  end
149
91
  end
@@ -7,20 +7,34 @@ module PmdTester
7
7
  class Cmd
8
8
  extend PmdTester
9
9
  def self.execute(cmd)
10
+ stdout, _stderr, _status = internal_execute(cmd)
11
+ stdout&.chomp!
12
+ stdout
13
+ end
14
+
15
+ def self.stderr_of(cmd)
16
+ _stdout, stderr, _status = internal_execute(cmd)
17
+ stderr
18
+ end
19
+
20
+ def self.internal_execute(cmd)
10
21
  logger.debug "execute command '#{cmd}'"
11
22
 
12
23
  stdout, stderr, status = Open3.capture3("#{cmd};")
13
24
 
14
25
  logger.debug stdout
15
26
  unless status.success?
27
+ logger.error stdout
16
28
  logger.error stderr
17
29
  raise CmdException.new(cmd, stderr)
18
30
  end
19
31
 
20
32
  stdout&.chomp!
21
33
 
22
- stdout
34
+ [stdout, stderr, status]
23
35
  end
36
+
37
+ private_class_method :internal_execute
24
38
  end
25
39
 
26
40
  # The exception should be raised when the shell command failed.
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PmdTester
4
+ # A collection of things, grouped by file.
5
+ #
6
+ # (Note: this replaces PmdErrors and PmdViolations)
7
+ class CollectionByFile
8
+ def initialize
9
+ # a hash of filename -> [list of items]
10
+ @hash = Hash.new([])
11
+ @total = 0
12
+ end
13
+
14
+ def add_all(filename, values)
15
+ return if values.empty?
16
+
17
+ if @hash.key?(filename)
18
+ @hash[filename].concat(values)
19
+ else
20
+ @hash[filename] = values
21
+ end
22
+ @total += values.size
23
+ end
24
+
25
+ def total_size
26
+ @total
27
+ end
28
+
29
+ def all_files
30
+ @hash.keys
31
+ end
32
+
33
+ def num_files
34
+ @hash.size
35
+ end
36
+
37
+ def all_values
38
+ @hash.values.flatten
39
+ end
40
+
41
+ def each_value(&block)
42
+ @hash.each_value do |vs|
43
+ vs.each(&block)
44
+ end
45
+ end
46
+
47
+ def [](fname)
48
+ @hash[fname]
49
+ end
50
+
51
+ def to_h
52
+ @hash
53
+ end
54
+ end
55
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'slop'
4
- require_relative '../pmdtester'
5
4
 
6
5
  module PmdTester
7
6
  class MissRequiredOptionError < StandardError; end
@@ -15,7 +14,9 @@ module PmdTester
15
14
  LOCAL = 'local'
16
15
  ONLINE = 'online'
17
16
  SINGLE = 'single'
18
- VERSION = '1.0.0-beta2'
17
+ DEFAULT_CONFIG_PATH = ResourceLocator.locate('config/all-java.xml')
18
+ DEFAULT_LIST_PATH = ResourceLocator.locate('config/project-list.xml')
19
+ DEFAULT_BASELINE_URL_PREFIX = 'https://sourceforge.net/projects/pmd/files/pmd-regression-tester/'
19
20
 
20
21
  attr_reader :local_git_repo
21
22
  attr_reader :base_branch
@@ -25,10 +26,14 @@ module PmdTester
25
26
  attr_reader :config
26
27
  attr_reader :project_list
27
28
  attr_reader :mode
29
+ attr_reader :threads
28
30
  attr_reader :html_flag
29
31
  attr_reader :auto_config_flag
30
32
  attr_reader :debug_flag
31
33
  attr_accessor :filter_set
34
+ attr_reader :keep_reports
35
+ attr_reader :error_recovery
36
+ attr_reader :baseline_download_url_prefix
32
37
 
33
38
  def initialize(argv)
34
39
  options = parse(argv)
@@ -40,10 +45,19 @@ module PmdTester
40
45
  @config = options[:c]
41
46
  @project_list = options[:l]
42
47
  @mode = options[:m]
48
+ @threads = options[:t]
43
49
  @html_flag = options[:f]
44
50
  @auto_config_flag = options[:a]
45
51
  @debug_flag = options[:d]
46
52
  @filter_set = nil
53
+ @keep_reports = options.keep_reports?
54
+ @error_recovery = options.error_recovery?
55
+ url = options[:baseline_download_url]
56
+ @baseline_download_url_prefix = if url[-1] == '/'
57
+ url
58
+ else
59
+ "#{url}/"
60
+ end
47
61
 
48
62
  # if the 'config' option is selected then `config` overrides `base_config` and `patch_config`
49
63
  @base_config = @config if !@config.nil? && @mode == 'local'
@@ -61,8 +75,8 @@ module PmdTester
61
75
  single: Set this option to 'single' if your patch branch contains changes
62
76
  for any option that can't work on master/base branch
63
77
  online: Set this option to 'online' if you want to download
64
- 'the PMD report of master/base branch rather than generating it locally
65
- local: Default option is 'local'
78
+ the PMD report of master/base branch rather than generating it locally
79
+ local: Default option is 'local', PMD reports for the base and patch branches are generated locally.
66
80
  DOC
67
81
 
68
82
  Slop.parse argv do |o|
@@ -70,19 +84,31 @@ module PmdTester
70
84
  o.string '-b', '--base-branch', 'name of the base branch in local PMD repository'
71
85
  o.string '-p', '--patch-branch',
72
86
  'name of the patch branch in local PMD repository'
73
- o.string '-bc', '--base-config', 'path to the base PMD configuration file'
74
- o.string '-pc', '--patch-config', 'path to the patch PMD configuration file'
87
+ o.string '-bc', '--base-config', 'path to the base PMD configuration file',
88
+ default: DEFAULT_CONFIG_PATH
89
+ o.string '-pc', '--patch-config', 'path to the patch PMD configuration file',
90
+ default: DEFAULT_CONFIG_PATH
75
91
  o.string '-c', '--config', 'path to the base and patch PMD configuration file'
76
92
  o.string '-l', '--list-of-project',
77
- 'path to the file which contains the list of standard projects'
93
+ 'path to the file which contains the list of standard projects',
94
+ default: DEFAULT_LIST_PATH
78
95
  o.string '-m', '--mode', mode_message, default: 'local'
96
+ o.integer '-t', '--threads', 'Sets the number of threads used by PMD.' \
97
+ ' Set threads to 0 to disable multi-threading processing.', default: 1
79
98
  o.bool '-f', '--html-flag',
80
99
  'whether to not generate the html diff report in single mode'
81
100
  o.bool '-a', '--auto-gen-config',
82
101
  'whether to generate configurations automatically based on branch differences,' \
83
102
  'this option only works in online and local mode'
103
+ o.bool '--keep-reports',
104
+ 'whether to keep old reports and skip running PMD again if possible'
84
105
  o.bool '-d', '--debug',
85
106
  'whether change log level to DEBUG to see more information'
107
+ o.bool '--error-recovery',
108
+ 'enable error recovery mode when executing PMD. Might help to analyze errors.'
109
+ o.string '--baseline-download-url',
110
+ 'download url prefix from where to download the baseline in online mode',
111
+ default: DEFAULT_BASELINE_URL_PREFIX
86
112
  o.on '-v', '--version' do
87
113
  puts VERSION
88
114
  exit
@@ -113,20 +139,17 @@ module PmdTester
113
139
  def check_local_options
114
140
  check_option(LOCAL, 'base branch name', @base_branch)
115
141
  check_option(LOCAL, 'base branch config path', @base_config) unless @auto_config_flag
116
- check_option(LOCAL, 'patch branch name', @patch_branch)
117
142
  check_option(LOCAL, 'patch branch config path', @patch_config) unless @auto_config_flag
118
143
  check_option(LOCAL, 'list of projects file path', @project_list)
119
144
  end
120
145
 
121
146
  def check_single_options
122
- check_option(SINGLE, 'patch branch name', @patch_branch)
123
147
  check_option(SINGLE, 'patch branch config path', @patch_config)
124
148
  check_option(SINGLE, 'list of projects file path', @project_list)
125
149
  end
126
150
 
127
151
  def check_online_options
128
152
  check_option(ONLINE, 'base branch name', @base_branch)
129
- check_option(ONLINE, 'patch branch name', @patch_branch)
130
153
  end
131
154
 
132
155
  def check_common_options
@@ -1,82 +1,132 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'nokogiri'
4
- require_relative '../pmd_violation'
5
- require_relative '../pmd_error'
6
4
  module PmdTester
7
5
  # This class is used for registering types of events you are interested in handling.
8
6
  # Also see: https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/SAX/Document
9
7
  class PmdReportDocument < Nokogiri::XML::SAX::Document
10
8
  attr_reader :violations
11
9
  attr_reader :errors
10
+ attr_reader :configerrors
11
+ attr_reader :infos_by_rules
12
+
12
13
  def initialize(branch_name, working_dir, filter_set = nil)
13
- @violations = PmdViolations.new
14
- @errors = PmdErrors.new
14
+ @violations = CollectionByFile.new
15
+ @errors = CollectionByFile.new
16
+ @configerrors = Hash.new { |hash, key| hash[key] = [] }
17
+
18
+ @infos_by_rules = {}
15
19
  @current_violations = []
16
20
  @current_violation = nil
17
21
  @current_error = nil
18
- @current_element = ''
19
- @filename = ''
22
+ @current_configerror = nil
20
23
  @filter_set = filter_set
21
24
  @working_dir = working_dir
22
25
  @branch_name = branch_name
26
+
27
+ @cur_text = String.new(capacity: 200)
23
28
  end
24
29
 
25
30
  def start_element(name, attrs = [])
26
31
  attrs = attrs.to_h
27
- @current_element = name
28
32
 
29
33
  case name
30
34
  when 'file'
31
- @current_violations = []
32
- @current_filename = remove_work_dir!(attrs['name'])
35
+ handle_start_file attrs
33
36
  when 'violation'
34
- @current_violation = PmdViolation.new(attrs, @branch_name)
37
+ handle_start_violation attrs
35
38
  when 'error'
36
- @current_filename = remove_work_dir!(attrs['filename'])
37
- remove_work_dir!(attrs['msg'])
38
- @current_error = PmdError.new(attrs, @branch_name)
39
+ handle_start_error attrs
40
+ when 'configerror'
41
+ handle_start_configerror attrs
39
42
  end
40
43
  end
41
44
 
42
- def remove_work_dir!(str)
43
- str.sub!(/#{@working_dir}/, '')
45
+ def characters(string)
46
+ @cur_text << remove_work_dir!(string)
44
47
  end
45
48
 
46
- def characters(string)
47
- @current_violation.text = string unless @current_violation.nil?
49
+ def cdata_block(string)
50
+ @cur_text << remove_work_dir!(string)
48
51
  end
49
52
 
50
53
  def end_element(name)
51
54
  case name
52
55
  when 'file'
53
- unless @current_violations.empty?
54
- @violations.add_violations_by_filename(@current_filename, @current_violations)
55
- end
56
+ @violations.add_all(@current_filename, @current_violations)
56
57
  @current_filename = nil
57
58
  when 'violation'
58
- @current_violations.push(@current_violation) if match_filter_set?(@current_violation)
59
+ if match_filter_set?(@current_violation)
60
+ @current_violation.message = finish_text!
61
+ @current_violations.push(@current_violation)
62
+ end
59
63
  @current_violation = nil
60
64
  when 'error'
61
- @errors.add_error_by_filename(@current_filename, @current_error)
65
+ @current_error.stack_trace = finish_text!
66
+ @errors.add_all(@current_filename, [@current_error])
62
67
  @current_filename = nil
63
68
  @current_error = nil
69
+ when 'configerror'
70
+ @configerrors[@current_configerror.rulename].push(@current_configerror)
71
+ @current_configerror = nil
64
72
  end
73
+ @cur_text.clear
65
74
  end
66
75
 
67
- def cdata_block(string)
68
- remove_work_dir!(string)
69
- @current_error.text = string unless @current_error.nil?
76
+ private
77
+
78
+ # Modifies the string in place and returns it
79
+ # (this is what sub! does, except it returns nil if no replacement occurred)
80
+ def remove_work_dir!(str)
81
+ str.sub!(/#{@working_dir}/, '')
82
+ str
83
+ end
84
+
85
+ def finish_text!
86
+ res = @cur_text.strip!.dup.freeze
87
+ @cur_text.clear
88
+ res
70
89
  end
71
90
 
72
91
  def match_filter_set?(violation)
73
92
  return true if @filter_set.nil?
74
93
 
75
- @filter_set.each do |ruleset|
76
- return true if ruleset.eql?(violation.attrs['ruleset'].delete(' ').downcase)
77
- end
94
+ ruleset_attr = violation.ruleset_name.delete(' ').downcase! << '.xml'
95
+ return true if @filter_set.include?(ruleset_attr)
96
+
97
+ rule_ref = "#{ruleset_attr}/#{violation.rule_name}"
98
+
99
+ @filter_set.include?(rule_ref)
100
+ end
101
+
102
+ def handle_start_file(attrs)
103
+ @current_filename = remove_work_dir!(attrs['name'])
104
+ @current_violations = []
105
+ end
106
+
107
+ def handle_start_violation(attrs)
108
+ @current_violation = PmdViolation.new(
109
+ branch: @branch_name,
110
+ fname: @current_filename,
111
+ info_url: attrs['externalInfoUrl'],
112
+ bline: attrs['beginline'].to_i,
113
+ rule_name: attrs['rule'],
114
+ ruleset_name: attrs['ruleset'].freeze
115
+ )
116
+ end
117
+
118
+ def handle_start_error(attrs)
119
+ @current_filename = remove_work_dir!(attrs['filename'])
120
+
121
+ @current_error = PmdError.new(
122
+ branch: @branch_name,
123
+ filename: @current_filename,
124
+ short_message: remove_work_dir!(attrs['msg'])
125
+ )
126
+ end
78
127
 
79
- false
128
+ def handle_start_configerror(attrs)
129
+ @current_configerror = PmdConfigError.new(attrs, @branch_name)
80
130
  end
81
131
  end
82
132
  end