slather 2.4.6 → 2.6.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: 87dc3cb198a7c6f4a3e02ab8f0494e8c65d47cc7dfcf5a6a8c683d3f2d7b6630
4
- data.tar.gz: 16ead0627576c7b079f9f29ed54521a8726db794f396d5ee109ea8046c11d212
3
+ metadata.gz: eeaf99ed5212bdc90e8098dfde877452af7f074ecfd41fc577d46f90b1ee65eb
4
+ data.tar.gz: 5dbd0db5223f26990c2bfd3ab02f4ed36a15d8088a0b5c393f522a785a0176cd
5
5
  SHA512:
6
- metadata.gz: b306cecaf97dece04f3c2ad147cc75dae2c2b17f5264bde4582c3815e3d310728d57ed97ecea7c0e3ab25c4d89798e328c3daf169d225e18c370aca04bed524a
7
- data.tar.gz: '03703182714e4ae4bdfbf46e5c2e7fc5c1d1b24416cff13e88be6ff569d3fc3c009e28027f5d6f6163dce0f0079ce87a389adcebe1939b057b431015d1b354c7'
6
+ metadata.gz: 6802b4ef28cfb856bf68d214416d6a455de715723327dc7167600bc9cae705dacbdbffb0b8d154b2027dde6d5b2f6baec719f69a81e5293a437da1e260461e73
7
+ data.tar.gz: c6b95c762eaa1d5260da5de5910e7f429a79e45556a3b32568ba8c7c9f3ed173ed514330793c39babc767e4f021dda7fc83971750d16407d0149050286495b95
data/.gitignore CHANGED
@@ -46,4 +46,8 @@ html
46
46
  *.gcno
47
47
 
48
48
  # JetBrains IDE
49
- .idea/
49
+ .idea/
50
+
51
+ # Test output
52
+ report.llcov
53
+ report.json
@@ -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 --no-ri --no-rdoc
7
+ - gem install bundler -v "~> 2.0" --no-document
8
8
 
9
9
  install:
10
10
  - bundle install --without=documentation
@@ -1,5 +1,54 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v2.6.0
4
+
5
+ * Added GitHub actions support
6
+ [martin-key](https://github.com/martin-key), [troyfontaine](https://github.com/troyfontaine)
7
+ [#468](https://github.com/SlatherOrg/slather/pull/468)
8
+
9
+ ## v2.5.0
10
+
11
+ * Fixed activesupport and cocoapods dependencies
12
+ [daneov](https://github.com/daneov)
13
+ [#456](https://github.com/SlatherOrg/slather/pull/467)
14
+
15
+ * Fixed typo in documentation
16
+ [descorp](https://github.com/descorp)
17
+ [#456](https://github.com/SlatherOrg/slather/pull/463)
18
+
19
+ ## v2.4.9
20
+
21
+ * Added support for Sonarqube output
22
+ [adellibovi](https://github.com/adellibovi)
23
+ [#456](https://github.com/SlatherOrg/slather/pull/456)
24
+
25
+ ## v2.4.8
26
+
27
+ * Optimize performance for many binaries
28
+ [cltnschlosser](https://github.com/cltnschlosser)
29
+ [#455](https://github.com/SlatherOrg/slather/pull/455)
30
+
31
+ * Don't generate line 0 in profdata_coverage_file.rb from line with error
32
+ [tthbalazs](https://github.com/tthbalazs)
33
+ [#449](https://github.com/SlatherOrg/slather/pull/449)
34
+
35
+ * coveralls dependency update
36
+ [GRiMe2D](https://github.com/GRiMe2D)
37
+ [#448](https://github.com/SlatherOrg/slather/pull/448)
38
+
39
+ ## v2.4.7
40
+
41
+ * Update dependencies
42
+ [dnedrow](https://github.com/dnedrow)
43
+
44
+ * Fixed errors when llvm-cov argument length exceeds ARG_MAX
45
+ [weibel](https://github.com/weibel)
46
+ [#414](https://github.com/SlatherOrg/slather/pull/414)
47
+
48
+ * Show "No coverage directory found." instead of "implicit conversion nil into String"
49
+ [phimage](https://github.com/phimage)
50
+ [#381](https://github.com/SlatherOrg/slather/pull/381) [#341](https://github.com/SlatherOrg/slather/issues/341)
51
+
3
52
  ## v2.4.6
4
53
 
5
54
  * Fix .dSYM and .swiftmodule files filtering in find_binary_files()
data/README.md CHANGED
@@ -67,6 +67,20 @@ If your configuration produces a universal binary you need to specify a specific
67
67
  $ slather coverage -s --arch x86_64 --scheme YourXcodeSchemeName --configuration YourBuildConfigurationName path/to/project.xcodeproj
68
68
  ```
69
69
 
70
+ ### For multiple modules
71
+
72
+ If you want to run some modules, but not all (like modules created by CocoaPods) you can do it like this:
73
+
74
+ ```sh
75
+ $ slather coverage --binary-basename module1 --binary-basename module2 path/to/project.xcodeproj
76
+ ```
77
+ You can also add it to the `.slather.yml` file as an array:
78
+ ```yml
79
+ binary_basename:
80
+ - module1
81
+ - module2
82
+ ```
83
+
70
84
  ### Setup for Xcode 5 and 6
71
85
 
72
86
  Run this command to enable the `Generate Test Coverage` and `Instrument Program Flow` flags for your project:
@@ -135,7 +149,7 @@ ignore:
135
149
  - ProjectTestsGroup/*
136
150
  ```
137
151
 
138
- 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:
139
153
 
140
154
  ```yml
141
155
  # .travis.yml
@@ -154,6 +168,25 @@ test:
154
168
 
155
169
  ```
156
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
+
157
190
  #### Usage with Travis CI Pro
158
191
 
159
192
  To use Coveralls with Travis CI Pro (for private repos), add following lines along with other settings to `.slather.yml`:
@@ -251,3 +284,4 @@ Please make sure to follow our general coding style and add test coverage for ne
251
284
  * [@jhersh](https://github.com/jhersh), CircleCI support.
252
285
  * [@tarbrain](https://github.com/tarbrain), Cobertura support and bugfixing.
253
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.
@@ -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
@@ -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
@@ -18,7 +18,6 @@ module Slather
18
18
  end
19
19
 
20
20
  def create_line_data
21
- all_lines = source_code_lines
22
21
  line_data = Hash.new
23
22
  all_lines.each { |line| line_data[line_number_in_line(line, self.line_numbers_first)] = line }
24
23
  self.line_data = line_data
@@ -26,14 +25,20 @@ module Slather
26
25
  private :create_line_data
27
26
 
28
27
  def path_on_first_line?
29
- path = self.source.split("\n")[0].sub ":", ""
30
- !path.lstrip.start_with?("1|")
28
+ !source.lstrip.start_with?("1|")
31
29
  end
32
30
 
33
31
  def source_file_pathname
34
32
  @source_file_pathname ||= begin
35
33
  if path_on_first_line?
36
- path = self.source.split("\n")[0].sub ":", ""
34
+ end_index = self.source.index(/:?\n/)
35
+ if end_index != nil
36
+ end_index -= 1
37
+ path = self.source[0..end_index]
38
+ else
39
+ # Empty file, output just contains path
40
+ path = self.source.sub ":", ""
41
+ end
37
42
  path &&= Pathname(path)
38
43
  else
39
44
  # llvm-cov was run with just one matching source file
@@ -64,7 +69,16 @@ module Slather
64
69
  end
65
70
 
66
71
  def source_code_lines
67
- self.source.split("\n")[(path_on_first_line? ? 1 : 0)..-1]
72
+ lines = self.source.split("\n")[(path_on_first_line? ? 1 : 0)..-1]
73
+ ignore_error_lines(lines)
74
+ end
75
+
76
+ def ignore_error_lines(lines, line_numbers_first = self.line_numbers_first)
77
+ if line_numbers_first
78
+ lines.reject { |line| line.lstrip.start_with?('|', '--') }
79
+ else
80
+ lines
81
+ end
68
82
  end
69
83
 
70
84
  def source_data
@@ -72,10 +86,7 @@ module Slather
72
86
  end
73
87
 
74
88
  def all_lines
75
- if @all_lines == nil
76
- @all_lines = source_code_lines
77
- end
78
- @all_lines
89
+ @all_lines ||= source_code_lines
79
90
  end
80
91
 
81
92
  def raw_source
@@ -94,6 +105,9 @@ module Slather
94
105
 
95
106
  def line_number_in_line(line, line_numbers_first = self.line_numbers_first)
96
107
  if line_numbers_first
108
+ # Skip regex if the number is the first thing in the line
109
+ fastpath_number = line.to_i
110
+ return fastpath_number if fastpath_number != 0
97
111
  line =~ /^(\s*)(\d*)/
98
112
  group = $2
99
113
  else
@@ -123,7 +137,7 @@ module Slather
123
137
  end
124
138
 
125
139
  def line_coverage_data
126
- source_code_lines.map do |line|
140
+ all_lines.map do |line|
127
141
  coverage_for_line(line, self.line_numbers_first)
128
142
  end
129
143
  end