ashtonw-slather 1.8.2

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +45 -0
  4. data/.travis.yml +19 -0
  5. data/CHANGELOG.md +132 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +206 -0
  9. data/Rakefile +1 -0
  10. data/assets/highlight.pack.js +1 -0
  11. data/assets/list.min.js +1 -0
  12. data/assets/slather.css +316 -0
  13. data/bin/slather +117 -0
  14. data/docs/logo.jpg +0 -0
  15. data/lib/cocoapods_plugin.rb +10 -0
  16. data/lib/slather.rb +20 -0
  17. data/lib/slather/coverage_file.rb +195 -0
  18. data/lib/slather/coverage_service/cobertura_xml_output.rb +183 -0
  19. data/lib/slather/coverage_service/coveralls.rb +186 -0
  20. data/lib/slather/coverage_service/gutter_json_output.rb +50 -0
  21. data/lib/slather/coverage_service/hardcover.rb +61 -0
  22. data/lib/slather/coverage_service/html_output.rb +244 -0
  23. data/lib/slather/coverage_service/simple_output.rb +31 -0
  24. data/lib/slather/coveralls_coverage_file.rb +13 -0
  25. data/lib/slather/project.rb +132 -0
  26. data/lib/slather/version.rb +3 -0
  27. data/slather.gemspec +32 -0
  28. data/spec/fixtures/fixtures.xcodeproj/project.pbxproj +496 -0
  29. data/spec/fixtures/fixtures.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  30. data/spec/fixtures/fixtures.xcodeproj/xcshareddata/xcschemes/fixtures.xcscheme +69 -0
  31. data/spec/fixtures/fixtures/Supporting Files/fixtures-Prefix.pch +9 -0
  32. data/spec/fixtures/fixtures/fixtures.h +16 -0
  33. data/spec/fixtures/fixtures/fixtures.m +23 -0
  34. data/spec/fixtures/fixtures/fixtures_cpp.cpp +9 -0
  35. data/spec/fixtures/fixtures/fixtures_cpp.h +6 -0
  36. data/spec/fixtures/fixtures/fixtures_m.h +5 -0
  37. data/spec/fixtures/fixtures/fixtures_m.m +5 -0
  38. data/spec/fixtures/fixtures/fixtures_mm.h +5 -0
  39. data/spec/fixtures/fixtures/fixtures_mm.mm +5 -0
  40. data/spec/fixtures/fixtures/more_files/Branches.h +15 -0
  41. data/spec/fixtures/fixtures/more_files/Branches.m +45 -0
  42. data/spec/fixtures/fixtures/more_files/Empty.h +13 -0
  43. data/spec/fixtures/fixtures/more_files/Empty.m +13 -0
  44. data/spec/fixtures/fixtures/more_files/peekaview.h +13 -0
  45. data/spec/fixtures/fixtures/more_files/peekaview.m +31 -0
  46. data/spec/fixtures/fixturesTests/BranchesTests.m +38 -0
  47. data/spec/fixtures/fixturesTests/Supporting Files/en.lproj/InfoPlist.strings +2 -0
  48. data/spec/fixtures/fixturesTests/Supporting Files/fixturesTests-Info.plist +22 -0
  49. data/spec/fixtures/fixturesTests/fixturesTests.m +36 -0
  50. data/spec/fixtures/fixturesTests/peekaviewTests.m +34 -0
  51. data/spec/fixtures/fixtures_html/Branches.m.html +261 -0
  52. data/spec/fixtures/fixtures_html/BranchesTests.m.html +228 -0
  53. data/spec/fixtures/fixtures_html/Empty.m.html +30 -0
  54. data/spec/fixtures/fixtures_html/fixtures.m.html +151 -0
  55. data/spec/fixtures/fixtures_html/fixturesTests.m.html +216 -0
  56. data/spec/fixtures/fixtures_html/fixtures_cpp.cpp.html +30 -0
  57. data/spec/fixtures/fixtures_html/fixtures_m.m.html +30 -0
  58. data/spec/fixtures/fixtures_html/fixtures_mm.mm.html +30 -0
  59. data/spec/fixtures/fixtures_html/index.html +134 -0
  60. data/spec/fixtures/fixtures_html/peekaview.m.html +190 -0
  61. data/spec/fixtures/fixtures_html/peekaviewTests.m.html +206 -0
  62. data/spec/fixtures/gutter.json +1 -0
  63. data/spec/slather/cocoapods_plugin_spec.rb +21 -0
  64. data/spec/slather/coverage_file_spec.rb +337 -0
  65. data/spec/slather/coverage_service/cobertura_xml_spec.rb +49 -0
  66. data/spec/slather/coverage_service/coveralls_spec.rb +122 -0
  67. data/spec/slather/coverage_service/gutter_json_spec.rb +28 -0
  68. data/spec/slather/coverage_service/hardcover_spec.rb +87 -0
  69. data/spec/slather/coverage_service/html_output_spec.rb +179 -0
  70. data/spec/slather/coverage_service/simple_output_spec.rb +35 -0
  71. data/spec/slather/fixtures.gcno +0 -0
  72. data/spec/slather/project_spec.rb +288 -0
  73. data/spec/spec_helper.rb +27 -0
  74. metadata +319 -0
@@ -0,0 +1,20 @@
1
+ require 'slather/version'
2
+ require 'slather/project'
3
+ require 'slather/coverage_file'
4
+ require 'slather/coveralls_coverage_file'
5
+ require 'slather/coverage_service/cobertura_xml_output'
6
+ require 'slather/coverage_service/coveralls'
7
+ require 'slather/coverage_service/hardcover'
8
+ require 'slather/coverage_service/gutter_json_output'
9
+ require 'slather/coverage_service/simple_output'
10
+ require 'slather/coverage_service/html_output'
11
+
12
+ module Slather
13
+
14
+ Encoding.default_external = "utf-8"
15
+
16
+ def self.prepare_pods(pods)
17
+ Pod::UI.warn("[Slather] prepare_pods is now deprecated. The call to prepare_pods in your Podfile can simply be ommitted.")
18
+ end
19
+
20
+ end
@@ -0,0 +1,195 @@
1
+ module Slather
2
+ class CoverageFile
3
+
4
+ attr_accessor :project, :gcno_file_pathname
5
+
6
+ def initialize(project, gcno_file_pathname)
7
+ self.project = project
8
+ self.gcno_file_pathname = Pathname(gcno_file_pathname)
9
+ end
10
+
11
+ def source_file_pathname
12
+ @source_file_pathname ||= begin
13
+ base_filename = gcno_file_pathname.basename.sub_ext("")
14
+ # TODO: Handle Swift
15
+ path = nil
16
+ if project.source_directory
17
+ path = Dir["#{project.source_directory}/**/#{base_filename}.{#{supported_file_extensions.join(",")}}"].first
18
+ path &&= Pathname(path)
19
+ else
20
+ pbx_file = project.files.detect { |pbx_file|
21
+ current_base_filename = pbx_file.real_path.basename
22
+ ext_name = File.extname(current_base_filename.to_s)[1..-1]
23
+ current_base_filename.sub_ext("") == base_filename && supported_file_extensions.include?(ext_name)
24
+ }
25
+ path = pbx_file && pbx_file.real_path
26
+ end
27
+ path
28
+ end
29
+ end
30
+
31
+ def source_file
32
+ File.new(source_file_pathname)
33
+ end
34
+
35
+ def source_data
36
+ source_file.read
37
+ end
38
+
39
+ def source_file_pathname_relative_to_repo_root
40
+ source_file_pathname.realpath.relative_path_from(Pathname("./").realpath)
41
+ end
42
+
43
+ def gcov_data
44
+ @gcov_data ||= begin
45
+ gcov_output = `gcov "#{source_file_pathname}" --object-directory "#{gcno_file_pathname.parent}" --branch-probabilities --branch-counts`
46
+ # Sometimes gcov makes gcov files for Cocoa Touch classes, like NSRange. Ignore and delete later.
47
+ gcov_files_created = gcov_output.scan(/creating '(.+\..+\.gcov)'/)
48
+
49
+ gcov_file_name = "./#{source_file_pathname.basename}.gcov"
50
+ if File.exists?(gcov_file_name)
51
+ gcov_data = File.new(gcov_file_name).read
52
+ else
53
+ gcov_data = ""
54
+ end
55
+
56
+ gcov_files_created.each { |file| FileUtils.rm_f(file) }
57
+ gcov_data
58
+ end
59
+ end
60
+
61
+ def line_coverage_data
62
+ unless cleaned_gcov_data.empty?
63
+ first_line_start = cleaned_gcov_data =~ /^\s+(-|#+|[0-9+]):\s+1:/
64
+
65
+ cleaned_gcov_data[first_line_start..-1].split("\n").map do |line|
66
+ coverage_for_line(line)
67
+ end
68
+ else
69
+ []
70
+ end
71
+ end
72
+
73
+ def cleaned_gcov_data
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
+ data.gsub(/^branch(.*)$\r?\n/, '')
76
+ end
77
+
78
+ def coverage_for_line(line)
79
+ line =~ /^(.+?):/
80
+
81
+ match = $1.strip
82
+ case match
83
+ when /[0-9]+/
84
+ match.to_i
85
+ when /#+/
86
+ 0
87
+ when "-"
88
+ nil
89
+ end
90
+ end
91
+
92
+ def num_lines_tested
93
+ line_coverage_data.compact.select { |cd| cd > 0 }.count
94
+ end
95
+
96
+ def num_lines_testable
97
+ line_coverage_data.compact.count
98
+ end
99
+
100
+ def rate_lines_tested
101
+ if num_lines_testable > 0
102
+ (num_lines_tested / num_lines_testable.to_f)
103
+ else
104
+ 0
105
+ end
106
+ end
107
+
108
+ def percentage_lines_tested
109
+ if num_lines_testable == 0
110
+ 100
111
+ else
112
+ rate_lines_tested * 100
113
+ end
114
+ end
115
+
116
+ def branch_coverage_data
117
+ @branch_coverage_data ||= begin
118
+ branch_coverage_data = Hash.new
119
+
120
+ gcov_data.scan(/(^(\s+(-|#+|[0-9]+):\s+[1-9]+:(.*)$\r?\n)(^branch\s+[0-9]+\s+[a-zA-Z0-9]+\s+[a-zA-Z0-9]+$\r?\n)+)+/) do |data|
121
+ lines = data[0].split("\n")
122
+ line_number = lines[0].split(':')[1].strip.to_i
123
+ branch_coverage_data[line_number] = lines[1..-1].map do |line|
124
+ if line.split(' ')[2].strip == "never"
125
+ 0
126
+ else
127
+ line.split(' ')[3].strip.to_i
128
+ end
129
+ end
130
+ end
131
+ branch_coverage_data
132
+ end
133
+ end
134
+
135
+ def branch_coverage_data_for_statement_on_line(line_number)
136
+ branch_coverage_data[line_number] || []
137
+ end
138
+
139
+ def num_branches_for_statement_on_line(line_number)
140
+ branch_coverage_data_for_statement_on_line(line_number).length
141
+ end
142
+
143
+ def num_branch_hits_for_statement_on_line(line_number)
144
+ branch_coverage_data_for_statement_on_line(line_number).count { |hit_count| hit_count > 0 }
145
+ end
146
+
147
+ def rate_branch_coverage_for_statement_on_line(line_number)
148
+ branch_data = branch_coverage_data_for_statement_on_line(line_number)
149
+ if branch_data.empty?
150
+ 0.0
151
+ else
152
+ (num_branch_hits_for_statement_on_line(line_number) / branch_data.length.to_f)
153
+ end
154
+ end
155
+
156
+ def percentage_branch_coverage_for_statement_on_line(line_number)
157
+ rate_branch_coverage_for_statement_on_line(line_number) * 100
158
+ end
159
+
160
+ def num_branches_testable
161
+ branch_coverage_data.keys.reduce(0) do |sum, line_number|
162
+ sum += num_branches_for_statement_on_line(line_number)
163
+ end
164
+ end
165
+
166
+ def num_branches_tested
167
+ branch_coverage_data.keys.reduce(0) do |sum, line_number|
168
+ sum += num_branch_hits_for_statement_on_line(line_number)
169
+ end
170
+ end
171
+
172
+ def rate_branches_tested
173
+ if (num_branches_testable > 0)
174
+ (num_branches_tested / num_branches_testable.to_f)
175
+ else
176
+ 0.0
177
+ end
178
+ end
179
+
180
+ def source_file_basename
181
+ File.basename(source_file_pathname, '.m')
182
+ end
183
+
184
+ def ignored?
185
+ project.ignore_list.any? do |ignore|
186
+ File.fnmatch(ignore, source_file_pathname_relative_to_repo_root)
187
+ end
188
+ end
189
+
190
+ def supported_file_extensions
191
+ ["cpp", "mm", "m"]
192
+ end
193
+ private :supported_file_extensions
194
+ end
195
+ end
@@ -0,0 +1,183 @@
1
+ require 'nokogiri'
2
+
3
+ module Slather
4
+ module CoverageService
5
+ module CoberturaXmlOutput
6
+
7
+ def coverage_file_class
8
+ Slather::CoverageFile
9
+ end
10
+ private :coverage_file_class
11
+
12
+ def post
13
+ cobertura_xml_report = create_xml_report(coverage_files)
14
+ store_report(cobertura_xml_report)
15
+ end
16
+
17
+ def store_report(report)
18
+ output_file = 'cobertura.xml'
19
+ if output_directory
20
+ FileUtils.mkdir_p(output_directory)
21
+ output_file = File.join(output_directory, output_file)
22
+ end
23
+ File.write(output_file, report.to_s)
24
+ end
25
+
26
+ def grouped_coverage_files
27
+ groups = Hash.new
28
+ coverage_files.each do |coverage_file|
29
+ path = File.dirname(coverage_file.source_file_pathname_relative_to_repo_root)
30
+ if groups[path] == nil
31
+ groups[path] = Array.new
32
+ end
33
+ groups[path].push(coverage_file)
34
+ end
35
+ groups
36
+ end
37
+
38
+ def create_xml_report(coverage_files)
39
+ total_project_lines = 0
40
+ total_project_lines_tested = 0
41
+ total_project_line_rate = '%.16f' % 1.0
42
+ total_project_branches = 0
43
+ total_project_branches_tested = 0
44
+ total_project_branch_rate = '%.16f' % 1.0
45
+
46
+ create_empty_xml_report
47
+ coverage_node = @doc.root
48
+ source_node = @doc.at_css "source"
49
+ source_node.content = Pathname.pwd.to_s
50
+ packages_node = @doc.at_css "packages"
51
+
52
+ # group files by path
53
+ grouped_coverage_files.each do |path , package_coverage_files|
54
+ package_node = Nokogiri::XML::Node.new "package", @doc
55
+ package_node.parent = packages_node
56
+ classes_node = Nokogiri::XML::Node.new "classes", @doc
57
+ classes_node.parent = package_node
58
+ package_node['name'] = path.gsub(/\//, '.')
59
+
60
+ total_package_lines = 0
61
+ total_package_lines_tested = 0
62
+ total_package_lines_rate = '%.16f' % 1.0
63
+ total_package_branches = 0
64
+ total_package_branches_tested = 0
65
+ total_package_branch_rate = '%.16f' % 1.0
66
+
67
+ package_coverage_files.each do |package_coverage_file|
68
+ class_node = create_class_node(package_coverage_file)
69
+ class_node.parent = classes_node
70
+ total_package_lines += package_coverage_file.num_lines_testable
71
+ total_package_lines_tested += package_coverage_file.num_lines_tested
72
+ total_package_branches += package_coverage_file.num_branches_testable
73
+ total_package_branches_tested += package_coverage_file.num_branches_tested
74
+ end
75
+
76
+ if (total_package_lines > 0)
77
+ total_package_line_rate = '%.16f' % (total_package_lines_tested / total_package_lines.to_f)
78
+ end
79
+
80
+ if (total_package_branches > 0)
81
+ total_package_branch_rate = '%.16f' % (total_package_branches_tested / total_package_branches.to_f)
82
+ end
83
+
84
+ package_node['line-rate'] = total_package_line_rate
85
+ package_node['branch-rate'] = total_package_branch_rate
86
+ package_node['complexity'] = '0.0'
87
+
88
+ total_project_lines += total_package_lines
89
+ total_project_lines_tested += total_package_lines_tested
90
+ total_project_branches += total_package_branches
91
+ total_project_branches_tested += total_package_branches_tested
92
+ end
93
+
94
+ if (total_project_lines > 0)
95
+ total_project_line_rate = '%.16f' % (total_project_lines_tested / total_project_lines.to_f)
96
+ end
97
+
98
+ if (total_project_branches > 0)
99
+ total_project_branch_rate = '%.16f' % (total_project_branches_tested / total_project_branches.to_f)
100
+ end
101
+
102
+ coverage_node['line-rate'] = total_project_line_rate
103
+ coverage_node['branch-rate'] = total_project_branch_rate
104
+ coverage_node['lines-covered'] = total_project_lines_tested
105
+ coverage_node['lines-valid'] = total_project_lines
106
+ coverage_node['branches-covered'] = total_project_branches_tested
107
+ coverage_node['branches-valid'] = total_project_branches
108
+ coverage_node['complexity'] = "0.0"
109
+ coverage_node['timestamp'] = DateTime.now.strftime('%s')
110
+ coverage_node['version'] = "Slather #{Slather::VERSION}"
111
+ @doc.to_xml
112
+ end
113
+
114
+ def create_class_node(coverage_file)
115
+ filename = coverage_file.source_file_basename
116
+ filepath = coverage_file.source_file_pathname_relative_to_repo_root.to_s
117
+
118
+ class_node = Nokogiri::XML::Node.new "class", @doc
119
+ class_node['name'] = filename
120
+ class_node['filename'] = filepath
121
+ class_node['line-rate'] = '%.16f' % [(coverage_file.num_lines_testable > 0) ? coverage_file.rate_lines_tested : 1.0]
122
+ class_node['branch-rate'] = '%.16f' % [(coverage_file.num_branches_testable > 0) ? coverage_file.rate_branches_tested : 1.0]
123
+ class_node['complexity'] = '0.0'
124
+
125
+ methods_node = Nokogiri::XML::Node.new "methods", @doc
126
+ methods_node.parent = class_node
127
+ lines_node = Nokogiri::XML::Node.new "lines", @doc
128
+ lines_node.parent = class_node
129
+
130
+ coverage_file.cleaned_gcov_data.split("\n").each do |line|
131
+ line_segments = line.split(':')
132
+ if coverage_file.coverage_for_line(line)
133
+ line_node = create_line_node(line, coverage_file)
134
+ line_node.parent = lines_node
135
+ end
136
+ end
137
+ class_node
138
+ end
139
+
140
+ def create_line_node(line, coverage_file)
141
+ line_number = line.split(':')[1].strip.to_i
142
+ line_node = Nokogiri::XML::Node.new "line", @doc
143
+ line_node['number'] = line_number
144
+ line_node['branch'] = "false"
145
+ line_node['hits'] = coverage_file.coverage_for_line(line)
146
+
147
+ unless coverage_file.branch_coverage_data_for_statement_on_line(line_number).empty?
148
+ line_node['branch'] = "true"
149
+ conditions_node = Nokogiri::XML::Node.new "conditions", @doc
150
+ conditions_node.parent = line_node
151
+ condition_node = Nokogiri::XML::Node.new "condition", @doc
152
+ condition_node.parent = conditions_node
153
+ condition_node['number'] = "0"
154
+ condition_node['type'] = "jump"
155
+ branches_testable = coverage_file.num_branches_for_statement_on_line(line_number)
156
+ branch_hits = coverage_file.num_branch_hits_for_statement_on_line(line_number)
157
+ condition_coverage = coverage_file.percentage_branch_coverage_for_statement_on_line(line_number)
158
+ condition_node['coverage'] = "#{condition_coverage.to_i}%"
159
+ line_node['condition-coverage'] = "#{condition_coverage.to_i}% (#{branch_hits}/#{branches_testable})"
160
+ end
161
+ line_node
162
+ end
163
+
164
+ def create_empty_xml_report
165
+ builder = Nokogiri::XML::Builder.new do |xml|
166
+ xml.doc.create_internal_subset(
167
+ 'coverage',
168
+ nil,
169
+ "http://cobertura.sourceforge.net/xml/coverage-04.dtd"
170
+ )
171
+ xml.coverage do
172
+ xml.sources do
173
+ xml.source
174
+ end
175
+ xml.packages
176
+ end
177
+ end
178
+ @doc = builder.doc
179
+ end
180
+
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,186 @@
1
+ module Slather
2
+ module CoverageService
3
+ module Coveralls
4
+
5
+ def coverage_file_class
6
+ Slather::CoverallsCoverageFile
7
+ end
8
+ private :coverage_file_class
9
+
10
+ def travis_job_id
11
+ ENV['TRAVIS_JOB_ID']
12
+ end
13
+ private :travis_job_id
14
+
15
+ def circleci_job_id
16
+ ENV['CIRCLE_BUILD_NUM']
17
+ end
18
+ private :circleci_job_id
19
+
20
+ def circleci_pull_request
21
+ ENV['CIRCLE_PR_NUMBER'] || ENV['CI_PULL_REQUEST'] || ""
22
+ end
23
+ private :circleci_pull_request
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 buildkite_job_id
41
+ ENV['BUILDKITE_BUILD_NUMBER']
42
+ end
43
+ private :buildkite_job_id
44
+
45
+ def buildkite_pull_request
46
+ ENV['BUILDKITE_PULL_REQUEST']
47
+ end
48
+ private :buildkite_pull_request
49
+
50
+ def jenkins_git_info
51
+ {
52
+ head: {
53
+ id: ENV['sha1'],
54
+ author_name: ENV['ghprbActualCommitAuthor'],
55
+ message: ENV['ghprbPullTitle']
56
+ },
57
+ branch: jenkins_branch_name
58
+ }
59
+ end
60
+ private :jenkins_git_info
61
+
62
+ def circleci_build_url
63
+ "https://circleci.com/gh/" + ENV['CIRCLE_PROJECT_USERNAME'] || "" + "/" + ENV['CIRCLE_PROJECT_REPONAME'] || "" + "/" + ENV['CIRCLE_BUILD_NUM'] || ""
64
+ end
65
+ private :circleci_build_url
66
+
67
+ def circleci_git_info
68
+ {
69
+ :head => {
70
+ :id => (ENV['CIRCLE_SHA1'] || ""),
71
+ :author_name => (ENV['CIRCLE_PR_USERNAME'] || ENV['CIRCLE_USERNAME'] || ""),
72
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
73
+ },
74
+ :branch => (ENV['CIRCLE_BRANCH'] || "")
75
+ }
76
+ end
77
+ private :circleci_git_info
78
+
79
+ def buildkite_git_info
80
+ {
81
+ :head => {
82
+ :id => ENV['BUILDKITE_COMMIT'],
83
+ :author_name => (`git log --format=%an -n 1 HEAD`.chomp || ""),
84
+ :author_email => (`git log --format=%ae -n 1 HEAD`.chomp || ""),
85
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
86
+ },
87
+ :branch => ENV['BUILDKITE_BRANCH']
88
+ }
89
+ end
90
+
91
+ def buildkite_build_url
92
+ "https://buildkite.com/" + ENV['BUILDKITE_PROJECT_SLUG'] + "/builds/" + ENV['BUILDKITE_BUILD_NUMBER'] + "#"
93
+ end
94
+
95
+ def coveralls_coverage_data
96
+ if ci_service == :travis_ci || ci_service == :travis_pro
97
+ if travis_job_id
98
+ if ci_service == :travis_ci
99
+ {
100
+ :service_job_id => travis_job_id,
101
+ :service_name => "travis-ci",
102
+ :source_files => coverage_files.map(&:as_json)
103
+ }.to_json
104
+ elsif ci_service == :travis_pro
105
+ {
106
+ :service_job_id => travis_job_id,
107
+ :service_name => "travis-pro",
108
+ :repo_token => coverage_access_token,
109
+ :source_files => coverage_files.map(&:as_json)
110
+ }.to_json
111
+ end
112
+ else
113
+ raise StandardError, "Environment variable `TRAVIS_JOB_ID` not set. Is this running on a travis build?"
114
+ end
115
+ elsif ci_service == :circleci
116
+ if circleci_job_id
117
+ coveralls_hash = {
118
+ :service_job_id => circleci_job_id,
119
+ :service_name => "circleci",
120
+ :repo_token => coverage_access_token,
121
+ :source_files => coverage_files.map(&:as_json),
122
+ :git => circleci_git_info,
123
+ :service_build_url => circleci_build_url
124
+ }
125
+
126
+ if circleci_pull_request != nil && circleci_pull_request.length > 0
127
+ coveralls_hash[:service_pull_request] = circleci_pull_request.split("/").last
128
+ end
129
+
130
+ coveralls_hash.to_json
131
+ else
132
+ raise StandardError, "Environment variable `CIRCLE_BUILD_NUM` not set. Is this running on a circleci build?"
133
+ end
134
+ elsif ci_service == :jenkins
135
+ if jenkins_job_id
136
+ {
137
+ service_job_id: jenkins_job_id,
138
+ service_name: "jenkins",
139
+ repo_token: coverage_access_token,
140
+ source_files: coverage_files.map(&:as_json),
141
+ git: jenkins_git_info
142
+ }.to_json
143
+ else
144
+ raise StandardError, "Environment variable `BUILD_ID` not set. Is this running on a jenkins build?"
145
+ end
146
+ elsif ci_service == :buildkite
147
+ if buildkite_job_id
148
+ {
149
+ :service_job_id => buildkite_job_id,
150
+ :service_name => "buildkite",
151
+ :repo_token => coverage_access_token,
152
+ :source_files => coverage_files.map(&:as_json),
153
+ :git => buildkite_git_info,
154
+ :service_build_url => buildkite_build_url,
155
+ :service_pull_request => buildkite_pull_request
156
+ }.to_json
157
+ else
158
+ raise StandardError, "Environment variable `BUILDKITE_BUILD_NUMBER` not set. Is this running on a buildkite build?"
159
+ end
160
+ else
161
+ raise StandardError, "No support for ci named #{ci_service}"
162
+ end
163
+ end
164
+ private :coveralls_coverage_data
165
+
166
+ def post
167
+ f = File.open('coveralls_json_file', 'w+')
168
+ begin
169
+ f.write(coveralls_coverage_data)
170
+ f.close
171
+ `curl -s --form json_file=@#{f.path} #{coveralls_api_jobs_path}`
172
+ rescue StandardError => e
173
+ FileUtils.rm(f)
174
+ raise e
175
+ end
176
+ FileUtils.rm(f)
177
+ end
178
+
179
+ def coveralls_api_jobs_path
180
+ "https://coveralls.io/api/v1/jobs"
181
+ end
182
+ private :coveralls_api_jobs_path
183
+
184
+ end
185
+ end
186
+ end