slather 1.7.1 → 1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +20 -9
- data/assets/highlight.pack.js +1 -0
- data/assets/list.min.js +1 -0
- data/assets/slather.css +316 -0
- data/bin/slather +9 -1
- data/lib/slather.rb +2 -0
- data/lib/slather/coverage_file.rb +1 -1
- data/lib/slather/coverage_service/coveralls.rb +55 -10
- data/lib/slather/coverage_service/hardcover.rb +61 -0
- data/lib/slather/coverage_service/html_output.rb +244 -0
- data/lib/slather/project.rb +10 -7
- data/lib/slather/version.rb +1 -1
- data/spec/fixtures/fixtures_html/Branches.m.html +261 -0
- data/spec/fixtures/fixtures_html/BranchesTests.m.html +228 -0
- data/spec/fixtures/fixtures_html/Empty.m.html +30 -0
- data/spec/fixtures/fixtures_html/fixtures.m.html +151 -0
- data/spec/fixtures/fixtures_html/fixturesTests.m.html +216 -0
- data/spec/fixtures/fixtures_html/fixtures_cpp.cpp.html +30 -0
- data/spec/fixtures/fixtures_html/fixtures_m.m.html +30 -0
- data/spec/fixtures/fixtures_html/fixtures_mm.mm.html +30 -0
- data/spec/fixtures/fixtures_html/index.html +134 -0
- data/spec/fixtures/fixtures_html/peekaview.m.html +190 -0
- data/spec/fixtures/fixtures_html/peekaviewTests.m.html +206 -0
- data/spec/slather/coverage_service/coveralls_spec.rb +25 -6
- data/spec/slather/coverage_service/hardcover_spec.rb +87 -0
- data/spec/slather/coverage_service/html_output_spec.rb +179 -0
- data/spec/slather/project_spec.rb +13 -6
- data/spec/spec_helper.rb +2 -1
- metadata +33 -2
data/lib/slather.rb
CHANGED
@@ -4,8 +4,10 @@ require 'slather/coverage_file'
|
|
4
4
|
require 'slather/coveralls_coverage_file'
|
5
5
|
require 'slather/coverage_service/cobertura_xml_output'
|
6
6
|
require 'slather/coverage_service/coveralls'
|
7
|
+
require 'slather/coverage_service/hardcover'
|
7
8
|
require 'slather/coverage_service/gutter_json_output'
|
8
9
|
require 'slather/coverage_service/simple_output'
|
10
|
+
require 'slather/coverage_service/html_output'
|
9
11
|
|
10
12
|
module Slather
|
11
13
|
|
@@ -71,7 +71,7 @@ module Slather
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def cleaned_gcov_data
|
74
|
-
data = gcov_data.gsub(/^function(.*) called [0-9]+ returned [0-9]+% blocks executed(.*)$\r?\n/, '')
|
74
|
+
data = gcov_data.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '').gsub(/^function(.*) called [0-9]+ returned [0-9]+% blocks executed(.*)$\r?\n/, '')
|
75
75
|
data.gsub(/^branch(.*)$\r?\n/, '')
|
76
76
|
end
|
77
77
|
|
@@ -11,22 +11,54 @@ module Slather
|
|
11
11
|
ENV['TRAVIS_JOB_ID']
|
12
12
|
end
|
13
13
|
private :travis_job_id
|
14
|
-
|
14
|
+
|
15
15
|
def circleci_job_id
|
16
16
|
ENV['CIRCLE_BUILD_NUM']
|
17
17
|
end
|
18
18
|
private :circleci_job_id
|
19
|
-
|
19
|
+
|
20
20
|
def circleci_pull_request
|
21
|
-
ENV['CI_PULL_REQUEST']
|
21
|
+
ENV['CIRCLE_PR_NUMBER'] || ENV['CI_PULL_REQUEST'] || ""
|
22
22
|
end
|
23
23
|
private :circleci_pull_request
|
24
|
-
|
24
|
+
|
25
|
+
def jenkins_job_id
|
26
|
+
ENV['BUILD_ID']
|
27
|
+
end
|
28
|
+
private :jenkins_job_id
|
29
|
+
|
30
|
+
def jenkins_branch_name
|
31
|
+
branch_name = ENV['GIT_BRANCH']
|
32
|
+
if branch_name.include? 'origin/'
|
33
|
+
branch_name[7...branch_name.length]
|
34
|
+
else
|
35
|
+
branch_name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
private :jenkins_branch_name
|
39
|
+
|
40
|
+
def jenkins_git_info
|
41
|
+
{
|
42
|
+
head: {
|
43
|
+
id: ENV['sha1'],
|
44
|
+
author_name: ENV['ghprbActualCommitAuthor'],
|
45
|
+
message: ENV['ghprbPullTitle']
|
46
|
+
},
|
47
|
+
branch: jenkins_branch_name
|
48
|
+
}
|
49
|
+
end
|
50
|
+
private :jenkins_git_info
|
51
|
+
|
52
|
+
def circleci_build_url
|
53
|
+
"https://circleci.com/gh/" + ENV['CIRCLE_PROJECT_USERNAME'] || "" + "/" + ENV['CIRCLE_PROJECT_REPONAME'] || "" + "/" + ENV['CIRCLE_BUILD_NUM'] || ""
|
54
|
+
end
|
55
|
+
private :circleci_build_url
|
56
|
+
|
25
57
|
def circleci_git_info
|
26
58
|
{
|
27
59
|
:head => {
|
28
60
|
:id => (ENV['CIRCLE_SHA1'] || ""),
|
29
|
-
:author_name => (ENV['CIRCLE_USERNAME'] || ""),
|
61
|
+
:author_name => (ENV['CIRCLE_PR_USERNAME'] || ENV['CIRCLE_USERNAME'] || ""),
|
30
62
|
:message => (`git log --format=%s -n 1 HEAD`.chomp || "")
|
31
63
|
},
|
32
64
|
:branch => (ENV['CIRCLE_BRANCH'] || "")
|
@@ -47,7 +79,7 @@ module Slather
|
|
47
79
|
{
|
48
80
|
:service_job_id => travis_job_id,
|
49
81
|
:service_name => "travis-pro",
|
50
|
-
:repo_token =>
|
82
|
+
:repo_token => coverage_access_token,
|
51
83
|
:source_files => coverage_files.map(&:as_json)
|
52
84
|
}.to_json
|
53
85
|
end
|
@@ -59,19 +91,32 @@ module Slather
|
|
59
91
|
coveralls_hash = {
|
60
92
|
:service_job_id => circleci_job_id,
|
61
93
|
:service_name => "circleci",
|
62
|
-
:repo_token =>
|
94
|
+
:repo_token => coverage_access_token,
|
63
95
|
:source_files => coverage_files.map(&:as_json),
|
64
|
-
:git => circleci_git_info
|
96
|
+
:git => circleci_git_info,
|
97
|
+
:service_build_url => circleci_build_url
|
65
98
|
}
|
66
|
-
|
99
|
+
|
67
100
|
if circleci_pull_request != nil && circleci_pull_request.length > 0
|
68
101
|
coveralls_hash[:service_pull_request] = circleci_pull_request.split("/").last
|
69
102
|
end
|
70
|
-
|
103
|
+
|
71
104
|
coveralls_hash.to_json
|
72
105
|
else
|
73
106
|
raise StandardError, "Environment variable `CIRCLE_BUILD_NUM` not set. Is this running on a circleci build?"
|
74
107
|
end
|
108
|
+
elsif ci_service == :jenkins
|
109
|
+
if jenkins_job_id
|
110
|
+
{
|
111
|
+
service_job_id: jenkins_job_id,
|
112
|
+
service_name: "jenkins",
|
113
|
+
repo_token: coverage_access_token,
|
114
|
+
source_files: coverage_files.map(&:as_json),
|
115
|
+
git: jenkins_git_info
|
116
|
+
}.to_json
|
117
|
+
else
|
118
|
+
raise StandardError, "Environment variable `BUILD_ID` not set. Is this running on a jenkins build?"
|
119
|
+
end
|
75
120
|
else
|
76
121
|
raise StandardError, "No support for ci named #{ci_service}"
|
77
122
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Slather
|
2
|
+
module CoverageService
|
3
|
+
module Hardcover
|
4
|
+
|
5
|
+
def coverage_file_class
|
6
|
+
Slather::CoverallsCoverageFile
|
7
|
+
end
|
8
|
+
private :coverage_file_class
|
9
|
+
|
10
|
+
def jenkins_job_id
|
11
|
+
"#{ENV['JOB_NAME']}/#{ENV['BUILD_NUMBER']}"
|
12
|
+
end
|
13
|
+
private :jenkins_job_id
|
14
|
+
|
15
|
+
def hardcover_coverage_data
|
16
|
+
if ci_service == :jenkins_ci
|
17
|
+
if jenkins_job_id
|
18
|
+
{
|
19
|
+
:service_job_id => jenkins_job_id,
|
20
|
+
:service_name => "jenkins-ci",
|
21
|
+
:repo_token => Project.yml["hardcover_repo_token"],
|
22
|
+
:source_files => coverage_files.map(&:as_json)
|
23
|
+
}.to_json
|
24
|
+
else
|
25
|
+
raise StandardError, "Environment variables `BUILD_NUMBER` and `JOB_NAME` are not set. Is this running on a Jenkins build?"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
raise StandardError, "No support for ci named #{ci_service}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
private :hardcover_coverage_data
|
32
|
+
|
33
|
+
def post
|
34
|
+
f = File.open('hardcover_json_file', 'w+')
|
35
|
+
begin
|
36
|
+
f.write(hardcover_coverage_data)
|
37
|
+
f.close
|
38
|
+
`curl --form json_file=@#{f.path} #{hardcover_api_jobs_path}`
|
39
|
+
rescue StandardError => e
|
40
|
+
FileUtils.rm(f)
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
FileUtils.rm(f)
|
44
|
+
end
|
45
|
+
|
46
|
+
def hardcover_api_jobs_path
|
47
|
+
"#{hardcover_base_url}/v1/jobs"
|
48
|
+
end
|
49
|
+
private :hardcover_api_jobs_path
|
50
|
+
|
51
|
+
def hardcover_base_url
|
52
|
+
url = Project.yml["hardcover_base_url"]
|
53
|
+
unless url
|
54
|
+
raise "No `hardcover_base_url` configured. Please add it to your `.slather.yml`"
|
55
|
+
end
|
56
|
+
url
|
57
|
+
end
|
58
|
+
private :hardcover_base_url
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Slather
|
4
|
+
module CoverageService
|
5
|
+
module HtmlOutput
|
6
|
+
|
7
|
+
def coverage_file_class
|
8
|
+
Slather::CoverageFile
|
9
|
+
end
|
10
|
+
private :coverage_file_class
|
11
|
+
|
12
|
+
def directory_path
|
13
|
+
is_path_valid = !output_directory.nil? && !output_directory.strip.eql?("")
|
14
|
+
is_path_valid ? File.expand_path(output_directory) : "html"
|
15
|
+
end
|
16
|
+
private :directory_path
|
17
|
+
|
18
|
+
def post
|
19
|
+
create_html_reports(coverage_files)
|
20
|
+
generate_reports(@docs)
|
21
|
+
|
22
|
+
index_html_path = File.join(directory_path, "index.html")
|
23
|
+
if show_html
|
24
|
+
open_coverage index_html_path
|
25
|
+
else
|
26
|
+
print_path_coverage index_html_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def print_path_coverage(index_html)
|
31
|
+
path = File.expand_path index_html
|
32
|
+
puts "\nTo open the html reports, use \n\nopen '#{path}'\n\nor use '--show' flag to open it automatically.\n\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
def open_coverage(index_html)
|
36
|
+
path = File.expand_path index_html
|
37
|
+
`open '#{path}'` if File.exist?(path)
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_html_reports(coverage_files)
|
41
|
+
create_index_html(coverage_files)
|
42
|
+
create_htmls_from_files(coverage_files)
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_reports(reports)
|
46
|
+
FileUtils.rm_rf(directory_path) if Dir.exist?(directory_path)
|
47
|
+
FileUtils.mkdir_p(directory_path)
|
48
|
+
|
49
|
+
reports.each do |name, doc|
|
50
|
+
html_file = File.join(directory_path, "#{name}.html")
|
51
|
+
File.write(html_file, doc.to_html)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_index_html(coverage_files)
|
56
|
+
project_name = File.basename(self.xcodeproj)
|
57
|
+
template = generate_html_template(project_name, true, false)
|
58
|
+
|
59
|
+
total_relevant_lines = 0
|
60
|
+
total_tested_lines = 0
|
61
|
+
coverage_files.each { |coverage_file|
|
62
|
+
total_tested_lines += coverage_file.num_lines_tested
|
63
|
+
total_relevant_lines += coverage_file.num_lines_testable
|
64
|
+
}
|
65
|
+
|
66
|
+
builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
|
67
|
+
cov.h2 "Files for \"#{project_name}\""
|
68
|
+
|
69
|
+
cov.h4 {
|
70
|
+
percentage = (total_tested_lines / total_relevant_lines.to_f) * 100.0
|
71
|
+
cov.span "Total Coverage : "
|
72
|
+
cov.span '%.2f%%' % percentage, :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
|
73
|
+
}
|
74
|
+
|
75
|
+
cov.input(:class => "search", :placeholder => "Search")
|
76
|
+
|
77
|
+
cov.table(:class => "coverage_list", :cellspacing => 0, :cellpadding => 0) {
|
78
|
+
|
79
|
+
cov.thead {
|
80
|
+
cov.tr {
|
81
|
+
cov.th "%", :class => "col_num sort", "data-sort" => "data_percentage"
|
82
|
+
cov.th "File", :class => "sort", "data-sort" => "data_filename"
|
83
|
+
cov.th "Lines", :class => "col_percent sort", "data-sort" => "data_lines"
|
84
|
+
cov.th "Relevant", :class => "col_percent sort", "data-sort" => "data_relevant"
|
85
|
+
cov.th "Covered", :class => "col_percent sort", "data-sort" => "data_covered"
|
86
|
+
cov.th "Missed", :class => "col_percent sort", "data-sort" => "data_missed"
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
cov.tbody(:class => "list") {
|
91
|
+
coverage_files.each { |coverage_file|
|
92
|
+
filename = File.basename(coverage_file.source_file_pathname_relative_to_repo_root)
|
93
|
+
filename_link = "#{filename}.html"
|
94
|
+
|
95
|
+
cov.tr {
|
96
|
+
percentage = coverage_file.percentage_lines_tested
|
97
|
+
|
98
|
+
cov.td { cov.span '%.2f' % percentage, :class => "percentage #{class_for_coverage_percentage(percentage)} data_percentage" }
|
99
|
+
cov.td(:class => "data_filename") {
|
100
|
+
cov.a filename, :href => filename_link
|
101
|
+
}
|
102
|
+
cov.td "#{coverage_file.line_coverage_data.count}", :class => "data_lines"
|
103
|
+
cov.td "#{coverage_file.num_lines_testable}", :class => "data_relevant"
|
104
|
+
cov.td "#{coverage_file.num_lines_tested}", :class => "data_covered"
|
105
|
+
cov.td "#{(coverage_file.num_lines_testable - coverage_file.num_lines_tested)}", :class => "data_missed"
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
@docs = Hash.new
|
113
|
+
@docs[:index] = builder.doc
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_htmls_from_files(coverage_files)
|
117
|
+
coverage_files.map { |file| create_html_from_file file }
|
118
|
+
end
|
119
|
+
|
120
|
+
def create_html_from_file(coverage_file)
|
121
|
+
filepath = coverage_file.source_file_pathname_relative_to_repo_root
|
122
|
+
filename = File.basename(filepath)
|
123
|
+
percentage = coverage_file.percentage_lines_tested
|
124
|
+
|
125
|
+
cleaned_gcov_lines = coverage_file.cleaned_gcov_data.split("\n")
|
126
|
+
is_file_empty = (cleaned_gcov_lines.count <= 0)
|
127
|
+
|
128
|
+
template = generate_html_template(filename, false, is_file_empty)
|
129
|
+
|
130
|
+
builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
|
131
|
+
cov.h2(:class => "cov_title") {
|
132
|
+
cov.span("Coverage for \"#{filename}\"" + (!is_file_empty ? " : " : ""))
|
133
|
+
cov.span("#{'%.2f' % percentage}%", :class => class_for_coverage_percentage(percentage)) unless is_file_empty
|
134
|
+
}
|
135
|
+
|
136
|
+
cov.h4("(#{coverage_file.num_lines_tested} of #{coverage_file.num_lines_testable} relevant lines covered)", :class => "cov_subtitle")
|
137
|
+
cov.h4(filepath, :class => "cov_filepath")
|
138
|
+
|
139
|
+
if is_file_empty
|
140
|
+
cov.p "¯\\_(ツ)_/¯"
|
141
|
+
next
|
142
|
+
end
|
143
|
+
|
144
|
+
cov.table(:class => "source_code") {
|
145
|
+
cleaned_gcov_lines.each do |line|
|
146
|
+
data = line.split(':', 3)
|
147
|
+
|
148
|
+
line_number = data[1].to_i
|
149
|
+
next unless line_number > 0
|
150
|
+
|
151
|
+
coverage_data = data[0].strip
|
152
|
+
line_data = [line_number, data[2], hits_for_coverage_data(coverage_data)]
|
153
|
+
classes = ["num", "src", "coverage"]
|
154
|
+
|
155
|
+
cov.tr(:class => class_for_coverage_data(coverage_data)) {
|
156
|
+
line_data.each_with_index { |line, idx|
|
157
|
+
if idx != 1
|
158
|
+
cov.td(line, :class => classes[idx])
|
159
|
+
else
|
160
|
+
cov.td(:class => classes[idx]) {
|
161
|
+
cov.pre { cov.code(line, :class => "objc") }
|
162
|
+
}
|
163
|
+
end
|
164
|
+
}
|
165
|
+
}
|
166
|
+
end
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
@docs[filename] = builder.doc
|
171
|
+
end
|
172
|
+
|
173
|
+
def generate_html_template(title, is_index, is_file_empty)
|
174
|
+
logo_path = File.join(gem_root_path, "docs/logo.jpg")
|
175
|
+
css_path = File.join(gem_root_path, "assets/slather.css")
|
176
|
+
highlight_js_path = File.join(gem_root_path, "assets/highlight.pack.js")
|
177
|
+
list_js_path = File.join(gem_root_path, "assets/list.min.js")
|
178
|
+
|
179
|
+
builder = Nokogiri::HTML::Builder.new do |doc|
|
180
|
+
doc.html {
|
181
|
+
doc.head {
|
182
|
+
doc.title "#{title} - Slather"
|
183
|
+
doc.link :href => css_path, :media => "all", :rel => "stylesheet"
|
184
|
+
}
|
185
|
+
doc.body {
|
186
|
+
doc.header {
|
187
|
+
doc.div(:class => "row") {
|
188
|
+
doc.a(:href => "index.html") { doc.img(:src => logo_path, :alt => "Slather logo") }
|
189
|
+
}
|
190
|
+
}
|
191
|
+
doc.div(:class => "row") { doc.div(:id => "reports") }
|
192
|
+
doc.footer {
|
193
|
+
doc.div(:class => "row") {
|
194
|
+
doc.p { doc.a("Fork me on Github", :href => "https://github.com/venmo/slather") }
|
195
|
+
doc.p("© #{Date.today.year} Slather")
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
if is_index
|
200
|
+
doc.script :src => list_js_path
|
201
|
+
doc.script "var reports = new List('reports', { valueNames: [ 'data_percentage', 'data_filename', 'data_lines', 'data_relevant', 'data_covered', 'data_missed' ]});"
|
202
|
+
else
|
203
|
+
unless is_file_empty
|
204
|
+
doc.script :src => highlight_js_path
|
205
|
+
doc.script "hljs.initHighlightingOnLoad();"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
}
|
209
|
+
}
|
210
|
+
end
|
211
|
+
builder.doc
|
212
|
+
end
|
213
|
+
|
214
|
+
def gem_root_path
|
215
|
+
File.expand_path File.join(File.dirname(__dir__), "../..")
|
216
|
+
end
|
217
|
+
|
218
|
+
def class_for_coverage_data(coverage_data)
|
219
|
+
case coverage_data
|
220
|
+
when /\d/ then "covered"
|
221
|
+
when /#/ then "missed"
|
222
|
+
else "never"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def hits_for_coverage_data(coverage_data)
|
227
|
+
case coverage_data
|
228
|
+
when /\d/ then (coverage_data.to_i > 0) ? "#{coverage_data}x" : ""
|
229
|
+
when /#/ then "!"
|
230
|
+
else ""
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def class_for_coverage_percentage(percentage)
|
235
|
+
case
|
236
|
+
when percentage > 85 then "cov_high"
|
237
|
+
when percentage > 70 then "cov_medium"
|
238
|
+
else "cov_low"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
data/lib/slather/project.rb
CHANGED
@@ -19,13 +19,14 @@ end
|
|
19
19
|
module Slather
|
20
20
|
class Project < Xcodeproj::Project
|
21
21
|
|
22
|
-
attr_accessor :build_directory, :ignore_list, :ci_service, :coverage_service, :
|
22
|
+
attr_accessor :build_directory, :ignore_list, :ci_service, :coverage_service, :coverage_access_token, :source_directory, :output_directory, :xcodeproj, :show_html
|
23
23
|
|
24
24
|
alias_method :setup_for_coverage, :slather_setup_for_coverage
|
25
25
|
|
26
26
|
def self.open(xcodeproj)
|
27
27
|
proj = super
|
28
28
|
proj.configure_from_yml
|
29
|
+
proj.xcodeproj = xcodeproj
|
29
30
|
proj
|
30
31
|
end
|
31
32
|
|
@@ -70,7 +71,7 @@ module Slather
|
|
70
71
|
configure_build_directory_from_yml
|
71
72
|
configure_ignore_list_from_yml
|
72
73
|
configure_ci_service_from_yml
|
73
|
-
|
74
|
+
configure_coverage_access_token_from_yml
|
74
75
|
configure_coverage_service_from_yml
|
75
76
|
configure_source_directory_from_yml
|
76
77
|
configure_output_directory_from_yml
|
@@ -104,26 +105,28 @@ module Slather
|
|
104
105
|
self.coverage_service ||= (self.class.yml["coverage_service"] || :terminal)
|
105
106
|
end
|
106
107
|
|
107
|
-
def
|
108
|
-
self.
|
108
|
+
def configure_coverage_access_token_from_yml
|
109
|
+
self.coverage_access_token ||= (ENV["COVERAGE_ACCESS_TOKEN"] || self.class.yml["coverage_access_token"] || "")
|
109
110
|
end
|
110
111
|
|
111
112
|
def coverage_service=(service)
|
112
113
|
service = service && service.to_sym
|
113
114
|
if service == :coveralls
|
114
115
|
extend(Slather::CoverageService::Coveralls)
|
116
|
+
elsif service == :hardcover
|
117
|
+
extend(Slather::CoverageService::Hardcover)
|
115
118
|
elsif service == :terminal
|
116
119
|
extend(Slather::CoverageService::SimpleOutput)
|
117
120
|
elsif service == :gutter_json
|
118
121
|
extend(Slather::CoverageService::GutterJsonOutput)
|
119
122
|
elsif service == :cobertura_xml
|
120
123
|
extend(Slather::CoverageService::CoberturaXmlOutput)
|
124
|
+
elsif service == :html
|
125
|
+
extend(Slather::CoverageService::HtmlOutput)
|
121
126
|
else
|
122
|
-
raise ArgumentError, "`#{coverage_service}` is not a valid coverage service. Try `terminal`, `coveralls`, `gutter_json` or `
|
127
|
+
raise ArgumentError, "`#{coverage_service}` is not a valid coverage service. Try `terminal`, `coveralls`, `gutter_json`, `cobertura_xml` or `html`"
|
123
128
|
end
|
124
129
|
@coverage_service = service
|
125
130
|
end
|
126
|
-
|
127
131
|
end
|
128
132
|
end
|
129
|
-
|