pmdtester 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.ci/build.sh +99 -0
  3. data/.ci/inc/fetch_ci_scripts.bash +19 -0
  4. data/.ci/manual-integration-tests.sh +37 -0
  5. data/.github/workflows/build.yml +55 -0
  6. data/.github/workflows/manual-integration-tests.yml +43 -0
  7. data/.gitignore +9 -0
  8. data/.hoerc +1 -1
  9. data/.rubocop.yml +9 -2
  10. data/.ruby-version +1 -0
  11. data/History.md +79 -0
  12. data/Manifest.txt +28 -9
  13. data/README.rdoc +59 -33
  14. data/Rakefile +7 -5
  15. data/config/all-java.xml +1 -1
  16. data/config/design.xml +1 -1
  17. data/config/project-list.xml +8 -7
  18. data/config/projectlist_1_0_0.xsd +2 -1
  19. data/config/projectlist_1_1_0.xsd +31 -0
  20. data/config/projectlist_1_2_0.xsd +39 -0
  21. data/lib/pmdtester.rb +8 -7
  22. data/lib/pmdtester/builders/liquid_renderer.rb +130 -0
  23. data/lib/pmdtester/builders/pmd_report_builder.rb +107 -79
  24. data/lib/pmdtester/builders/project_builder.rb +105 -0
  25. data/lib/pmdtester/builders/project_hasher.rb +128 -0
  26. data/lib/pmdtester/builders/rule_set_builder.rb +96 -47
  27. data/lib/pmdtester/builders/simple_progress_logger.rb +4 -4
  28. data/lib/pmdtester/builders/summary_report_builder.rb +63 -131
  29. data/lib/pmdtester/collection_by_file.rb +55 -0
  30. data/lib/pmdtester/parsers/options.rb +24 -0
  31. data/lib/pmdtester/parsers/pmd_report_document.rb +72 -28
  32. data/lib/pmdtester/parsers/projects_parser.rb +2 -4
  33. data/lib/pmdtester/pmd_branch_detail.rb +35 -19
  34. data/lib/pmdtester/pmd_configerror.rb +23 -24
  35. data/lib/pmdtester/pmd_error.rb +34 -34
  36. data/lib/pmdtester/pmd_report_detail.rb +10 -13
  37. data/lib/pmdtester/pmd_tester_utils.rb +58 -0
  38. data/lib/pmdtester/pmd_violation.rb +66 -28
  39. data/lib/pmdtester/project.rb +42 -56
  40. data/lib/pmdtester/report_diff.rb +203 -109
  41. data/lib/pmdtester/resource_locator.rb +4 -0
  42. data/lib/pmdtester/runner.rb +67 -64
  43. data/pmdtester.gemspec +28 -37
  44. data/resources/_includes/diff_pill_row.html +6 -0
  45. data/resources/css/bootstrap.min.css +7 -0
  46. data/resources/css/datatables.min.css +36 -0
  47. data/resources/css/pmd-tester.css +132 -0
  48. data/resources/js/bootstrap.min.js +7 -0
  49. data/resources/js/code-snippets.js +73 -0
  50. data/resources/js/datatables.min.js +726 -0
  51. data/resources/js/jquery-3.2.1.slim.min.js +4 -0
  52. data/resources/js/jquery.min.js +2 -0
  53. data/resources/js/popper.min.js +5 -0
  54. data/resources/js/project-report.js +137 -0
  55. data/resources/project_diff_report.html +214 -0
  56. data/resources/project_index.html +113 -0
  57. data/resources/project_pmd_report.html +186 -0
  58. metadata +73 -25
  59. data/.travis.yml +0 -40
  60. data/lib/pmdtester/builders/diff_builder.rb +0 -31
  61. data/lib/pmdtester/builders/diff_report/configerrors.rb +0 -50
  62. data/lib/pmdtester/builders/diff_report/errors.rb +0 -71
  63. data/lib/pmdtester/builders/diff_report/violations.rb +0 -77
  64. data/lib/pmdtester/builders/diff_report_builder.rb +0 -99
  65. data/lib/pmdtester/builders/html_report_builder.rb +0 -56
  66. data/resources/css/maven-base.css +0 -155
  67. data/resources/css/maven-theme.css +0 -171
data/README.rdoc CHANGED
@@ -4,7 +4,9 @@ home :: https://pmd.github.io
4
4
  code :: https://github.com/pmd/pmd-regression-tester
5
5
  bugs :: https://github.com/pmd/pmd-regression-tester/issues
6
6
 
7
- build-status :: {<img src="https://travis-ci.com/pmd/pmd-regression-tester.svg?branch=master" alt="Build Status" />}[https://travis-ci.com/pmd/pmd-regression-tester]
7
+ build-status :: {<img src="https://github.com/pmd/pmd-regression-tester/workflows/build/badge.svg?branch=master" alt="Build Status" />}[https://github.com/pmd/pmd-regression-tester/actions?query=workflow%3Abuild]
8
+
9
+ gem-version :: {<img src="https://badge.fury.io/rb/pmdtester.svg" alt="Gem Version" />}[https://rubygems.org/gems/pmdtester]
8
10
 
9
11
  == DESCRIPTION:
10
12
 
@@ -18,26 +20,30 @@ on a list of standard projects(Spring Framework, Hibernate, Solr, etc.)
18
20
  == SYNOPSIS:
19
21
 
20
22
  === Options:
21
- -r, --local-git-repo path to the local PMD repository
22
- -b, --base-branch name of the base branch in local PMD repository
23
- -p, --patch-branch name of the patch branch in local PMD repository
24
- -bc, --base-config path to the base PMD configuration file default:PMDTESTER_INSTALLED_DIR/config/all-java.xml
25
- -pc, --patch-config path to the patch PMD configuration file default:PMDTESTER_INSTALLED_DIR/config/all-java.xml
26
- -c, --config path to the base and patch PMD configuration file
27
- -l, --list-of-project path to the file which contains the list of standard projects default:PMDTESTER_INSTALLED_DIR/config/project-list.xml
28
- -m, --mode the mode of the tool: 'local', 'online' or 'single'
23
+ -r, --local-git-repo path to the local PMD repository
24
+ -b, --base-branch name of the base branch in local PMD repository
25
+ -p, --patch-branch name of the patch branch in local PMD repository
26
+ -bc, --base-config path to the base PMD configuration file
27
+ -pc, --patch-config path to the patch PMD configuration file
28
+ -c, --config path to the base and patch PMD configuration file
29
+ -l, --list-of-project path to the file which contains the list of standard projects
30
+ -m, --mode the mode of the tool: 'local', 'online' or 'single'
29
31
  single: Set this option to 'single' if your patch branch contains changes
30
32
  for any option that can't work on master/base branch
31
33
  online: Set this option to 'online' if you want to download
32
34
  the PMD report of master/base branch rather than generating it locally
33
35
  local: Default option is 'local', PMD reports for the base and patch branches are generated locally.
34
36
 
35
- -t, --threads Sets the number of threads used by PMD. Set threads to 0 to disable multi-threading processing. default:1
36
- -f, --html-flag whether to not generate the html diff report in single mode
37
- -a, --auto-gen-config whether to generate configurations automatically based on branch differences,this option only works in online and local mode
38
- -d, --debug whether change log level to DEBUG to see more information
39
- -v, --version
40
- -h, --help
37
+ -t, --threads Sets the number of threads used by PMD. Set threads to 0 to disable multi-threading processing.
38
+ -f, --html-flag whether to not generate the html diff report in single mode
39
+ -a, --auto-gen-config whether to generate configurations automatically based on branch differences,this option only works in online and local mode
40
+ --filter-with-patch-config whether to use patch config to filter baseline result as if --auto-gen-config has been used. This option only works in online mode.
41
+ --keep-reports whether to keep old reports and skip running PMD again if possible
42
+ -d, --debug whether change log level to DEBUG to see more information
43
+ --error-recovery enable error recovery mode when executing PMD. Might help to analyze errors.
44
+ --baseline-download-url download url prefix from where to download the baseline in online mode
45
+ -v, --version
46
+ -h, --help
41
47
 
42
48
  === Quick start
43
49
 
@@ -60,19 +66,24 @@ The tool creates the following folders:
60
66
  │ ├── PROJECT_NAME_1
61
67
  │ ├── ......
62
68
  │ └── PROJECT_NAME_n
63
- └── reports
64
- ├── BASE_BRANCH_NAME <- the base baseline is placed here
65
- ├── PATCH_BRANCH_NAME <- the patch baseline is placed here
66
- └── diff
67
- ├── index.xml <- the summary report of diff reports
68
- ├── base_config.xml <- the resources of the summary report
69
- ├── patch_config.xml <- the resources fo the summary report
70
- ├── css <- css reources are placed here
71
- ├── PROJECT_NAME_1
72
- └── index.xml <- the diff report of PROJECT_1
73
- ├── .......
74
- └── PROJECT_NAME_n
75
- └── index.xml <- the diff report of PROJECT_N
69
+ ├── reports
70
+ ├── BASE_BRANCH_NAME <- the base baseline is placed here
71
+ ├── PATCH_BRANCH_NAME <- the patch baseline is placed here
72
+ └── diff
73
+ ├── index.html <- the summary report of diff reports
74
+ ├── base_config.xml <- pmd config from the base branch
75
+ ├── patch_config.xml <- pmd config from the patch branch
76
+ ├── css <- css resources are placed here
77
+ ├── js <- js resources
78
+ │ ├── PROJECT_NAME_1
79
+ │ │ ├── project_data.js <- contains the violations as js/json
80
+ │ │ └── index.html <- the diff report of PROJECT_1
81
+ │ ├── .......
82
+ │ └── PROJECT_NAME_n
83
+ │ ├── project_data.js <- contains the violations as js/json
84
+ │ └── index.xml <- the diff report of PROJECT_N
85
+ ├── pmd-bin-<version>-<branch_name>-<sha1> <- cached pmd builds that are reused
86
+ └── pmd-bin-....
76
87
 
77
88
  ==== The baseline format
78
89
  branch_name
@@ -90,14 +101,16 @@ The tool creates the following folders:
90
101
 
91
102
  == REQUIREMENTS:
92
103
 
93
- * Ruby 2.4.1 or higher
104
+ * Ruby 2.7 or higher
94
105
 
95
106
  === Runtime dependency
96
107
 
97
- nokogiri ~> 1.8
108
+ nokogiri >= 1.11.0.rc4
98
109
  slop ~> 4.6
99
110
  differ ~> 0.1
100
111
  rufus-scheduler ~> 3.5
112
+ logger-colors ~> 1.0
113
+ liquid >= 4.0
101
114
 
102
115
  === Development dependency
103
116
 
@@ -122,11 +135,24 @@ The tool creates the following folders:
122
135
  bundle install # once
123
136
  bundle exec rake verify # run this command before commit your changes
124
137
  bundle exec pmdtester ... # run this to directly execute pmdtester from source
138
+
139
+ Run a single test class, e.g.:
140
+ bundle exec ruby -I test test/test_diff_report_builder.rb
141
+
142
+ Run a single test, e.g.:
143
+ bundle exec ruby -I test test/test_diff_report_builder.rb -n test_diff_report_builder
125
144
 
126
145
  === Releasing
127
146
 
128
147
  * Update +History.md+ (version and date)
129
148
  * Update +lib/pmdtester.rb+ (version)
130
- * Commit ("Prepare release x.y.z"), tag, push. Travis will build and publish the new gem.
131
- * Update History.md and lib/pmdtester.rb for the next development version
132
- ("Prepare next development version x.y.z-SNAPSHOT").
149
+ * Run "bundle exec rake verify" and add new +pmdtester.gemspec+ (new version)
150
+ * Commit ("Prepare release x.y.z").
151
+ * Tag this commit ("git tag vx.y.z").
152
+ * Update History.md and lib/pmdtester.rb for the next development version,
153
+ run again "bundle exec rake verify"
154
+ * Commit ("Prepare next development version x.y.z-SNAPSHOT").
155
+ * Push to master.
156
+ * Push the tag. Github Actions will build and publish the new gem
157
+ * A github release is automatically created, verify it on https://github.com/pmd/pmd-regression-tester/releases
158
+ * To make pmd's main CI use the new version (in [pmd/pmd](https://github.com/pmd/pmd/)), go to the root directory and run `bundle lock --update`. Commit these changes.
data/Rakefile CHANGED
@@ -14,12 +14,14 @@ Hoe.plugin :git
14
14
  hoe = Hoe.spec 'pmdtester' do
15
15
  self.version = PmdTester::VERSION
16
16
 
17
- developer 'Andreas Dangel', 'andreas.dangel@adangel.org'
17
+ developer 'Andreas Dangel', 'andreas.dangel@pmd-code.org'
18
18
  developer 'Binguo Bao', 'djydewang@gmail.com'
19
+ developer 'Clément Fournier', 'clement.fournier76@gmail.com'
19
20
 
20
- self.clean_globs = %w[target/reports/**/* target/test/**/* Gemfile.lock]
21
- self.extra_deps += [['nokogiri', '~> 1.8'], ['slop', '~> 4.6'], ['differ', '~> 0.1'],
22
- ['rufus-scheduler', '~> 3.5']]
21
+ self.clean_globs = %w[target/reports/**/* target/test/**/* target/dynamic-config.xml Gemfile.lock]
22
+ self.extra_deps += [['nokogiri', '>= 1.11.0.rc4'], ['slop', '~> 4.6'], ['differ', '~> 0.1'],
23
+ ['rufus-scheduler', '~> 3.5'], ['logger-colors', '~> 1.0'],
24
+ ['liquid', '>= 4.0']]
23
25
  self.extra_dev_deps += [
24
26
  ['hoe-bundler', '~> 1.5'],
25
27
  ['hoe-git', '~> 1.6'],
@@ -30,7 +32,7 @@ hoe = Hoe.spec 'pmdtester' do
30
32
  ['test-unit', '~> 3.2'],
31
33
  ['rdoc', ['>= 4.0', '< 7']]
32
34
  ]
33
- spec_extras[:required_ruby_version] = '>= 2.2'
35
+ spec_extras[:required_ruby_version] = '>= 2.7'
34
36
 
35
37
  license 'BSD-2-Clause'
36
38
  end
data/config/all-java.xml CHANGED
@@ -3,7 +3,7 @@
3
3
  <ruleset name="All Java Rules"
4
4
  xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
5
5
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6
- xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
6
+ xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
7
7
  <description>Every Java Rule in PMD</description>
8
8
 
9
9
  <rule ref="category/java/bestpractices.xml" />
data/config/design.xml CHANGED
@@ -3,7 +3,7 @@
3
3
  <ruleset name="Design"
4
4
  xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
5
5
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6
- xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
6
+ xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
7
7
 
8
8
  <description>
9
9
  The Design ruleset contains rules that flag suboptimal code implementations. Alternate approaches
@@ -1,7 +1,7 @@
1
1
  <?xml version="1.0"?>
2
2
 
3
3
  <projectlist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
- xsi:noNamespaceSchemaLocation="projectlist_1_0_0.xsd">
4
+ xsi:noNamespaceSchemaLocation="projectlist_1_2_0.xsd">
5
5
  <description>Standard Projects</description>
6
6
 
7
7
  <project>
@@ -20,10 +20,11 @@ xsi:noNamespaceSchemaLocation="projectlist_1_0_0.xsd">
20
20
  <tag>v5.0.6.RELEASE</tag>
21
21
  </project>
22
22
 
23
- <!---<project>
24
- <name>openjdk10</name>
25
- <type>hg</type>
26
- <connection>http://hg.openjdk.java.net/jdk10/jdk10/jdk</connection>
27
- <webview-url>http://hg.openjdk.java.net/jdk10/jdk10/jdk/file/777356696811</webview-url>
28
- </project> -->
23
+ <project>
24
+ <name>openjdk-11</name>
25
+ <type>git</type>
26
+ <connection>https://github.com/openjdk/jdk</connection>
27
+ <tag>jdk-11+28</tag>
28
+ <src-subpath>src/java.base</src-subpath>
29
+ </project>
29
30
  </projectlist>
@@ -1,4 +1,5 @@
1
1
  <?xml version="1.0" ?>
2
+ <!-- version 1.0.0 -->
2
3
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3
4
  <xs:element name="projectlist">
4
5
  <xs:complexType>
@@ -25,4 +26,4 @@
25
26
  <xs:element name="exclude-pattern" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
26
27
  </xs:sequence>
27
28
  </xs:complexType>
28
- </xs:schema>
29
+ </xs:schema>
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" ?>
2
+ <!-- version 1.1.0 -->
3
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4
+ <xs:element name="projectlist">
5
+ <xs:complexType>
6
+ <xs:sequence>
7
+ <xs:element name="description" type="xs:string" minOccurs="1" maxOccurs="1"/>
8
+ <xs:element name="project" type="project" minOccurs="1" maxOccurs="unbounded"/>
9
+ </xs:sequence>
10
+ </xs:complexType>
11
+ </xs:element>
12
+ <xs:complexType name="project">
13
+ <xs:sequence>
14
+ <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
15
+ <xs:element name="type" minOccurs="1" maxOccurs="1">
16
+ <xs:simpleType>
17
+ <xs:restriction base="xs:string">
18
+ <xs:enumeration value="git"/>
19
+ <xs:enumeration value="hg"/>
20
+ </xs:restriction>
21
+ </xs:simpleType>
22
+ </xs:element>
23
+ <xs:element name="connection" type="xs:string" minOccurs="1" maxOccurs="1"/>
24
+ <xs:element name="webview-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
25
+ <xs:element name="tag" type="xs:string" minOccurs="0" maxOccurs="1"/>
26
+ <xs:element name="exclude-pattern" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
27
+ <xs:element name="build-command" type="xs:string" minOccurs="0" maxOccurs="1"/>
28
+ <xs:element name="auxclasspath-command" type="xs:string" minOccurs="0" maxOccurs="1"/>
29
+ </xs:sequence>
30
+ </xs:complexType>
31
+ </xs:schema>
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" ?>
2
+ <!-- version 1.1.0 -->
3
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
4
+ <xs:element name="projectlist">
5
+ <xs:complexType>
6
+ <xs:sequence>
7
+ <xs:element name="description" type="xs:string" minOccurs="1" maxOccurs="1"/>
8
+ <xs:element name="project" type="project" minOccurs="1" maxOccurs="unbounded"/>
9
+ </xs:sequence>
10
+ </xs:complexType>
11
+ </xs:element>
12
+ <xs:complexType name="project">
13
+ <xs:sequence>
14
+ <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
15
+ <xs:element name="type" minOccurs="1" maxOccurs="1">
16
+ <xs:simpleType>
17
+ <xs:restriction base="xs:string">
18
+ <xs:enumeration value="git"/>
19
+ </xs:restriction>
20
+ </xs:simpleType>
21
+ </xs:element>
22
+ <xs:element name="connection" type="xs:string" minOccurs="1" maxOccurs="1"/>
23
+ <xs:element name="webview-url" type="xs:string" minOccurs="0" maxOccurs="1"/>
24
+ <xs:element name="tag" type="xs:string" minOccurs="0" maxOccurs="1"/>
25
+ <xs:element name="src-subpath" type="xs:string" minOccurs="0" maxOccurs="1" default=".">
26
+ <xs:annotation>
27
+ <xs:documentation>
28
+ Value of the -dir option for the PMD run.
29
+ The value must be a directory path relative to the root directory of the clone.
30
+ Defaults to just '.', ie the entire directory.
31
+ </xs:documentation>
32
+ </xs:annotation>
33
+ </xs:element>
34
+ <xs:element name="exclude-pattern" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
35
+ <xs:element name="build-command" type="xs:string" minOccurs="0" maxOccurs="1"/>
36
+ <xs:element name="auxclasspath-command" type="xs:string" minOccurs="0" maxOccurs="1"/>
37
+ </xs:sequence>
38
+ </xs:complexType>
39
+ </xs:schema>
data/lib/pmdtester.rb CHANGED
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'logger'
4
+ require 'logger/colors'
4
5
 
5
6
  require_relative 'pmdtester/cmd'
7
+ require_relative 'pmdtester/collection_by_file'
6
8
  require_relative 'pmdtester/pmd_branch_detail'
7
9
  require_relative 'pmdtester/pmd_configerror'
8
10
  require_relative 'pmdtester/pmd_error'
9
11
  require_relative 'pmdtester/pmd_report_detail'
12
+ require_relative 'pmdtester/pmd_tester_utils'
10
13
  require_relative 'pmdtester/pmd_violation'
11
14
  require_relative 'pmdtester/project'
12
15
  require_relative 'pmdtester/report_diff'
@@ -14,13 +17,10 @@ require_relative 'pmdtester/resource_locator'
14
17
  require_relative 'pmdtester/runner'
15
18
 
16
19
  require_relative 'pmdtester/builders/simple_progress_logger'
17
- require_relative 'pmdtester/builders/html_report_builder'
18
- require_relative 'pmdtester/builders/diff_builder'
19
- require_relative 'pmdtester/builders/diff_report/violations'
20
- require_relative 'pmdtester/builders/diff_report/configerrors'
21
- require_relative 'pmdtester/builders/diff_report/errors'
22
- require_relative 'pmdtester/builders/diff_report_builder'
20
+ require_relative 'pmdtester/builders/project_builder'
21
+ require_relative 'pmdtester/builders/project_hasher'
23
22
  require_relative 'pmdtester/builders/pmd_report_builder'
23
+ require_relative 'pmdtester/builders/liquid_renderer'
24
24
  require_relative 'pmdtester/builders/rule_set_builder'
25
25
  require_relative 'pmdtester/builders/summary_report_builder'
26
26
 
@@ -32,9 +32,10 @@ require_relative 'pmdtester/parsers/projects_parser'
32
32
  # and unexpected behaviors will not be introduced to PMD project
33
33
  # after fixing an issue and new rules can work as expected.
34
34
  module PmdTester
35
- VERSION = '1.0.0'
35
+ VERSION = '1.2.0'
36
36
  BASE = 'base'
37
37
  PATCH = 'patch'
38
+ PR_NUM_ENV_VAR = 'PMD_CI_PULL_REQUEST_NUMBER' # see PmdBranchDetail
38
39
 
39
40
  def logger
40
41
  PmdTester.logger
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'liquid'
4
+ require 'json'
5
+
6
+ module PmdTester
7
+ # A module to include in classes that use a Liquid template
8
+ # to generate content.
9
+ module LiquidRenderer
10
+ include PmdTester
11
+
12
+ def render_liquid(template_path, env)
13
+ to_render = File.read(ResourceLocator.resource(template_path))
14
+ includes = Liquid::LocalFileSystem.new(ResourceLocator.resource('_includes'), '%s.html')
15
+ Liquid::Template.file_system = includes
16
+ template = Liquid::Template.parse(to_render, error_mode: :strict)
17
+ template.render!(env, { strict_variables: true })
18
+ end
19
+
20
+ def render_and_write(template_path, target_file, env)
21
+ write_file(target_file, render_liquid(template_path, env))
22
+ end
23
+
24
+ def write_file(target_file, contents)
25
+ dir = File.dirname(target_file)
26
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
27
+
28
+ index = File.new(target_file, 'w')
29
+ index&.puts contents # may be nil when stubbing
30
+ logger&.info "Written #{target_file}"
31
+ ensure
32
+ index&.close
33
+ end
34
+
35
+ def copy_resource(dir, to_root)
36
+ src = ResourceLocator.resource(dir)
37
+ dest = "#{to_root}/#{dir}"
38
+ FileUtils.copy_entry(src, dest)
39
+ end
40
+ end
41
+
42
+ # Renders the index of a project diff report.
43
+ class LiquidProjectRenderer
44
+ include PmdTester
45
+ include ProjectHasher
46
+ include LiquidRenderer
47
+
48
+ def write_project_index(project, root)
49
+ liquid_env = {
50
+ 'diff' => report_diff_to_h(project.report_diff),
51
+ 'error_diffs' => errors_to_h(project),
52
+ 'configerror_diffs' => configerrors_to_h(project),
53
+ 'project_name' => project.name
54
+ }
55
+
56
+ # Renders index.html using liquid
57
+ write_file("#{root}/index.html", render_liquid('project_diff_report.html', liquid_env))
58
+ # generate array of violations in json
59
+ write_file("#{root}/project_data.js", dump_violations_json(project))
60
+ # copy original pmd reports
61
+ copy_file("#{root}/base_pmd_report.xml", project.report_diff.base_report.file)
62
+ copy_file("#{root}/patch_pmd_report.xml", project.report_diff.patch_report.file)
63
+ # render full pmd reports
64
+ write_file("#{root}/base_pmd_report.html",
65
+ render_liquid('project_pmd_report.html', pmd_report_liquid_env(project, BASE)))
66
+ write_file("#{root}/base_data.js", dump_violations_json(project, BASE))
67
+ write_file("#{root}/patch_pmd_report.html",
68
+ render_liquid('project_pmd_report.html', pmd_report_liquid_env(project, PATCH)))
69
+ write_file("#{root}/patch_data.js", dump_violations_json(project, PATCH))
70
+ end
71
+
72
+ def dump_violations_json(project, branch = 'diff')
73
+ violations_by_file = if branch == BASE
74
+ project.report_diff.base_report.violations_by_file.to_h
75
+ elsif branch == PATCH
76
+ project.report_diff.patch_report.violations_by_file.to_h
77
+ else
78
+ project.report_diff.violation_diffs_by_file
79
+ end
80
+
81
+ h = {
82
+ 'source_link_base' => project.webview_url,
83
+ 'source_link_template' => link_template(project),
84
+ **violations_to_hash(project, violations_by_file, branch == 'diff')
85
+ }
86
+
87
+ project_data = JSON.fast_generate(h, indent: ' ', object_nl: "\n", array_nl: "\n")
88
+ "let project = #{project_data}"
89
+ end
90
+
91
+ private
92
+
93
+ def copy_file(target_file, source_file)
94
+ if File.exist? source_file
95
+ FileUtils.cp(source_file, target_file)
96
+ logger&.info "Written #{target_file}"
97
+ else
98
+ logger&.warn "File #{source_file} not found"
99
+ end
100
+ end
101
+
102
+ def pmd_report_liquid_env(project, branch)
103
+ report = if branch == BASE
104
+ project.report_diff.base_report
105
+ else
106
+ project.report_diff.patch_report
107
+ end
108
+ {
109
+ 'project_name' => project.name,
110
+ 'branch' => branch,
111
+ 'report' => report_to_h(project, report)
112
+ }
113
+ end
114
+
115
+ def report_to_h(project, report)
116
+ {
117
+ 'violation_counts' => report.violations_by_file.total_size,
118
+ 'error_counts' => report.errors_by_file.total_size,
119
+ 'configerror_counts' => report.configerrors_by_rule.values.flatten.length,
120
+
121
+ 'execution_time' => PmdReportDetail.convert_seconds(report.exec_time),
122
+ 'timestamp' => report.timestamp,
123
+
124
+ 'rules' => report.rule_summaries,
125
+ 'errors' => report.errors_by_file.all_values.map { |e| error_to_hash(e, project) },
126
+ 'configerrors' => report.configerrors_by_rule.values.flatten.map { |e| configerror_to_hash(e) }
127
+ }
128
+ end
129
+ end
130
+ end