slather 2.4.8 → 2.7.0

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.
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