Class: Danger::DangerJacoco
- Inherits:
-
Plugin
- Object
- Plugin
- Danger::DangerJacoco
- Defined in:
- lib/jacoco/plugin.rb
Overview
Verify code coverage inside your projects This is done using the jacoco output Results are passed out as a table in markdown
Instance Attribute Summary collapse
-
#class_column_title ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#fail_no_coverage_data_found ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#file_to_create_on_failure ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#files_extension ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#files_to_check ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#minimum_class_coverage_map ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#minimum_class_coverage_percentage ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#minimum_composable_class_coverage_percentage ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#minimum_package_coverage_map ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#minimum_project_coverage_percentage ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#subtitle_failure ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#subtitle_success ⇒ Object
rubocop:disable Metrics/ClassLength.
-
#title ⇒ Object
rubocop:disable Metrics/ClassLength.
Instance Method Summary collapse
-
#classes(delimiter) ⇒ Object
rubocop:enable Style/AbcSize.
-
#coverage_status(coverage, minimum_percentage) ⇒ Object
it returns an emoji for coverage status.
-
#package_coverage(class_name) ⇒ Object
it returns the most suitable coverage by package name to class or nil.
-
#parse(path) ⇒ Object
Parses the xml output of jacoco to Ruby model classes This is slow since it’s basically DOM parsing.
-
#report(path, report_url = '', delimiter = %r{/java/|/kotlin/}, fail_no_coverage_data_found: true) ⇒ Object
This is a fast report based on SAX parser.
-
#report_class(jacoco_class, file_path) ⇒ Object
It returns a specific class code coverage and an emoji status as well.
-
#required_class_coverage(jacoco_class, file_path) ⇒ Object
Determines the required coverage for the class rubocop:disable Metrics/AbcSize rubocop:disable Metrics/CyclomaticComplexity.
-
#setup ⇒ Object
Initialize the plugin with configured parameters or defaults.
-
#setup_minimum_coverages ⇒ Object
Initialize the plugin with configured coverage minimum parameters or defaults.
-
#setup_texts ⇒ Object
Initialize the plugin with configured optional texts.
-
#total_coverage(report_path) ⇒ Object
It returns total of project code coverage and an emoji status as well.
Instance Attribute Details
#class_column_title ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def class_column_title @class_column_title end |
#fail_no_coverage_data_found ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def fail_no_coverage_data_found @fail_no_coverage_data_found end |
#file_to_create_on_failure ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def file_to_create_on_failure @file_to_create_on_failure end |
#files_extension ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def files_extension @files_extension end |
#files_to_check ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def files_to_check @files_to_check end |
#minimum_class_coverage_map ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def minimum_class_coverage_map @minimum_class_coverage_map end |
#minimum_class_coverage_percentage ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def minimum_class_coverage_percentage @minimum_class_coverage_percentage end |
#minimum_composable_class_coverage_percentage ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def minimum_composable_class_coverage_percentage @minimum_composable_class_coverage_percentage end |
#minimum_package_coverage_map ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def minimum_package_coverage_map @minimum_package_coverage_map end |
#minimum_project_coverage_percentage ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def minimum_project_coverage_percentage @minimum_project_coverage_percentage end |
#subtitle_failure ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def subtitle_failure @subtitle_failure end |
#subtitle_success ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def subtitle_success @subtitle_success end |
#title ⇒ Object
rubocop:disable Metrics/ClassLength
23 24 25 |
# File 'lib/jacoco/plugin.rb', line 23 def title @title end |
Instance Method Details
#classes(delimiter) ⇒ Object
rubocop:enable Style/AbcSize
106 107 108 109 110 111 112 113 114 |
# File 'lib/jacoco/plugin.rb', line 106 def classes(delimiter) class_to_file_path_hash = {} files_to_check.select { |file| files_extension.reduce(false) { |state, el| state || file.end_with?(el) } } .each do |file| # "src/java/com/example/CachedRepository.java" classname = file.split('.').first.split(delimiter)[1] # "com/example/CachedRepository" class_to_file_path_hash[classname] = file end class_to_file_path_hash end |
#coverage_status(coverage, minimum_percentage) ⇒ Object
it returns an emoji for coverage status
170 171 172 173 174 175 176 |
# File 'lib/jacoco/plugin.rb', line 170 def coverage_status(coverage, minimum_percentage) if coverage < (minimum_percentage / 2) then ':skull:' elsif coverage < minimum_percentage then ':warning:' else ':white_check_mark:' end end |
#package_coverage(class_name) ⇒ Object
it returns the most suitable coverage by package name to class or nil
156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/jacoco/plugin.rb', line 156 def package_coverage(class_name) path = class_name package_parts = class_name.split('/') package_parts.reverse_each do |item| size = item.size path = path[0...-size] coverage = minimum_package_coverage_map[path] path = path[0...-1] unless path.empty? return coverage unless coverage.nil? end nil end |
#parse(path) ⇒ Object
Parses the xml output of jacoco to Ruby model classes This is slow since it’s basically DOM parsing
59 60 61 |
# File 'lib/jacoco/plugin.rb', line 59 def parse(path) Jacoco::DOMParser.read_path(path) end |
#report(path, report_url = '', delimiter = %r{/java/|/kotlin/}, fail_no_coverage_data_found: true) ⇒ Object
This is a fast report based on SAX parser
changed files. We need to get the class from this path to check the Jacoco report,
e.g. src/java/com/example/SomeJavaClass.java -> com/example/SomeJavaClass e.g. src/kotlin/com/example/SomeKotlinClass.kt -> com/example/SomeKotlinClass
The default value supposes that you’re using gradle structure, that is your path to source files is something like
Java => blah/blah/java/slashed_package/Source.java Kotlin => blah/blah/kotlin/slashed_package/Source.kt
rubocop:disable Style/AbcSize
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/jacoco/plugin.rb', line 81 def report(path, report_url = '', delimiter = %r{/java/|/kotlin/}, fail_no_coverage_data_found: true) @fail_no_coverage_data_found = fail_no_coverage_data_found setup class_to_file_path_hash = classes(delimiter) classnames = class_to_file_path_hash.keys parser = Jacoco::SAXParser.new(classnames) Nokogiri::XML::SAX::Parser.new(parser).parse(File.open(path)) total_covered = total_coverage(path) header = "### #{title} Code Coverage #{total_covered[:covered]}% #{total_covered[:status]}\n" report_markdown = header report_markdown += "| #{class_column_title} | Covered | Required | Status |\n" report_markdown += "|:---|:---:|:---:|:---:|\n" class_coverage_above_minimum = markdown_class(parser, report_markdown, report_url, class_to_file_path_hash) subtitle = class_coverage_above_minimum ? subtitle_success : subtitle_failure report_markdown.insert(header.length, "#### #{subtitle}\n") markdown(report_markdown) report_fails(parser, report_url, class_coverage_above_minimum, total_covered) end |
#report_class(jacoco_class, file_path) ⇒ Object
It returns a specific class code coverage and an emoji status as well
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/jacoco/plugin.rb', line 117 def report_class(jacoco_class, file_path) report_result = { covered: 'No coverage data found : -', status: ':black_joker:', required_coverage_percentage: 'No coverage data found : -' } counter = coverage_counter(jacoco_class) unless counter.nil? coverage = (counter.covered.fdiv(counter.covered + counter.missed) * 100).floor required_coverage = required_class_coverage(jacoco_class, file_path) status = coverage_status(coverage, required_coverage) report_result = { covered: coverage, status: status, required_coverage_percentage: required_coverage } end report_result end |
#required_class_coverage(jacoco_class, file_path) ⇒ Object
Determines the required coverage for the class rubocop:disable Metrics/AbcSize rubocop:disable Metrics/CyclomaticComplexity
143 144 145 146 147 148 149 150 151 |
# File 'lib/jacoco/plugin.rb', line 143 def required_class_coverage(jacoco_class, file_path) key = minimum_class_coverage_map.keys.detect { |k| jacoco_class.name.match(k) } || jacoco_class.name required_coverage = minimum_class_coverage_map[key] includes_composables = File.read(file_path).include? '@Composable' if File.exist?(file_path) required_coverage = minimum_composable_class_coverage_percentage if required_coverage.nil? && includes_composables required_coverage = package_coverage(jacoco_class.name) if required_coverage.nil? required_coverage = minimum_class_coverage_percentage if required_coverage.nil? required_coverage end |
#setup ⇒ Object
Initialize the plugin with configured parameters or defaults
29 30 31 32 33 34 35 |
# File 'lib/jacoco/plugin.rb', line 29 def setup setup_minimum_coverages setup_texts @files_to_check = [] unless files_to_check @files_extension = ['.kt', '.java'] unless files_extension @file_to_create_on_failure = 'danger_jacoco_failure_status_file.json' unless file_to_create_on_failure end |
#setup_minimum_coverages ⇒ Object
Initialize the plugin with configured coverage minimum parameters or defaults
46 47 48 49 50 51 52 |
# File 'lib/jacoco/plugin.rb', line 46 def setup_minimum_coverages @minimum_project_coverage_percentage = 0 unless minimum_project_coverage_percentage @minimum_class_coverage_percentage = 0 unless minimum_class_coverage_percentage @minimum_composable_class_coverage_percentage = 0 unless minimum_composable_class_coverage_percentage @minimum_package_coverage_map = {} unless minimum_package_coverage_map @minimum_class_coverage_map = {} unless minimum_class_coverage_map end |
#setup_texts ⇒ Object
Initialize the plugin with configured optional texts
38 39 40 41 42 43 |
# File 'lib/jacoco/plugin.rb', line 38 def setup_texts @title = 'JaCoCo' unless title @class_column_title = 'Class' unless class_column_title @subtitle_success = 'All classes meet coverage requirement. Well done! :white_check_mark:' unless subtitle_success @subtitle_failure = 'There are classes that do not meet coverage requirement :warning:' unless subtitle_failure end |
#total_coverage(report_path) ⇒ Object
It returns total of project code coverage and an emoji status as well
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/jacoco/plugin.rb', line 179 def total_coverage(report_path) jacoco_report = Nokogiri::XML(File.open(report_path)) report = jacoco_report.xpath('report/counter').select { |item| item['type'] == 'INSTRUCTION' } missed_instructions = report.first['missed'].to_f covered_instructions = report.first['covered'].to_f total_instructions = missed_instructions + covered_instructions covered_percentage = (covered_instructions * 100 / total_instructions).round(2) coverage_status = coverage_status(covered_percentage, minimum_project_coverage_percentage) { covered: covered_percentage, status: coverage_status } end |