slather 2.4.8 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24ee530494c9f131751a85dba16a4bc09292c187d045be17b1212d9cf4038378
4
- data.tar.gz: 4c5dabc3de752ebb88998ca29d87d6f072e4477a909926d4237078a2a9f73bc2
3
+ metadata.gz: d6388d4f62571f927f845978e5383f2508b98e7e3ba0205aaf546b5a54d465f5
4
+ data.tar.gz: 837f82512416a6f57cb9c4510dcc7bd9524a4aeeaa05f42bdd841f18cf4fa1d9
5
5
  SHA512:
6
- metadata.gz: b7d4a1db210237adec6b9c03634774991a209c4aa64c10dea0a73208642298082b9a76f9c0e979b68a4601c6c9ff37f92d6f05bfd3c8a35429bd78cc8ac9549c
7
- data.tar.gz: 9bf87cccabbd4b243e8ba9c519d491818a38924125694ca8701b3b34764a8c9ae167919b764638fa0af27b137dbbf10d9188b3e6297f93f3d1673ec07566d817
6
+ metadata.gz: 2b1af2387a7475860aeb3666883c5fd8d2e2b9be020680452140e71fa5bbb3ff057eb3b23b0ddb1c02d6fd55478aafceda18f5527ed2bd086b49d0d89a06e75b
7
+ data.tar.gz: 0b464fbffa5722ed27fa157e429427387889e9e5c641ed2d2d2663a90ccc6f815163e19687a21fac2078dbb6c9c8c8baf9745ff1b55266e38f220aed6258c66f
data/.travis.yml CHANGED
@@ -1,10 +1,10 @@
1
1
  language: objective-c
2
2
  script: bundle exec rake
3
- osx_image: xcode9.2
3
+ osx_image: xcode12.2
4
4
 
5
5
  before_install:
6
6
  - curl http://curl.haxx.se/ca/cacert.pem -o /usr/local/share/cacert.pem
7
- - gem install bundler -v "~> 1.0" --no-ri --no-rdoc
7
+ - gem install bundler -v "~> 2.0" --no-document
8
8
 
9
9
  install:
10
10
  - bundle install --without=documentation
data/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v2.7.0
4
+
5
+ * Add Branch Coverage data for ProfData coverage files
6
+ [hborawski](https://github.com/hborawski)
7
+ [#477](https://github.com/SlatherOrg/slather/pull/477)
8
+
9
+ * Fixed 'Argument list too long' when running 'xcrun llvm-cov'
10
+ [samuelsainz](https://github.com/samuelsainz)
11
+ [#476](https://github.com/SlatherOrg/slather/pull/476)
12
+
13
+ ## v2.6.1
14
+
15
+ * Update nokogiri to 1.11
16
+ [ashin-omg](https://github.com/ashin-omg)
17
+ [#473](https://github.com/SlatherOrg/slather/pull/473)
18
+
19
+ ## v2.6.0
20
+
21
+ * Added GitHub actions support
22
+ [martin-key](https://github.com/martin-key), [troyfontaine](https://github.com/troyfontaine)
23
+ [#468](https://github.com/SlatherOrg/slather/pull/468)
24
+
25
+ ## v2.5.0
26
+
27
+ * Fixed activesupport and cocoapods dependencies
28
+ [daneov](https://github.com/daneov)
29
+ [#456](https://github.com/SlatherOrg/slather/pull/467)
30
+
31
+ * Fixed typo in documentation
32
+ [descorp](https://github.com/descorp)
33
+ [#456](https://github.com/SlatherOrg/slather/pull/463)
34
+
35
+ ## v2.4.9
36
+
37
+ * Added support for Sonarqube output
38
+ [adellibovi](https://github.com/adellibovi)
39
+ [#456](https://github.com/SlatherOrg/slather/pull/456)
40
+
3
41
  ## v2.4.8
4
42
 
5
43
  * Optimize performance for many binaries
data/README.md CHANGED
@@ -149,7 +149,7 @@ ignore:
149
149
  - ProjectTestsGroup/*
150
150
  ```
151
151
 
152
- And then in your `.travis.yml` or `circle.yml`, call `slather` after a successful build:
152
+ And then in your `.travis.yml` or `circle.yml` or `github-action.yml`, call `slather` after a successful build:
153
153
 
154
154
  ```yml
155
155
  # .travis.yml
@@ -168,6 +168,25 @@ test:
168
168
 
169
169
  ```
170
170
 
171
+ ```yml
172
+ # github-action.yml
173
+ myjob:
174
+ steps:
175
+ - run: |
176
+ bundle config path vendor/bundle
177
+ bundle install --without=documentation --jobs 4 --retry 3
178
+ - name: Extract branch name
179
+ shell: bash
180
+ run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
181
+ id: get_branch
182
+ - run: bundle exec slather
183
+ env:
184
+ GIT_BRANCH: ${{ steps.get_branch.outputs.branch }}
185
+ CI_PULL_REQUEST: ${{ github.event.number }}
186
+ COVERAGE_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
187
+
188
+ ```
189
+
171
190
  #### Usage with Travis CI Pro
172
191
 
173
192
  To use Coveralls with Travis CI Pro (for private repos), add following lines along with other settings to `.slather.yml`:
@@ -265,3 +284,4 @@ Please make sure to follow our general coding style and add test coverage for ne
265
284
  * [@jhersh](https://github.com/jhersh), CircleCI support.
266
285
  * [@tarbrain](https://github.com/tarbrain), Cobertura support and bugfixing.
267
286
  * [@ikhsan](https://github.com/ikhsan), html support.
287
+ * [@martin-key](https://github.com/martin-key) and [@troyfontaine](https://github.com/troyfontaine), Github Actions support.
data/assets/slather.css CHANGED
@@ -74,6 +74,7 @@ table.source_code {
74
74
  table.source_code td {
75
75
  padding-bottom: 0.3em;
76
76
  }
77
+ code.missed { background-color: rgba(255, 73, 76, 0.3); }
77
78
  table.source_code tr.missed td { background-color: rgba(248, 103, 105, 0.2); }
78
79
  table.source_code tr.covered td { background-color: rgba(103, 207, 124, 0.2); }
79
80
  table.source_code td.num {
@@ -124,7 +125,7 @@ footer p, footer a {
124
125
  Syntax Highlighting using highlight.js (https://highlightjs.org)
125
126
  ------------------------------------------------------------- */
126
127
  .hljs {
127
- display: block;
128
+ display: inline-block;
128
129
  overflow-x: auto;
129
130
  -webkit-text-size-adjust: none;
130
131
  }
data/lib/slather.rb CHANGED
@@ -12,6 +12,7 @@ require 'slather/coverage_service/simple_output'
12
12
  require 'slather/coverage_service/html_output'
13
13
  require 'slather/coverage_service/json_output'
14
14
  require 'slather/coverage_service/llvm_cov_output'
15
+ require 'slather/coverage_service/sonarqube_xml_output'
15
16
  require 'cfpropertylist'
16
17
 
17
18
  module Slather
@@ -8,11 +8,13 @@ class CoverageCommand < Clamp::Command
8
8
  option ["--jenkins"], :flag, "Indicate that the builds are running on Jenkins"
9
9
  option ["--buildkite"], :flag, "Indicate that the builds are running on Buildkite"
10
10
  option ["--teamcity"], :flag, "Indicate that the builds are running on TeamCity"
11
+ option ["--github"], :flag, "Indicate that the builds are running on Github Actions"
11
12
 
12
13
  option ["--coveralls", "-c"], :flag, "Post coverage results to coveralls"
13
14
  option ["--simple-output", "-s"], :flag, "Output coverage results to the terminal"
14
15
  option ["--gutter-json", "-g"], :flag, "Output coverage results as Gutter JSON format"
15
16
  option ["--cobertura-xml", "-x"], :flag, "Output coverage results as Cobertura XML format"
17
+ option ["--sonarqube-xml", "-sq"], :flag, "Output coverage results as SonarQube XML format"
16
18
  option ["--llvm-cov", "-r"], :flag, "Output coverage as llvm-cov format"
17
19
  option ["--json"], :flag, "Output coverage results as simple JSON"
18
20
  option ["--html"], :flag, "Output coverage results as static html pages"
@@ -90,6 +92,8 @@ class CoverageCommand < Clamp::Command
90
92
  project.ci_service = :buildkite
91
93
  elsif teamcity?
92
94
  project.ci_service = :teamcity
95
+ elsif github?
96
+ project.ci_service = :github
93
97
  end
94
98
  end
95
99
 
@@ -124,6 +128,8 @@ class CoverageCommand < Clamp::Command
124
128
  project.show_html = show?
125
129
  elsif json?
126
130
  project.coverage_service = :json
131
+ elsif sonarqube_xml?
132
+ project.coverage_service = :sonarqube_xml
127
133
  end
128
134
  end
129
135
 
@@ -43,18 +43,23 @@ module Slather
43
43
 
44
44
  def gcov_data
45
45
  @gcov_data ||= begin
46
- gcov_output = `gcov "#{source_file_pathname}" --object-directory "#{gcno_file_pathname.parent}" --branch-probabilities --branch-counts`
47
- # Sometimes gcov makes gcov files for Cocoa Touch classes, like NSRange. Ignore and delete later.
48
- gcov_files_created = gcov_output.scan(/creating '(.+\..+\.gcov)'/)
46
+ gcov_data = ""
47
+
48
+ Dir.chdir(project.project_dir) do
49
+ gcov_output = `gcov "#{source_file_pathname}" --object-directory "#{gcno_file_pathname.parent}" --branch-probabilities --branch-counts`
50
+ # Sometimes gcov makes gcov files for Cocoa Touch classes, like NSRange. Ignore and delete later.
51
+ gcov_files_created = gcov_output.scan(/creating '(.+\..+\.gcov)'/)
52
+
53
+ gcov_file_name = "./#{source_file_pathname.basename}.gcov"
54
+ if File.exists?(gcov_file_name)
55
+ gcov_data = File.new(gcov_file_name).read
56
+ else
57
+ gcov_data = ""
58
+ end
49
59
 
50
- gcov_file_name = "./#{source_file_pathname.basename}.gcov"
51
- if File.exists?(gcov_file_name)
52
- gcov_data = File.new(gcov_file_name).read
53
- else
54
- gcov_data = ""
60
+ gcov_files_created.each { |file| FileUtils.rm_f(file) }
55
61
  end
56
62
 
57
- gcov_files_created.each { |file| FileUtils.rm_f(file) }
58
63
  gcov_data
59
64
  end
60
65
  end
@@ -36,6 +36,21 @@ module Slather
36
36
  end
37
37
  private :jenkins_job_id
38
38
 
39
+ def github_job_id
40
+ ENV['GITHUB_RUN_ID']
41
+ end
42
+ private :github_job_id
43
+
44
+ def github_pull_request
45
+ ENV['CI_PULL_REQUEST'] || ""
46
+ end
47
+ private :github_pull_request
48
+
49
+ def github_repo_name
50
+ ENV['GITHUB_REPOSITORY'] || ""
51
+ end
52
+ private :github_repo_name
53
+
39
54
  def jenkins_branch_name
40
55
  branch_name = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME']
41
56
  if branch_name.include? 'origin/'
@@ -51,6 +66,11 @@ module Slather
51
66
  end
52
67
  private :teamcity_branch_name
53
68
 
69
+ def github_branch_name
70
+ ENV['GIT_BRANCH'] || `git ls-remote --heads origin | grep $(git rev-parse HEAD) | cut -d / -f 3-`.chomp
71
+ end
72
+ private :github_branch_name
73
+
54
74
  def buildkite_job_id
55
75
  ENV['BUILDKITE_BUILD_NUMBER']
56
76
  end
@@ -119,6 +139,23 @@ module Slather
119
139
  "https://buildkite.com/" + ENV['BUILDKITE_PROJECT_SLUG'] + "/builds/" + ENV['BUILDKITE_BUILD_NUMBER'] + "#"
120
140
  end
121
141
 
142
+ def github_git_info
143
+ {
144
+ :head => {
145
+ :id => ENV['GITHUB_SHA'],
146
+ :author_name => ENV['GITHUB_ACTOR'],
147
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
148
+ },
149
+ :branch => github_branch_name
150
+ }
151
+ end
152
+ private :github_git_info
153
+
154
+ def github_build_url
155
+ "https://github.com/" + ENV['GITHUB_REPOSITORY'] + "/actions/runs/" + ENV['GITHUB_RUN_ID']
156
+ end
157
+ private :github_build_url
158
+
122
159
  def coveralls_coverage_data
123
160
  if ci_service == :travis_ci || ci_service == :travis_pro
124
161
  if travis_job_id
@@ -206,6 +243,26 @@ module Slather
206
243
  else
207
244
  raise StandardError, "Environment variable `TC_BUILD_NUMBER` not set. Is this running on a teamcity build?"
208
245
  end
246
+ elsif ci_service == :github
247
+
248
+ if coverage_access_token.to_s.strip.length == 0
249
+ raise StandardError, "Access token is not set. Uploading coverage data for private repositories requires an access token."
250
+ end
251
+
252
+ if github_job_id
253
+ {
254
+ :service_job_id => github_job_id,
255
+ :service_name => "github",
256
+ :repo_token => coverage_access_token,
257
+ :repo_name => github_repo_name,
258
+ :source_files => coverage_files.map(&:as_json),
259
+ :service_build_url => github_build_url,
260
+ :service_pull_request => github_pull_request,
261
+ :git => github_git_info
262
+ }.to_json
263
+ else
264
+ raise StandardError, "Environment variable `GITHUB_RUN_ID` not set. Is this running on github build?"
265
+ end
209
266
  else
210
267
  raise StandardError, "No support for ci named #{ci_service}"
211
268
  end
@@ -70,9 +70,14 @@ module Slather
70
70
 
71
71
  total_relevant_lines = 0
72
72
  total_tested_lines = 0
73
+ total_relevant_branches = 0
74
+ total_branches_tested = 0
73
75
  coverage_files.each { |coverage_file|
74
76
  total_tested_lines += coverage_file.num_lines_tested
75
77
  total_relevant_lines += coverage_file.num_lines_testable
78
+
79
+ total_relevant_branches += coverage_file.num_branches_testable
80
+ total_branches_tested += coverage_file.num_branches_tested
76
81
  }
77
82
 
78
83
  builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
@@ -84,6 +89,12 @@ module Slather
84
89
  cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
85
90
  }
86
91
 
92
+ cov.h4 {
93
+ percentage = (total_branches_tested / total_relevant_branches.to_f) * 100.0
94
+ cov.span "Total Branch Coverage : "
95
+ cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
96
+ }
97
+
87
98
  cov.input(:class => "search", :placeholder => "Search")
88
99
 
89
100
  cov.table(:class => "coverage_list", :cellspacing => 0, :cellpadding => 0) {
@@ -133,6 +144,7 @@ module Slather
133
144
  filepath = coverage_file.source_file_pathname_relative_to_repo_root
134
145
  filename = File.basename(filepath)
135
146
  percentage = coverage_file.percentage_lines_tested
147
+ branch_percentage = coverage_file.rate_branches_tested * 100
136
148
 
137
149
  cleaned_gcov_lines = coverage_file.cleaned_gcov_data.split("\n")
138
150
  is_file_empty = (cleaned_gcov_lines.count <= 0)
@@ -142,7 +154,10 @@ module Slather
142
154
  builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
143
155
  cov.h2(:class => "cov_title") {
144
156
  cov.span("Coverage for \"#{filename}\"" + (!is_file_empty ? " : " : ""))
157
+ cov.span("Lines: ") unless is_file_empty
145
158
  cov.span("#{decimal_f(percentage)}%", :class => class_for_coverage_percentage(percentage)) unless is_file_empty
159
+ cov.span(" Branches: ") unless is_file_empty
160
+ cov.span("#{decimal_f(branch_percentage)}%", :class => class_for_coverage_percentage(branch_percentage)) unless is_file_empty
146
161
  }
147
162
 
148
163
  cov.h4("(#{coverage_file.num_lines_tested} of #{coverage_file.num_lines_testable} relevant lines covered)", :class => "cov_subtitle")
@@ -157,8 +172,9 @@ module Slather
157
172
 
158
173
  cov.table(:class => "source_code") {
159
174
  cleaned_gcov_lines.each do |line|
160
-
161
175
  line_number = coverage_file.line_number_in_line(line)
176
+ missed_regions = coverage_file.branch_region_data[line_number]
177
+ hits = coverage_file.coverage_for_line(line)
162
178
  next unless line_number > 0
163
179
 
164
180
  line_source = line.split(line_number_separator, 3)[2]
@@ -171,7 +187,30 @@ module Slather
171
187
  cov.td(line, :class => classes[idx])
172
188
  else
173
189
  cov.td(:class => classes[idx]) {
174
- cov.pre { cov.code(line, :class => "objc") }
190
+ cov.pre {
191
+ # If the line has coverage and missed regions, split up
192
+ # the line to show regions that weren't covered
193
+ if missed_regions != nil && hits != nil && hits > 0
194
+ regions = missed_regions.map do |region|
195
+ region_start, region_length = region
196
+ if region_length != nil
197
+ line[region_start, region_length]
198
+ else
199
+ line[region_start, line.length - region_start]
200
+ end
201
+ end
202
+ current_line = line
203
+ regions.each do |region|
204
+ covered, remainder = current_line.split(region)
205
+ cov.code(covered, :class => "objc")
206
+ cov.code(region, :class => "objc missed")
207
+ current_line = remainder
208
+ end
209
+ cov.code(current_line, :class => "objc")
210
+ else
211
+ cov.code(line, :class => "objc")
212
+ end
213
+ }
175
214
  }
176
215
  end
177
216
  }
@@ -0,0 +1,61 @@
1
+ require 'nokogiri'
2
+ require 'date'
3
+
4
+ module Slather
5
+ module CoverageService
6
+ module SonarqubeXmlOutput
7
+
8
+ def coverage_file_class
9
+ if input_format == "profdata"
10
+ Slather::ProfdataCoverageFile
11
+ else
12
+ Slather::CoverageFile
13
+ end
14
+ end
15
+ private :coverage_file_class
16
+
17
+ def post
18
+ cobertura_xml_report = create_xml_report(coverage_files)
19
+ store_report(cobertura_xml_report)
20
+ end
21
+
22
+ def store_report(report)
23
+ output_file = 'sonarqube-generic-coverage.xml'
24
+ if output_directory
25
+ FileUtils.mkdir_p(output_directory)
26
+ output_file = File.join(output_directory, output_file)
27
+ end
28
+ File.write(output_file, report.to_s)
29
+ end
30
+
31
+ def create_xml_report(coverage_files)
32
+ create_empty_xml_report
33
+ coverage_node = @doc.root
34
+ coverage_node['version'] = "1"
35
+
36
+ coverage_files.each do |coverage_file|
37
+ file_node = Nokogiri::XML::Node.new "file", @doc
38
+ file_node.parent = coverage_node
39
+ file_node['path'] = coverage_file.source_file_pathname_relative_to_repo_root.to_s
40
+ coverage_file.all_lines.each do |line|
41
+ if coverage_file.coverage_for_line(line)
42
+ line_node = Nokogiri::XML::Node.new "lineToCover", @doc
43
+ line_node['lineNumber'] = coverage_file.line_number_in_line(line)
44
+ line_node['covered'] = coverage_file.coverage_for_line(line) == 0 ? "false" : "true"
45
+ line_node.parent = file_node
46
+ end
47
+ end
48
+ end
49
+ @doc.to_xml
50
+ end
51
+
52
+ def create_empty_xml_report
53
+ builder = Nokogiri::XML::Builder.new do |xml|
54
+ xml.coverage
55
+ end
56
+ @doc = builder.doc
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -8,7 +8,7 @@ module Slather
8
8
  include CoverageInfo
9
9
  include CoverallsCoverage
10
10
 
11
- attr_accessor :project, :source, :line_numbers_first, :line_data
11
+ attr_accessor :project, :source, :segments, :line_numbers_first, :line_data
12
12
 
13
13
  def initialize(project, source, line_numbers_first)
14
14
  self.project = project
@@ -188,7 +188,47 @@ module Slather
188
188
 
189
189
  def branch_coverage_data
190
190
  @branch_coverage_data ||= begin
191
- Hash.new
191
+ branch_coverage_data = Hash.new
192
+
193
+ self.segments.each do |segment|
194
+ line, col, hits, has_count, *rest = segment
195
+ next if !has_count
196
+ if branch_coverage_data.key?(line)
197
+ branch_coverage_data[line] = branch_coverage_data[line] + [hits]
198
+ else
199
+ branch_coverage_data[line] = [hits]
200
+ end
201
+ end
202
+
203
+ branch_coverage_data
204
+ end
205
+ end
206
+
207
+ def branch_region_data
208
+ @branch_region_data ||= begin
209
+ branch_region_data = Hash.new
210
+ region_start = nil
211
+ current_line = 0
212
+ @segments ||= []
213
+ @segments.each do |segment|
214
+ line, col, hits, has_count, *rest = segment
215
+ # Make column 0 based index
216
+ col = col - 1
217
+ if hits == 0 && has_count
218
+ current_line = line
219
+ region_start = col
220
+ elsif region_start != nil && hits > 0 && has_count
221
+ # if the region wrapped to a new line before ending, put nil to indicate it didnt end on this line
222
+ region_end = line == current_line ? col - region_start : nil
223
+ if branch_region_data.key?(current_line)
224
+ branch_region_data[current_line] = branch_region_data[current_line] + [region_start, region_end]
225
+ else
226
+ branch_region_data[current_line] = [[region_start, region_end]]
227
+ end
228
+ region_start = nil
229
+ end
230
+ end
231
+ branch_region_data
192
232
  end
193
233
  end
194
234
 
@@ -135,7 +135,7 @@ module Slather
135
135
  coverage_json = JSON.parse(coverage_json_string)
136
136
  coverage_json["data"].reduce([]) do |result, chunk|
137
137
  result.concat(chunk["files"].map do |file|
138
- Pathname(file["filename"]).realpath
138
+ {"filename" => Pathname(file["filename"]).realpath, "segments" => file["segments"]}
139
139
  end)
140
140
  end
141
141
  end
@@ -162,13 +162,24 @@ module Slather
162
162
  end
163
163
  private :create_coverage_files_for_binary
164
164
 
165
- def create_coverage_files(binary_path, pathnames)
165
+ def create_coverage_files(binary_path, path_objects)
166
166
  line_numbers_first = Gem::Version.new(self.llvm_version) >= Gem::Version.new('8.1.0')
167
+ # get just file names from the path objects
168
+ pathnames = path_objects.map { |path_obj| path_obj["filename"] }.compact
169
+ # Map of path name => segment array
170
+ paths_to_segments = path_objects.reduce(Hash.new) do |hash, path_obj|
171
+ hash[path_obj["filename"]] = path_obj["segments"]
172
+ hash
173
+ end
167
174
  files = create_profdata(binary_path, pathnames)
168
175
  files.map do |source|
169
176
  coverage_file = coverage_file_class.new(self, source, line_numbers_first)
170
177
  # If a single source file is used, the resulting output does not contain the file name.
171
178
  coverage_file.source_file_pathname = pathnames.first if pathnames.count == 1
179
+ # if there is segment data for the given path, add it to the coverage_file
180
+ if paths_to_segments.key?(coverage_file.source_file_pathname)
181
+ coverage_file.segments = paths_to_segments[coverage_file.source_file_pathname]
182
+ end
172
183
  !coverage_file.ignored? ? coverage_file : nil
173
184
  end.compact
174
185
  end
@@ -277,7 +288,10 @@ module Slather
277
288
  if self.arch
278
289
  llvm_cov_args << "--arch" << self.arch
279
290
  end
280
- `xcrun llvm-cov #{llvm_cov_args.shelljoin} #{source_files.shelljoin}`
291
+
292
+ # POSIX systems have an ARG_MAX for the maximum total length of the command line, so the command may fail with an error message of "Argument list too long".
293
+ # Using the xargs command we can break the list of source_files into sublists small enough to be acceptable.
294
+ `printf '%s\\0' #{source_files.shelljoin} | xargs -0 xcrun llvm-cov #{llvm_cov_args.shelljoin}`
281
295
  end
282
296
  private :unsafe_profdata_llvm_cov_output
283
297
 
@@ -424,6 +438,8 @@ module Slather
424
438
  extend(Slather::CoverageService::HtmlOutput)
425
439
  when :json
426
440
  extend(Slather::CoverageService::JsonOutput)
441
+ when :sonarqube_xml
442
+ extend(Slather::CoverageService::SonarqubeXmlOutput)
427
443
  else
428
444
  raise ArgumentError, "`#{coverage_service}` is not a valid coverage service. Try `terminal`, `coveralls`, `gutter_json`, `cobertura_xml` or `html`"
429
445
  end
@@ -1,3 +1,3 @@
1
1
  module Slather
2
- VERSION = '2.4.8' unless defined?(Slather::VERSION)
2
+ VERSION = '2.7.0' unless defined?(Slather::VERSION)
3
3
  end
data/slather.gemspec CHANGED
@@ -17,20 +17,20 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ['lib']
19
19
 
20
- spec.add_development_dependency 'bundler', '~> 1.17'
20
+ spec.add_development_dependency 'bundler', '~> 2.0'
21
21
  spec.add_development_dependency 'coveralls', '~> 0.8'
22
22
  spec.add_development_dependency 'simplecov', '~> 0'
23
23
  spec.add_development_dependency 'rake', '~> 12.3'
24
24
  spec.add_development_dependency 'rspec', '~> 3.8'
25
25
  spec.add_development_dependency 'pry', '~> 0.12'
26
- spec.add_development_dependency 'cocoapods', '~> 1.5'
26
+ spec.add_development_dependency 'cocoapods', '~> 1.10.beta.1'
27
27
  spec.add_development_dependency 'json_spec', '~> 1.1'
28
28
  spec.add_development_dependency 'equivalent-xml', '~> 0.6'
29
29
 
30
30
  spec.add_dependency 'clamp', '~> 1.3'
31
31
  spec.add_dependency 'xcodeproj', '~> 1.7'
32
- spec.add_dependency 'nokogiri', '~> 1.8'
32
+ spec.add_dependency 'nokogiri', '~> 1.11'
33
33
  spec.add_dependency 'CFPropertyList', '>= 2.2', '< 4'
34
34
 
35
- spec.add_runtime_dependency 'activesupport', '< 5', '>= 4.0.2'
35
+ spec.add_runtime_dependency 'activesupport'
36
36
  end
@@ -0,0 +1,93 @@
1
+ <?xml version="1.0"?>
2
+ <coverage version="1">
3
+ <file path="spec/fixtures/fixtures/fixtures.m">
4
+ <lineToCover lineNumber="14" covered="true"/>
5
+ <lineToCover lineNumber="15" covered="true"/>
6
+ <lineToCover lineNumber="16" covered="true"/>
7
+ <lineToCover lineNumber="19" covered="false"/>
8
+ <lineToCover lineNumber="20" covered="false"/>
9
+ <lineToCover lineNumber="21" covered="false"/>
10
+ </file>
11
+ <file path="spec/fixtures/fixtures/more_files/Branches.m">
12
+ <lineToCover lineNumber="14" covered="true"/>
13
+ <lineToCover lineNumber="15" covered="true"/>
14
+ <lineToCover lineNumber="16" covered="true"/>
15
+ <lineToCover lineNumber="17" covered="true"/>
16
+ <lineToCover lineNumber="18" covered="true"/>
17
+ <lineToCover lineNumber="19" covered="false"/>
18
+ <lineToCover lineNumber="20" covered="false"/>
19
+ <lineToCover lineNumber="21" covered="true"/>
20
+ <lineToCover lineNumber="22" covered="true"/>
21
+ <lineToCover lineNumber="23" covered="true"/>
22
+ <lineToCover lineNumber="24" covered="true"/>
23
+ <lineToCover lineNumber="25" covered="true"/>
24
+ <lineToCover lineNumber="26" covered="true"/>
25
+ <lineToCover lineNumber="27" covered="true"/>
26
+ <lineToCover lineNumber="28" covered="true"/>
27
+ <lineToCover lineNumber="29" covered="false"/>
28
+ <lineToCover lineNumber="30" covered="false"/>
29
+ <lineToCover lineNumber="31" covered="false"/>
30
+ <lineToCover lineNumber="32" covered="false"/>
31
+ <lineToCover lineNumber="33" covered="false"/>
32
+ <lineToCover lineNumber="34" covered="false"/>
33
+ <lineToCover lineNumber="35" covered="false"/>
34
+ <lineToCover lineNumber="36" covered="false"/>
35
+ <lineToCover lineNumber="37" covered="false"/>
36
+ <lineToCover lineNumber="38" covered="false"/>
37
+ <lineToCover lineNumber="39" covered="false"/>
38
+ <lineToCover lineNumber="40" covered="false"/>
39
+ <lineToCover lineNumber="41" covered="false"/>
40
+ <lineToCover lineNumber="42" covered="false"/>
41
+ <lineToCover lineNumber="43" covered="false"/>
42
+ </file>
43
+ <file path="spec/fixtures/fixturesTests/BranchesTests.m">
44
+ <lineToCover lineNumber="18" covered="true"/>
45
+ <lineToCover lineNumber="19" covered="true"/>
46
+ <lineToCover lineNumber="20" covered="true"/>
47
+ <lineToCover lineNumber="21" covered="true"/>
48
+ <lineToCover lineNumber="23" covered="true"/>
49
+ <lineToCover lineNumber="24" covered="true"/>
50
+ <lineToCover lineNumber="25" covered="true"/>
51
+ <lineToCover lineNumber="26" covered="true"/>
52
+ <lineToCover lineNumber="28" covered="true"/>
53
+ <lineToCover lineNumber="29" covered="true"/>
54
+ <lineToCover lineNumber="30" covered="true"/>
55
+ <lineToCover lineNumber="31" covered="true"/>
56
+ <lineToCover lineNumber="33" covered="true"/>
57
+ <lineToCover lineNumber="34" covered="true"/>
58
+ <lineToCover lineNumber="35" covered="true"/>
59
+ <lineToCover lineNumber="36" covered="true"/>
60
+ </file>
61
+ <file path="spec/fixtures/fixturesTests/fixturesTests.m">
62
+ <lineToCover lineNumber="20" covered="true"/>
63
+ <lineToCover lineNumber="21" covered="true"/>
64
+ <lineToCover lineNumber="22" covered="true"/>
65
+ <lineToCover lineNumber="23" covered="true"/>
66
+ <lineToCover lineNumber="26" covered="true"/>
67
+ <lineToCover lineNumber="27" covered="true"/>
68
+ <lineToCover lineNumber="28" covered="true"/>
69
+ <lineToCover lineNumber="29" covered="true"/>
70
+ <lineToCover lineNumber="32" covered="true"/>
71
+ <lineToCover lineNumber="33" covered="true"/>
72
+ <lineToCover lineNumber="34" covered="true"/>
73
+ <lineToCover lineNumber="35" covered="true"/>
74
+ <lineToCover lineNumber="38" covered="true"/>
75
+ <lineToCover lineNumber="39" covered="true"/>
76
+ <lineToCover lineNumber="40" covered="true"/>
77
+ <lineToCover lineNumber="41" covered="true"/>
78
+ <lineToCover lineNumber="42" covered="true"/>
79
+ </file>
80
+ <file path="spec/fixtures/fixturesTests/peekaviewTests&#x1F4A3;.m">
81
+ <lineToCover lineNumber="18" covered="true"/>
82
+ <lineToCover lineNumber="19" covered="true"/>
83
+ <lineToCover lineNumber="20" covered="true"/>
84
+ <lineToCover lineNumber="21" covered="true"/>
85
+ <lineToCover lineNumber="24" covered="true"/>
86
+ <lineToCover lineNumber="25" covered="true"/>
87
+ <lineToCover lineNumber="26" covered="true"/>
88
+ <lineToCover lineNumber="27" covered="true"/>
89
+ <lineToCover lineNumber="30" covered="true"/>
90
+ <lineToCover lineNumber="31" covered="true"/>
91
+ <lineToCover lineNumber="32" covered="true"/>
92
+ </file>
93
+ </coverage>
@@ -151,6 +151,26 @@ describe Slather::CoverageService::Coveralls do
151
151
  ENV['GIT_BRANCH'] = git_branch
152
152
  end
153
153
  end
154
+
155
+ context "coverage_service is :github" do
156
+ before(:each) { fixtures_project.ci_service = :github }
157
+
158
+ it "should return valid json for coveralls coverage data" do
159
+ allow(fixtures_project).to receive(:github_job_id).and_return("9182")
160
+ allow(fixtures_project).to receive(:coverage_access_token).and_return("abc123")
161
+ allow(fixtures_project).to receive(:github_pull_request).and_return("1")
162
+ allow(fixtures_project).to receive(:github_build_url).and_return("https://github.com/Bruce/Wayne/actions/runs/1")
163
+ allow(fixtures_project).to receive(:github_git_info).and_return({ :head => { :id => "ababa123", :author_name => "bwayne", :message => "hello" }, :branch => "master" })
164
+ expect(fixtures_project.send(:coveralls_coverage_data)).to be_json_eql("{\"service_job_id\":\"9182\",\"service_name\":\"github\",\"repo_name\":\"\",\"repo_token\":\"abc123\",\"service_pull_request\":\"1\",\"service_build_url\":\"https://github.com/Bruce/Wayne/actions/runs/1\",\"git\":{\"head\":{\"id\":\"ababa123\",\"author_name\":\"bwayne\",\"message\":\"hello\"},\"branch\":\"master\"}}").excluding("source_files")
165
+ expect(fixtures_project.send(:coveralls_coverage_data)).to be_json_eql(fixtures_project.coverage_files.map(&:as_json).to_json).at_path("source_files")
166
+ end
167
+
168
+ it "should raise an error if there is no GITHUB_RUN_ID" do
169
+ allow(fixtures_project).to receive(:github_job_id).and_return(nil)
170
+ expect { fixtures_project.send(:coveralls_coverage_data) }.to raise_error(StandardError)
171
+ end
172
+ end
173
+
154
174
  end
155
175
 
156
176
  describe '#coveralls_coverage_data' do
@@ -185,8 +185,8 @@ describe Slather::CoverageService::HtmlOutput do
185
185
  end
186
186
 
187
187
  allow(fixtures_project).to receive(:input_format).and_return("profdata")
188
- allow(fixtures_project).to receive(:profdata_llvm_cov_output).and_return("./spec/fixtures/fixtures/other_fixtures.m:
189
- 1| |//
188
+ allow(fixtures_project).to receive(:pathnames_per_binary).and_return([{"filename" => Pathname.new("./spec/fixtures/fixtures/other_fixtures.m"), "segments" => []}])
189
+ allow(fixtures_project).to receive(:profdata_llvm_cov_output).and_return("1| |//
190
190
  2| |// other_fixtures.m
191
191
  3| |// fixtures
192
192
  4| |//
@@ -0,0 +1,46 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+ require 'json'
3
+
4
+ describe Slather::CoverageService::SonarqubeXmlOutput do
5
+
6
+ let(:fixtures_project) do
7
+ proj = Slather::Project.open(FIXTURES_PROJECT_PATH)
8
+ proj.build_directory = TEMP_DERIVED_DATA_PATH
9
+ proj.input_format = "profdata"
10
+ proj.coverage_service = "sonarqube_xml"
11
+ proj.configure
12
+ proj
13
+ end
14
+
15
+ describe '#coverage_file_class' do
16
+ it "should return CoverageFile" do
17
+ expect(fixtures_project.send(:coverage_file_class)).to eq(Slather::ProfdataCoverageFile)
18
+ end
19
+ end
20
+
21
+ describe '#post' do
22
+ it "should create an XML report spanning all coverage files" do
23
+ fixtures_project.post
24
+
25
+ file = File.open(FIXTURES_SONARQUBE_XML_PATH)
26
+ fixture_xml_doc = Nokogiri::XML(file)
27
+ file.close
28
+
29
+ file = File.open('sonarqube-generic-coverage.xml')
30
+ current_xml_doc = Nokogiri::XML(file)
31
+ file.close
32
+
33
+ expect(EquivalentXml.equivalent?(current_xml_doc, fixture_xml_doc)).to be_truthy
34
+ end
35
+
36
+ it "should create an XML report in the given output directory" do
37
+ fixtures_project.output_directory = "./output"
38
+ fixtures_project.post
39
+
40
+ filepath = "#{fixtures_project.output_directory}/sonarqube-generic-coverage.xml"
41
+ expect(File.exists?(filepath)).to be_truthy
42
+
43
+ FileUtils.rm_rf(fixtures_project.output_directory)
44
+ end
45
+ end
46
+ end
@@ -157,6 +157,18 @@ describe Slather::ProfdataCoverageFile do
157
157
  end
158
158
  end
159
159
 
160
+ describe "#branch_coverage_data" do
161
+ it "should have branch data for line 19" do
162
+ # these segments correspond to the only statement on line 19
163
+ profdata_coverage_file.segments = [[19, 9, 0, true, false], [19, 20, 1, true, false]]
164
+ expect(profdata_coverage_file.branch_coverage_data[19]).to eq([0,1])
165
+ end
166
+ it "should have missing region data for line 19" do
167
+ profdata_coverage_file.segments = [[19, 9, 0, true, false], [19, 20, 1, true, false]]
168
+ expect(profdata_coverage_file.branch_region_data[19]).to eq([[8,11]])
169
+ end
170
+ end
171
+
160
172
  describe "#ignored" do
161
173
 
162
174
  before(:each) {
@@ -653,8 +653,8 @@ describe Slather::Project do
653
653
  it "should find relevant source files" do
654
654
  source_files = fixtures_project.find_source_files
655
655
  expect(source_files.count).to eq(2)
656
- expect(source_files.first.to_s).to include("fixtures.m")
657
- expect(source_files.last.to_s).to include("fixturesTwo.m")
656
+ expect(source_files.first.to_s).to include("fixturesTwo.m")
657
+ expect(source_files.last.to_s).to include("fixtures.m")
658
658
  end
659
659
 
660
660
  it "should print out the coverage for each file, and then total coverage" do
@@ -664,10 +664,12 @@ describe Slather::Project do
664
664
  {
665
665
  "files":[
666
666
  {
667
- "filename":"spec/fixtures/fixtures/fixtures.m"
667
+ "filename":"spec/fixtures/fixtures/fixtures.m",
668
+ "segments": []
668
669
  },
669
670
  {
670
- "filename":"spec/fixtures/fixturesTwo/fixturesTwo.m"
671
+ "filename":"spec/fixtures/fixturesTwo/fixturesTwo.m",
672
+ "segments": []
671
673
  }
672
674
  ]
673
675
  }
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,7 @@ require 'equivalent-xml'
13
13
 
14
14
 
15
15
  FIXTURES_XML_PATH = File.join(File.dirname(__FILE__), 'fixtures/cobertura.xml')
16
+ FIXTURES_SONARQUBE_XML_PATH = File.join(File.dirname(__FILE__), 'fixtures/sonarqube-generic-coverage.xml')
16
17
  FIXTURES_JSON_PATH = File.join(File.dirname(__FILE__), 'fixtures/report.json')
17
18
  FIXTURES_LLCOV_PATH = File.join(File.dirname(__FILE__), 'fixtures/report.llcov')
18
19
  FIXTURES_GUTTER_JSON_PATH = File.join(File.dirname(__FILE__), 'fixtures/gutter.json')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slather
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.8
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Larsen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-23 00:00:00.000000000 Z
11
+ date: 2021-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.17'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.17'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: coveralls
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.5'
103
+ version: 1.10.beta.1
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1.5'
110
+ version: 1.10.beta.1
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: json_spec
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: '1.8'
173
+ version: '1.11'
174
174
  type: :runtime
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: '1.8'
180
+ version: '1.11'
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: CFPropertyList
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -202,23 +202,17 @@ dependencies:
202
202
  name: activesupport
203
203
  requirement: !ruby/object:Gem::Requirement
204
204
  requirements:
205
- - - "<"
206
- - !ruby/object:Gem::Version
207
- version: '5'
208
205
  - - ">="
209
206
  - !ruby/object:Gem::Version
210
- version: 4.0.2
207
+ version: '0'
211
208
  type: :runtime
212
209
  prerelease: false
213
210
  version_requirements: !ruby/object:Gem::Requirement
214
211
  requirements:
215
- - - "<"
216
- - !ruby/object:Gem::Version
217
- version: '5'
218
212
  - - ">="
219
213
  - !ruby/object:Gem::Version
220
- version: 4.0.2
221
- description:
214
+ version: '0'
215
+ description:
222
216
  email:
223
217
  - mark@venmo.com
224
218
  executables:
@@ -255,6 +249,7 @@ files:
255
249
  - lib/slather/coverage_service/json_output.rb
256
250
  - lib/slather/coverage_service/llvm_cov_output.rb
257
251
  - lib/slather/coverage_service/simple_output.rb
252
+ - lib/slather/coverage_service/sonarqube_xml_output.rb
258
253
  - lib/slather/coveralls_coverage.rb
259
254
  - lib/slather/profdata_coverage_file.rb
260
255
  - lib/slather/project.rb
@@ -304,6 +299,7 @@ files:
304
299
  - spec/fixtures/gutter.json
305
300
  - spec/fixtures/report.json
306
301
  - spec/fixtures/report.llcov
302
+ - spec/fixtures/sonarqube-generic-coverage.xml
307
303
  - spec/slather/cocoapods_plugin_spec.rb
308
304
  - spec/slather/coverage_file_spec.rb
309
305
  - spec/slather/coverage_service/cobertura_xml_spec.rb
@@ -314,6 +310,7 @@ files:
314
310
  - spec/slather/coverage_service/json_spec.rb
315
311
  - spec/slather/coverage_service/llvm_cov_spec.rb
316
312
  - spec/slather/coverage_service/simple_output_spec.rb
313
+ - spec/slather/coverage_service/sonarqube_xml_spec.rb
317
314
  - spec/slather/fixtures.gcno
318
315
  - spec/slather/profdata_coverage_spec.rb
319
316
  - spec/slather/project_spec.rb
@@ -322,7 +319,7 @@ homepage: https://github.com/SlatherOrg/slather
322
319
  licenses:
323
320
  - MIT
324
321
  metadata: {}
325
- post_install_message:
322
+ post_install_message:
326
323
  rdoc_options: []
327
324
  require_paths:
328
325
  - lib
@@ -337,8 +334,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
337
334
  - !ruby/object:Gem::Version
338
335
  version: '0'
339
336
  requirements: []
340
- rubygems_version: 3.1.2
341
- signing_key:
337
+ rubygems_version: 3.1.3
338
+ signing_key:
342
339
  specification_version: 4
343
340
  summary: Test coverage reports for Xcode projects
344
341
  test_files:
@@ -386,6 +383,7 @@ test_files:
386
383
  - spec/fixtures/gutter.json
387
384
  - spec/fixtures/report.json
388
385
  - spec/fixtures/report.llcov
386
+ - spec/fixtures/sonarqube-generic-coverage.xml
389
387
  - spec/slather/cocoapods_plugin_spec.rb
390
388
  - spec/slather/coverage_file_spec.rb
391
389
  - spec/slather/coverage_service/cobertura_xml_spec.rb
@@ -396,6 +394,7 @@ test_files:
396
394
  - spec/slather/coverage_service/json_spec.rb
397
395
  - spec/slather/coverage_service/llvm_cov_spec.rb
398
396
  - spec/slather/coverage_service/simple_output_spec.rb
397
+ - spec/slather/coverage_service/sonarqube_xml_spec.rb
399
398
  - spec/slather/fixtures.gcno
400
399
  - spec/slather/profdata_coverage_spec.rb
401
400
  - spec/slather/project_spec.rb