pmdtester 1.1.2 → 1.4.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.ci/build.sh +87 -55
  3. data/.ci/inc/fetch_ci_scripts.bash +19 -0
  4. data/.ci/manual-integration-tests.sh +31 -14
  5. data/.github/workflows/build.yml +26 -9
  6. data/.github/workflows/manual-integration-tests.yml +24 -8
  7. data/.hoerc +1 -1
  8. data/.rubocop.yml +3 -0
  9. data/History.md +31 -0
  10. data/Manifest.txt +4 -2
  11. data/README.rdoc +26 -25
  12. data/Rakefile +11 -6
  13. data/config/project-list.xml +8 -7
  14. data/config/projectlist_1_2_0.xsd +39 -0
  15. data/lib/pmdtester/builders/liquid_renderer.rb +60 -3
  16. data/lib/pmdtester/builders/pmd_report_builder.rb +9 -3
  17. data/lib/pmdtester/builders/project_builder.rb +14 -9
  18. data/lib/pmdtester/builders/project_hasher.rb +41 -39
  19. data/lib/pmdtester/builders/rule_set_builder.rb +116 -75
  20. data/lib/pmdtester/builders/summary_report_builder.rb +1 -0
  21. data/lib/pmdtester/parsers/options.rb +5 -0
  22. data/lib/pmdtester/parsers/pmd_report_document.rb +1 -3
  23. data/lib/pmdtester/parsers/projects_parser.rb +1 -1
  24. data/lib/pmdtester/pmd_branch_detail.rb +6 -0
  25. data/lib/pmdtester/pmd_tester_utils.rb +1 -0
  26. data/lib/pmdtester/pmd_violation.rb +11 -1
  27. data/lib/pmdtester/project.rb +24 -11
  28. data/lib/pmdtester/report_diff.rb +20 -4
  29. data/lib/pmdtester/runner.rb +8 -3
  30. data/lib/pmdtester/semver.rb +36 -0
  31. data/lib/pmdtester.rb +2 -1
  32. data/pmdtester.gemspec +18 -18
  33. data/resources/css/pmd-tester.css +17 -1
  34. data/resources/js/code-snippets.js +48 -15
  35. data/resources/js/project-report.js +5 -3
  36. data/resources/project_diff_report.html +9 -0
  37. data/resources/project_index.html +11 -0
  38. data/resources/project_pmd_report.html +186 -0
  39. metadata +26 -30
  40. data/.ci/files/env.gpg +0 -1
  41. data/.ci/inc/install-openjdk.inc +0 -26
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pathname'
4
+
3
5
  module PmdTester
4
6
  # This class represents all the information about the project
5
7
  class Project
@@ -12,7 +14,8 @@ module PmdTester
12
14
  attr_reader :connection
13
15
  attr_reader :webview_url
14
16
  attr_reader :tag
15
- attr_reader :exclude_pattern
17
+ attr_reader :exclude_patterns
18
+ attr_reader :src_subpath
16
19
  attr_accessor :report_diff
17
20
  # key: pmd branch name as String => value: local path of pmd report
18
21
  attr_reader :build_command
@@ -20,7 +23,7 @@ module PmdTester
20
23
  # stores the auxclasspath calculated after cloning/preparing the project
21
24
  attr_accessor :auxclasspath
22
25
 
23
- def initialize(project)
26
+ def initialize(project) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
24
27
  @name = project.at_xpath('name').text
25
28
  @type = project.at_xpath('type').text
26
29
  @connection = project.at_xpath('connection').text
@@ -31,9 +34,10 @@ module PmdTester
31
34
  @webview_url = default_webview_url
32
35
  @webview_url = webview_url_element.text unless webview_url_element.nil?
33
36
 
34
- @exclude_pattern = []
37
+ @src_subpath = project.at_xpath('src-subpath')&.text || '.'
38
+ @exclude_patterns = []
35
39
  project.xpath('exclude-pattern').each do |ep|
36
- @exclude_pattern.push(ep.text)
40
+ @exclude_patterns.push(ep.text)
37
41
  end
38
42
 
39
43
  @build_command = project.at_xpath('build-command')&.text
@@ -56,17 +60,17 @@ module PmdTester
56
60
  # Change the file path from 'LOCAL_DIR/SOURCE_CODE_PATH' to
57
61
  # 'WEB_VIEW_URL/SOURCE_CODE_PATH'
58
62
  def get_webview_url(file_path)
59
- file_path.gsub(%r{/#{local_source_path}}, @webview_url)
63
+ file_path.gsub(%r{/#{clone_root_path}}, @webview_url)
60
64
  end
61
65
 
62
66
  # Change the file path from 'LOCAL_DIR/SOURCE_CODE_PATH' to
63
67
  # 'PROJECT_NAME/SOURCE_CODE_PATH'
64
68
  def get_path_inside_project(file_path)
65
- file_path.gsub(%r{/#{local_source_path}}, @name)
69
+ file_path.gsub(%r{/#{clone_root_path}}, @name)
66
70
  end
67
71
 
68
72
  def get_local_path(file_path)
69
- file_path.sub(%r{/#{local_source_path}/}, '')
73
+ file_path.sub(%r{/#{clone_root_path}/}, '')
70
74
  end
71
75
 
72
76
  def get_pmd_report_path(branch_name)
@@ -93,6 +97,19 @@ module PmdTester
93
97
  end
94
98
  end
95
99
 
100
+ ##
101
+ # Path to the sources to analyze (below or equal to clone_root_path)
102
+ def local_source_path
103
+ # normalize path
104
+ Pathname.new("#{clone_root_path}/#{src_subpath}").cleanpath
105
+ end
106
+
107
+ ##
108
+ # Path to the clone directory
109
+ def clone_root_path
110
+ "#{REPOSITORIES_PATH}/#{@name}"
111
+ end
112
+
96
113
  def get_project_target_dir(branch_name)
97
114
  branch_filename = PmdBranchDetail.branch_filename(branch_name)
98
115
  dir = "target/reports/#{branch_filename}/#{@name}"
@@ -100,10 +117,6 @@ module PmdTester
100
117
  dir
101
118
  end
102
119
 
103
- def local_source_path
104
- "#{REPOSITORIES_PATH}/#{@name}"
105
- end
106
-
107
120
  def compute_report_diff(base_branch, patch_branch, filter_set)
108
121
  self.report_diff = build_report_diff(get_pmd_report_path(base_branch),
109
122
  get_pmd_report_path(patch_branch),
@@ -57,28 +57,45 @@ module PmdTester
57
57
  :configerrors_by_rule,
58
58
  :exec_time,
59
59
  :timestamp,
60
- :infos_by_rule
60
+ :file
61
61
 
62
62
  def initialize(report_document: nil,
63
+ file: '',
63
64
  exec_time: 0,
64
65
  timestamp: '0')
65
66
  initialize_empty
66
67
  initialize_with_report_document report_document unless report_document.nil?
67
68
  @exec_time = exec_time
68
69
  @timestamp = timestamp
70
+ @file = file
69
71
  end
70
72
 
71
73
  def self.empty
72
74
  new
73
75
  end
74
76
 
77
+ def rule_summaries
78
+ summary = {}
79
+ @violations_by_file.each_value do |violation|
80
+ unless summary.key?(violation.rule_name)
81
+ summary[violation.rule_name] = {
82
+ 'name' => violation.rule_name,
83
+ 'info_url' => violation.info_url,
84
+ 'count' => 0
85
+ }
86
+ end
87
+ summary[violation.rule_name]['count'] += 1
88
+ end
89
+
90
+ summary.values
91
+ end
92
+
75
93
  private
76
94
 
77
95
  def initialize_with_report_document(report_document)
78
96
  @violations_by_file = report_document.violations
79
97
  @errors_by_file = report_document.errors
80
98
  @configerrors_by_rule = report_document.configerrors
81
- @infos_by_rule = report_document.infos_by_rules
82
99
 
83
100
  PmdTester.logger.debug("Loaded #{@violations_by_file.total_size} violations " \
84
101
  "in #{@violations_by_file.num_files} files")
@@ -91,7 +108,6 @@ module PmdTester
91
108
  @violations_by_file = CollectionByFile.new
92
109
  @errors_by_file = CollectionByFile.new
93
110
  @configerrors_by_rule = {}
94
- @infos_by_rule = {}
95
111
  end
96
112
  end
97
113
 
@@ -122,7 +138,7 @@ module PmdTester
122
138
  @error_diffs_by_file = {}
123
139
  @configerror_diffs_by_rule = {}
124
140
 
125
- @rule_infos_union = base_report.infos_by_rule.dup
141
+ @rule_infos_union = {}
126
142
  @base_report = base_report
127
143
  @patch_report = patch_report
128
144
 
@@ -33,8 +33,11 @@ module PmdTester
33
33
  def run_local_mode
34
34
  logger.info "Mode: #{@options.mode}"
35
35
  get_projects(@options.project_list) unless @options.nil?
36
- rule_sets = RuleSetBuilder.new(@options).build if @options.auto_config_flag
37
- return if rule_sets&.empty?
36
+ if @options.auto_config_flag
37
+ run_required = RuleSetBuilder.new(@options).build?
38
+ logger.debug "Run required: #{run_required}"
39
+ return unless run_required
40
+ end
38
41
 
39
42
  base_branch_details = create_pmd_report(config: @options.base_config, branch: @options.base_branch)
40
43
  patch_branch_details = create_pmd_report(config: @options.patch_config, branch: @options.patch_branch)
@@ -51,7 +54,8 @@ module PmdTester
51
54
  get_projects(project_list)
52
55
 
53
56
  if @options.auto_config_flag
54
- return if RuleSetBuilder.new(@options).build.empty?
57
+ logger.info 'Autogenerating a dynamic ruleset based on source changes'
58
+ return unless RuleSetBuilder.new(@options).build?
55
59
  elsif @options.patch_config == Options::DEFAULT_CONFIG_PATH
56
60
  # patch branch build pmd reports with same configuration as base branch
57
61
  # if not specified otherwise. This allows to use a different config (e.g. less rules)
@@ -59,6 +63,7 @@ module PmdTester
59
63
  @options.patch_config = "#{baseline_path}/config.xml"
60
64
  else
61
65
  logger.info "Using config #{@options.patch_config} which might differ from baseline"
66
+ RuleSetBuilder.new(@options).calculate_filter_set if @options.filter_with_patch_config
62
67
  end
63
68
 
64
69
  patch_branch_details = create_pmd_report(config: @options.patch_config, branch: @options.patch_branch)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PmdTester
4
+ # Utility to deal with semantic versions
5
+ class Semver
6
+ def self.compare(version_a, version_b)
7
+ PmdTester.logger.debug "Comparing #{version_a} <=> #{version_b}"
8
+ m = /(\d+)\.(\d+)\.(\d+)(.*)/.match(version_a)
9
+ a_major = m[1].to_i
10
+ a_minor = m[2].to_i
11
+ a_patch = m[3].to_i
12
+ a_snapshot = m[4]
13
+ PmdTester.logger.debug " a_major: #{a_major} a_minor: #{a_minor} a_patch: #{a_patch} a_snapshot: #{a_snapshot}"
14
+
15
+ m = /(\d+)\.(\d+)\.(\d+)(.*)/.match(version_b)
16
+ b_major = m[1].to_i
17
+ b_minor = m[2].to_i
18
+ b_patch = m[3].to_i
19
+ b_snapshot = m[4]
20
+ PmdTester.logger.debug " b_major: #{b_major} b_minor: #{b_minor} b_patch: #{b_patch} b_snapshot: #{b_snapshot}"
21
+
22
+ return a_major <=> b_major if a_major != b_major
23
+ return a_minor <=> b_minor if a_minor != b_minor
24
+ return a_patch <=> b_patch if a_patch != b_patch
25
+
26
+ compare_snapshots(a_snapshot, b_snapshot)
27
+ end
28
+
29
+ private_class_method def self.compare_snapshots(a_snapshot, b_snapshot)
30
+ return -1 if a_snapshot == '-SNAPSHOT' && b_snapshot == ''
31
+ return 1 if a_snapshot == '' && b_snapshot == '-SNAPSHOT'
32
+
33
+ a_snapshot <=> b_snapshot
34
+ end
35
+ end
36
+ end
data/lib/pmdtester.rb CHANGED
@@ -15,6 +15,7 @@ require_relative 'pmdtester/project'
15
15
  require_relative 'pmdtester/report_diff'
16
16
  require_relative 'pmdtester/resource_locator'
17
17
  require_relative 'pmdtester/runner'
18
+ require_relative 'pmdtester/semver'
18
19
 
19
20
  require_relative 'pmdtester/builders/simple_progress_logger'
20
21
  require_relative 'pmdtester/builders/project_builder'
@@ -32,7 +33,7 @@ require_relative 'pmdtester/parsers/projects_parser'
32
33
  # and unexpected behaviors will not be introduced to PMD project
33
34
  # after fixing an issue and new rules can work as expected.
34
35
  module PmdTester
35
- VERSION = '1.1.2'
36
+ VERSION = '1.4.0'
36
37
  BASE = 'base'
37
38
  PATCH = 'patch'
38
39
  PR_NUM_ENV_VAR = 'PMD_CI_PULL_REQUEST_NUMBER' # see PmdBranchDetail
data/pmdtester.gemspec CHANGED
@@ -1,22 +1,22 @@
1
1
  # DO NOT EDIT THIS FILE. Instead, edit Rakefile, and run `rake hoe:spec`.
2
2
 
3
3
  # -*- encoding: utf-8 -*-
4
- # stub: pmdtester 1.1.2 ruby lib
4
+ # stub: pmdtester 1.4.0 ruby lib
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pmdtester".freeze
8
- s.version = "1.1.2"
8
+ s.version = "1.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
11
11
  s.metadata = { "bug_tracker_uri" => "https://github.com/pmd/pmd-regression-tester/issues", "homepage_uri" => "https://pmd.github.io", "source_code_uri" => "https://github.com/pmd/pmd-regression-tester" } if s.respond_to? :metadata=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Andreas Dangel".freeze, "Binguo Bao".freeze, "Cl\u00E9ment Fournier".freeze]
14
- s.date = "2021-04-20"
14
+ s.date = "2022-03-24"
15
15
  s.description = "A regression testing tool ensure that new problems and unexpected behaviors will not be introduced to PMD project after fixing an issue , and new rules can work as expected.".freeze
16
16
  s.email = ["andreas.dangel@pmd-code.org".freeze, "djydewang@gmail.com".freeze, "clement.fournier76@gmail.com".freeze]
17
17
  s.executables = ["pmdtester".freeze]
18
18
  s.extra_rdoc_files = ["History.md".freeze, "Manifest.txt".freeze, "README.rdoc".freeze]
19
- s.files = [".ci/build.sh".freeze, ".ci/files/env.gpg".freeze, ".ci/inc/install-openjdk.inc".freeze, ".ci/manual-integration-tests.sh".freeze, ".github/workflows/build.yml".freeze, ".github/workflows/manual-integration-tests.yml".freeze, ".gitignore".freeze, ".hoerc".freeze, ".rubocop.yml".freeze, ".rubocop_todo.yml".freeze, ".ruby-version".freeze, "Gemfile".freeze, "History.md".freeze, "LICENSE".freeze, "Manifest.txt".freeze, "README.rdoc".freeze, "Rakefile".freeze, "bin/pmdtester".freeze, "config/all-java.xml".freeze, "config/design.xml".freeze, "config/project-list.xml".freeze, "config/projectlist_1_0_0.xsd".freeze, "config/projectlist_1_1_0.xsd".freeze, "lib/pmdtester.rb".freeze, "lib/pmdtester/builders/liquid_renderer.rb".freeze, "lib/pmdtester/builders/pmd_report_builder.rb".freeze, "lib/pmdtester/builders/project_builder.rb".freeze, "lib/pmdtester/builders/project_hasher.rb".freeze, "lib/pmdtester/builders/rule_set_builder.rb".freeze, "lib/pmdtester/builders/simple_progress_logger.rb".freeze, "lib/pmdtester/builders/summary_report_builder.rb".freeze, "lib/pmdtester/cmd.rb".freeze, "lib/pmdtester/collection_by_file.rb".freeze, "lib/pmdtester/parsers/options.rb".freeze, "lib/pmdtester/parsers/pmd_report_document.rb".freeze, "lib/pmdtester/parsers/projects_parser.rb".freeze, "lib/pmdtester/pmd_branch_detail.rb".freeze, "lib/pmdtester/pmd_configerror.rb".freeze, "lib/pmdtester/pmd_error.rb".freeze, "lib/pmdtester/pmd_report_detail.rb".freeze, "lib/pmdtester/pmd_tester_utils.rb".freeze, "lib/pmdtester/pmd_violation.rb".freeze, "lib/pmdtester/project.rb".freeze, "lib/pmdtester/report_diff.rb".freeze, "lib/pmdtester/resource_locator.rb".freeze, "lib/pmdtester/runner.rb".freeze, "pmdtester.gemspec".freeze, "resources/_includes/diff_pill_row.html".freeze, "resources/css/bootstrap.min.css".freeze, "resources/css/datatables.min.css".freeze, "resources/css/pmd-tester.css".freeze, "resources/js/bootstrap.min.js".freeze, "resources/js/code-snippets.js".freeze, "resources/js/datatables.min.js".freeze, "resources/js/jquery-3.2.1.slim.min.js".freeze, "resources/js/jquery.min.js".freeze, "resources/js/popper.min.js".freeze, "resources/js/project-report.js".freeze, "resources/project_diff_report.html".freeze, "resources/project_index.html".freeze]
19
+ s.files = [".ci/build.sh".freeze, ".ci/inc/fetch_ci_scripts.bash".freeze, ".ci/manual-integration-tests.sh".freeze, ".github/workflows/build.yml".freeze, ".github/workflows/manual-integration-tests.yml".freeze, ".gitignore".freeze, ".hoerc".freeze, ".rubocop.yml".freeze, ".rubocop_todo.yml".freeze, ".ruby-version".freeze, "Gemfile".freeze, "History.md".freeze, "LICENSE".freeze, "Manifest.txt".freeze, "README.rdoc".freeze, "Rakefile".freeze, "bin/pmdtester".freeze, "config/all-java.xml".freeze, "config/design.xml".freeze, "config/project-list.xml".freeze, "config/projectlist_1_0_0.xsd".freeze, "config/projectlist_1_1_0.xsd".freeze, "config/projectlist_1_2_0.xsd".freeze, "lib/pmdtester.rb".freeze, "lib/pmdtester/builders/liquid_renderer.rb".freeze, "lib/pmdtester/builders/pmd_report_builder.rb".freeze, "lib/pmdtester/builders/project_builder.rb".freeze, "lib/pmdtester/builders/project_hasher.rb".freeze, "lib/pmdtester/builders/rule_set_builder.rb".freeze, "lib/pmdtester/builders/simple_progress_logger.rb".freeze, "lib/pmdtester/builders/summary_report_builder.rb".freeze, "lib/pmdtester/cmd.rb".freeze, "lib/pmdtester/collection_by_file.rb".freeze, "lib/pmdtester/parsers/options.rb".freeze, "lib/pmdtester/parsers/pmd_report_document.rb".freeze, "lib/pmdtester/parsers/projects_parser.rb".freeze, "lib/pmdtester/pmd_branch_detail.rb".freeze, "lib/pmdtester/pmd_configerror.rb".freeze, "lib/pmdtester/pmd_error.rb".freeze, "lib/pmdtester/pmd_report_detail.rb".freeze, "lib/pmdtester/pmd_tester_utils.rb".freeze, "lib/pmdtester/pmd_violation.rb".freeze, "lib/pmdtester/project.rb".freeze, "lib/pmdtester/report_diff.rb".freeze, "lib/pmdtester/resource_locator.rb".freeze, "lib/pmdtester/runner.rb".freeze, "lib/pmdtester/semver.rb".freeze, "pmdtester.gemspec".freeze, "resources/_includes/diff_pill_row.html".freeze, "resources/css/bootstrap.min.css".freeze, "resources/css/datatables.min.css".freeze, "resources/css/pmd-tester.css".freeze, "resources/js/bootstrap.min.js".freeze, "resources/js/code-snippets.js".freeze, "resources/js/datatables.min.js".freeze, "resources/js/jquery-3.2.1.slim.min.js".freeze, "resources/js/jquery.min.js".freeze, "resources/js/popper.min.js".freeze, "resources/js/project-report.js".freeze, "resources/project_diff_report.html".freeze, "resources/project_index.html".freeze, "resources/project_pmd_report.html".freeze]
20
20
  s.homepage = "https://pmd.github.io".freeze
21
21
  s.licenses = ["BSD-2-Clause".freeze]
22
22
  s.rdoc_options = ["--main".freeze, "README.rdoc".freeze]
@@ -29,35 +29,35 @@ Gem::Specification.new do |s|
29
29
  end
30
30
 
31
31
  if s.respond_to? :add_runtime_dependency then
32
- s.add_runtime_dependency(%q<nokogiri>.freeze, [">= 1.11.0.rc4"])
32
+ s.add_runtime_dependency(%q<nokogiri>.freeze, ["~> 1.13"])
33
33
  s.add_runtime_dependency(%q<slop>.freeze, ["~> 4.6"])
34
34
  s.add_runtime_dependency(%q<differ>.freeze, ["~> 0.1"])
35
- s.add_runtime_dependency(%q<rufus-scheduler>.freeze, ["~> 3.5"])
35
+ s.add_runtime_dependency(%q<rufus-scheduler>.freeze, ["~> 3.8"])
36
36
  s.add_runtime_dependency(%q<logger-colors>.freeze, ["~> 1.0"])
37
- s.add_runtime_dependency(%q<liquid>.freeze, [">= 4.0"])
37
+ s.add_runtime_dependency(%q<liquid>.freeze, ["~> 5.2"])
38
38
  s.add_development_dependency(%q<hoe-bundler>.freeze, ["~> 1.5"])
39
39
  s.add_development_dependency(%q<hoe-git>.freeze, ["~> 1.6"])
40
40
  s.add_development_dependency(%q<minitest>.freeze, ["~> 5.10"])
41
41
  s.add_development_dependency(%q<mocha>.freeze, ["~> 1.5"])
42
- s.add_development_dependency(%q<rubocop>.freeze, ["~> 0.81"])
43
- s.add_development_dependency(%q<test-unit>.freeze, ["~> 3.2"])
44
- s.add_development_dependency(%q<rdoc>.freeze, [">= 4.0", "< 7"])
45
- s.add_development_dependency(%q<hoe>.freeze, ["~> 3.22"])
42
+ s.add_development_dependency(%q<rubocop>.freeze, ["~> 0.93"])
43
+ s.add_development_dependency(%q<test-unit>.freeze, ["~> 3.5"])
44
+ s.add_development_dependency(%q<rdoc>.freeze, ["~> 6.4"])
45
+ s.add_development_dependency(%q<hoe>.freeze, ["~> 3.23"])
46
46
  else
47
- s.add_dependency(%q<nokogiri>.freeze, [">= 1.11.0.rc4"])
47
+ s.add_dependency(%q<nokogiri>.freeze, ["~> 1.13"])
48
48
  s.add_dependency(%q<slop>.freeze, ["~> 4.6"])
49
49
  s.add_dependency(%q<differ>.freeze, ["~> 0.1"])
50
- s.add_dependency(%q<rufus-scheduler>.freeze, ["~> 3.5"])
50
+ s.add_dependency(%q<rufus-scheduler>.freeze, ["~> 3.8"])
51
51
  s.add_dependency(%q<logger-colors>.freeze, ["~> 1.0"])
52
- s.add_dependency(%q<liquid>.freeze, [">= 4.0"])
52
+ s.add_dependency(%q<liquid>.freeze, ["~> 5.2"])
53
53
  s.add_dependency(%q<hoe-bundler>.freeze, ["~> 1.5"])
54
54
  s.add_dependency(%q<hoe-git>.freeze, ["~> 1.6"])
55
55
  s.add_dependency(%q<minitest>.freeze, ["~> 5.10"])
56
56
  s.add_dependency(%q<mocha>.freeze, ["~> 1.5"])
57
- s.add_dependency(%q<rubocop>.freeze, ["~> 0.81"])
58
- s.add_dependency(%q<test-unit>.freeze, ["~> 3.2"])
59
- s.add_dependency(%q<rdoc>.freeze, [">= 4.0", "< 7"])
60
- s.add_dependency(%q<hoe>.freeze, ["~> 3.22"])
57
+ s.add_dependency(%q<rubocop>.freeze, ["~> 0.93"])
58
+ s.add_dependency(%q<test-unit>.freeze, ["~> 3.5"])
59
+ s.add_dependency(%q<rdoc>.freeze, ["~> 6.4"])
60
+ s.add_dependency(%q<hoe>.freeze, ["~> 3.23"])
61
61
  end
62
62
  end
63
63
 
@@ -10,9 +10,25 @@ code {
10
10
  font-size: 13pt;
11
11
  white-space: pre;
12
12
  }
13
- code.highlight {
13
+ code.highlight, tr.highlight {
14
14
  background-color: yellow;
15
15
  }
16
+ table.code-snippet > tbody > tr > td {
17
+ padding: 0px;
18
+ border: none;
19
+ }
20
+ table.code-snippet > tbody > tr > td.line-number > code:before {
21
+ content: attr(data-line-number);
22
+ }
23
+ .btn-clipboard {
24
+ margin-top: 1rem;
25
+ display: block;
26
+ padding: .25rem .5rem;
27
+ color: #0d6efd;
28
+ background-color: #fff;
29
+ border: 1px solid;
30
+ border-radius: .25rem;
31
+ }
16
32
  a {
17
33
  text-decoration: none;
18
34
  }
@@ -15,18 +15,18 @@
15
15
 
16
16
  // returns text, not html
17
17
  function formatLineNumber(number) {
18
- let prefix;
18
+ let prefix = '';
19
19
  if (number < 10) {
20
- prefix = nbsp.repeat(3);
20
+ prefix = nbsp.repeat(3);
21
21
  } else if (number < 100) {
22
- prefix = nbsp.repeat(2);
22
+ prefix = nbsp.repeat(2);
23
23
  } else if (number < 1000) {
24
24
  prefix = nbsp;
25
25
  }
26
26
  return prefix + number;
27
27
  }
28
28
 
29
- function fetchSnippet(document, container, url, line, weburl) {
29
+ function fetchSnippet(document, container, url, violationLineNumber, weburl) {
30
30
  var weburl, requestUrl, oReq;
31
31
 
32
32
  requestUrl = url.replace(/github.com/, "raw.githubusercontent.com");
@@ -34,37 +34,70 @@
34
34
 
35
35
  oReq = new XMLHttpRequest();
36
36
  oReq.addEventListener("load", function() {
37
- let lines, start, deleteCount;
37
+ let lines, start, deleteCount, lineSeparator;
38
38
 
39
39
  // we'll append stuff in the loop below
40
40
  container.innerHTML = '<p><a href="' + weburl + '" target="_blank" rel="noopener noreferrer">' + weburl + '</a></p>';
41
41
 
42
- lines = this.responseText.split(/\r\n|\n/);
43
- start = line - contextLines;
42
+ if (this.responseText.indexOf('\r\n') >= 0) {
43
+ lineSeparator = '\r\n';
44
+ } else {
45
+ lineSeparator = '\n';
46
+ }
47
+ lines = this.responseText.split(lineSeparator);
48
+ start = violationLineNumber - contextLines;
44
49
  if (start > 0) {
45
50
  lines.splice(0, start); // remove lines before
46
51
  }
47
52
  deleteCount = lines.length - (2 * contextLines) + 1;
48
53
  lines.splice(2 * contextLines - 1, deleteCount); // delete lines after
49
54
 
55
+ let table = document.createElement('table');
56
+ table.classList.add('code-snippet');
57
+ let tableBody = document.createElement('tbody');
58
+ table.appendChild(tableBody);
50
59
  // now we have just the lines which will be displayed
51
60
  lines.forEach(line => {
52
61
  start++;
53
- let lineElt = document.createElement("code");
54
- if (start === line) {
55
- lineElt.classList.add("highlight");
62
+ let tableRow = document.createElement('tr');
63
+ if (start === violationLineNumber) {
64
+ tableRow.classList.add("highlight");
56
65
  }
66
+
67
+ let lineNumberColumn = document.createElement('td');
68
+ lineNumberColumn.classList.add('line-number');
69
+ tableRow.appendChild(lineNumberColumn);
70
+ let lineNumberElement = document.createElement('code');
71
+ lineNumberColumn.appendChild(lineNumberElement);
72
+ lineNumberElement.setAttribute('data-line-number', formatLineNumber(start));
73
+
74
+ let codeColumn = document.createElement('td');
75
+ tableRow.appendChild(codeColumn);
76
+ let codeElement = document.createElement("code");
77
+ codeColumn.appendChild(codeElement);
57
78
  // createTextNode escapes special chars
58
- lineElt.appendChild(document.createTextNode(formatLineNumber(start) + nbsp + line));
59
- lineElt.appendChild(document.createElement("br"));
79
+ codeElement.appendChild(document.createTextNode(line));
60
80
 
61
- container.appendChild(lineElt); // append to the container
81
+ tableBody.appendChild(tableRow); // append row to the table
62
82
  });
83
+ container.appendChild(table);
84
+
85
+ if (navigator.clipboard) {
86
+ let copyButton = document.createElement('button');
87
+ copyButton.classList.add('btn-clipboard');
88
+ copyButton.setAttribute('title', 'Copy to clipboard');
89
+ copyButton.appendChild(document.createTextNode('copy'));
90
+ copyButton.onclick = function() {
91
+ navigator.clipboard.writeText(lines.join(lineSeparator));
92
+ }
93
+ container.appendChild(copyButton);
94
+ }
63
95
  });
64
- oReq.open("GET", requestUrl);
65
- oReq.send();
66
96
 
67
97
  container.innerHTML = "<samp>fetching...</samp>";
98
+
99
+ oReq.open("GET", requestUrl);
100
+ oReq.send();
68
101
  }
69
102
 
70
103
  window.pmd_code_snippets = {
@@ -52,12 +52,13 @@ $(document).ready(function () {
52
52
  ],
53
53
  deferRender: true,
54
54
  // scrollY: "6000px",
55
- dom: 'Pfrtip', // Search Panes, filtering input, processing display element, table, table information summary, pagination control
55
+ dom: 'Pfrtipl', // Search Panes, filtering input, processing display element, table, table information summary, pagination control, length changing input control
56
56
  searchPanes: {
57
57
  viewTotal: true,
58
58
  cascadePanes: true,
59
59
  columns: [0, 1, 3],
60
- order: ['Rule', 'Location (click row to expand)', 'Type']
60
+ order: ['Rule', 'Location (click row to expand)', 'Type'],
61
+ threshold: 1 // always show filters in search pane (default: 0.6)
61
62
  },
62
63
  // scrollCollapse: true,
63
64
  // paging: false,
@@ -112,12 +113,13 @@ $(document).ready(function () {
112
113
  },
113
114
  ],
114
115
  displayLength: 25,
116
+ lengthMenu: [ [10, 20, 25, 50, 100, -1], [10, 20, 25, 50, 100, "All"] ],
115
117
  rowCallback(row, data, index) {
116
118
  $(row).addClass(cssClass[data.t]);
117
119
  },
118
120
  });
119
121
 
120
- $('#violationsTable tbody').on('click', 'tr', function() {
122
+ $('#violationsTable tbody').on('click', 'tr[role=row]', function() {
121
123
  var tr = $(this).closest('tr');
122
124
  var row = table.row( tr );
123
125
 
@@ -18,6 +18,9 @@
18
18
 
19
19
  </head>
20
20
  <body>
21
+ <div class="section">
22
+ <h1>PMD Regression Tester Diff Report for {{project_name}}</h1>
23
+ </div>
21
24
  <div class="section">
22
25
  <h2>Summary</h2>
23
26
  <div class="section-content">
@@ -68,6 +71,12 @@
68
71
  <td class="patch">{{diff.patch_timestamp}}</td>
69
72
  <td class="diff"></td>
70
73
  </tr>
74
+ <tr>
75
+ <td class="item">Full Report</td>
76
+ <td class="base"><a href="base_pmd_report.html">Base PMD Report</a></td>
77
+ <td class="patch"><a href="patch_pmd_report.html">Patch PMD Report</a></td>
78
+ <td class="diff"></td>
79
+ </tr>
71
80
  </tbody>
72
81
  </table>
73
82
  </div>
@@ -13,6 +13,12 @@
13
13
  <link rel="stylesheet" href="css/pmd-tester.css">
14
14
  </head>
15
15
  <body>
16
+ <div class="section">
17
+ <h1>PMD Regression Tester Report</h1>
18
+ <p>
19
+ <a href="https://github.com/pmd/pmd-regression-tester">github.com/pmd/pmd-regression-tester</a>
20
+ </p>
21
+ </div>
16
22
  <div class="section">
17
23
  <h2>Branch details</h2>
18
24
  <div class="section-content">
@@ -37,6 +43,11 @@
37
43
  <span class="external-link-secondary"><a href="{{ comparison_url }}">[Compare]</a></span>
38
44
  </td>
39
45
  </tr>
46
+ <tr>
47
+ <td class="item">Timestamp</td>
48
+ <td class="base">{{base.timestamp}}</td>
49
+ <td class="patch">{{patch.timestamp}}</td>
50
+ </tr>
40
51
  <tr>
41
52
  <td class="item">Total PMD runtime</td>
42
53
  <td class="base">{{base.execution_time}}</td>