Class: Danger::DangerJacoco

Inherits:
Plugin
  • Object
show all
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

Examples:

Verify coverage

jacoco.minimum_project_coverage_percentage = 50

Verify coverage per package

jacoco.minimum_package_coverage_map = { # optional (default is empty)
 'com/package/' => 55,
 'com/package/more/specific/' => 15
}

See Also:

  • Malinskiy/danger-jacoco

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#fail_no_coverage_data_foundObject

Returns the value of attribute fail_no_coverage_data_found.



28
29
30
# File 'lib/jacoco/plugin.rb', line 28

def fail_no_coverage_data_found
  @fail_no_coverage_data_found
end

#files_extensionObject

Returns the value of attribute files_extension.



25
26
27
# File 'lib/jacoco/plugin.rb', line 25

def files_extension
  @files_extension
end

#minimum_class_coverage_mapObject

Returns the value of attribute minimum_class_coverage_map.



27
28
29
# File 'lib/jacoco/plugin.rb', line 27

def minimum_class_coverage_map
  @minimum_class_coverage_map
end

#minimum_class_coverage_percentageObject

Returns the value of attribute minimum_class_coverage_percentage.



24
25
26
# File 'lib/jacoco/plugin.rb', line 24

def minimum_class_coverage_percentage
  @minimum_class_coverage_percentage
end

#minimum_package_coverage_mapObject

Returns the value of attribute minimum_package_coverage_map.



26
27
28
# File 'lib/jacoco/plugin.rb', line 26

def minimum_package_coverage_map
  @minimum_package_coverage_map
end

#minimum_project_coverage_percentageObject

rubocop:disable Metrics/ClassLength



23
24
25
# File 'lib/jacoco/plugin.rb', line 23

def minimum_project_coverage_percentage
  @minimum_project_coverage_percentage
end

Instance Method Details

#classes(delimiter) ⇒ Object

Select modified and added files in this PR



86
87
88
89
90
91
# File 'lib/jacoco/plugin.rb', line 86

def classes(delimiter)
  git = @dangerfile.git
  affected_files = git.modified_files + git.added_files
  affected_files.select { |file| files_extension.reduce(false) { |state, el| state || file.end_with?(el) } }
                .map { |file| file.split('.').first.split(delimiter)[1] }
end

#coverage_status(coverage, minimum_percentage) ⇒ Object

it returns an emoji for coverage status



134
135
136
137
138
139
# File 'lib/jacoco/plugin.rb', line 134

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



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/jacoco/plugin.rb', line 120

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



44
45
46
# File 'lib/jacoco/plugin.rb', line 44

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



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/jacoco/plugin.rb', line 65

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
  classes = classes(delimiter)

  parser = Jacoco::SAXParser.new(classes)
  Nokogiri::XML::SAX::Parser.new(parser).parse(File.open(path))

  total_covered = total_coverage(path)

  report_markdown = "### JaCoCO Code Coverage #{total_covered[:covered]}% #{total_covered[:status]}\n"
  report_markdown += "| Class | Covered | Meta | Status |\n"
  report_markdown += "|:---|:---:|:---:|:---:|\n"
  class_coverage_above_minimum = markdown_class(parser, report_markdown, report_url)
  markdown(report_markdown)

  report_fails(class_coverage_above_minimum, total_covered)
end

#report_class(jacoco_class) ⇒ Object

It returns a specific class code coverage and an emoji status as well



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/jacoco/plugin.rb', line 94

def report_class(jacoco_class)
  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 = minimum_class_coverage_map[jacoco_class.name]
    required_coverage = package_coverage(jacoco_class.name) if required_coverage.nil?
    required_coverage = minimum_class_coverage_percentage if required_coverage.nil?
    status = coverage_status(coverage, required_coverage)

    report_result = {
      covered: coverage,
      status: status,
      required_coverage_percentage: required_coverage
    }
  end

  report_result
end

#setupObject

Initialize the plugin with configured parameters or defaults



31
32
33
34
35
36
37
# File 'lib/jacoco/plugin.rb', line 31

def setup
  @minimum_project_coverage_percentage = 0 unless minimum_project_coverage_percentage
  @minimum_class_coverage_percentage = 0 unless minimum_class_coverage_percentage
  @minimum_package_coverage_map = {} unless minimum_package_coverage_map
  @minimum_class_coverage_map = {} unless minimum_class_coverage_map
  @files_extension = ['.kt', '.java'] unless files_extension
end

#total_coverage(report_path) ⇒ Object

It returns total of project code coverage and an emoji status as well



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/jacoco/plugin.rb', line 142

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