slather 2.4.8 → 2.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +4 -2
  4. data/CHANGELOG.md +100 -0
  5. data/README.md +26 -3
  6. data/assets/slather.css +2 -1
  7. data/lib/slather/command/coverage_command.rb +9 -1
  8. data/lib/slather/coverage_file.rb +14 -9
  9. data/lib/slather/coverage_service/coveralls.rb +129 -5
  10. data/lib/slather/coverage_service/html_output.rb +62 -6
  11. data/lib/slather/coverage_service/sonarqube_xml_output.rb +61 -0
  12. data/lib/slather/profdata_coverage_file.rb +42 -2
  13. data/lib/slather/project.rb +41 -7
  14. data/lib/slather/version.rb +1 -1
  15. data/lib/slather.rb +1 -0
  16. data/slather.gemspec +5 -5
  17. data/spec/fixtures/FixtureFramework/FixtureFramework.h +19 -0
  18. data/spec/fixtures/FixtureFramework/FlashExperiment.swift +7 -0
  19. data/spec/fixtures/FixtureFramework/Info.plist +24 -0
  20. data/spec/fixtures/FixtureFrameworkTests/FixtureFrameworkTests.swift +34 -0
  21. data/spec/fixtures/FixtureFrameworkTests/FlashExperimentTests.swift +9 -0
  22. data/spec/fixtures/FixtureFrameworkTests/Info.plist +22 -0
  23. data/spec/fixtures/cobertura.xml +157 -37
  24. data/spec/fixtures/fixtures.xcodeproj/project.pbxproj +222 -0
  25. data/spec/fixtures/fixtures.xcodeproj/xcshareddata/xcschemes/fixtures.xcscheme +21 -5
  26. data/spec/fixtures/fixtures.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  27. data/spec/fixtures/sonarqube-generic-coverage.xml +93 -0
  28. data/spec/slather/coverage_service/cobertura_xml_spec.rb +1 -1
  29. data/spec/slather/coverage_service/coveralls_spec.rb +20 -0
  30. data/spec/slather/coverage_service/html_output_spec.rb +2 -2
  31. data/spec/slather/coverage_service/json_spec.rb +1 -1
  32. data/spec/slather/coverage_service/llvm_cov_spec.rb +1 -1
  33. data/spec/slather/coverage_service/sonarqube_xml_spec.rb +46 -0
  34. data/spec/slather/profdata_coverage_spec.rb +16 -0
  35. data/spec/slather/project_spec.rb +12 -8
  36. data/spec/spec_helper.rb +1 -0
  37. metadata +38 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24ee530494c9f131751a85dba16a4bc09292c187d045be17b1212d9cf4038378
4
- data.tar.gz: 4c5dabc3de752ebb88998ca29d87d6f072e4477a909926d4237078a2a9f73bc2
3
+ metadata.gz: 2c4a1059a1eae7156ac2c98e509e9cc267e6dd29fbd18332155e94b81c56c3de
4
+ data.tar.gz: b4d09bcb4d70d24e482268791c1a86f80f62a5f9206b3188931dabd1e8673b30
5
5
  SHA512:
6
- metadata.gz: b7d4a1db210237adec6b9c03634774991a209c4aa64c10dea0a73208642298082b9a76f9c0e979b68a4601c6c9ff37f92d6f05bfd3c8a35429bd78cc8ac9549c
7
- data.tar.gz: 9bf87cccabbd4b243e8ba9c519d491818a38924125694ca8701b3b34764a8c9ae167919b764638fa0af27b137dbbf10d9188b3e6297f93f3d1673ec07566d817
6
+ metadata.gz: 2a526985aec8bbf888ccdf584c3638c97349eddaff3b905df334a88ec42e865f1012c928aa520a3471ad6aadf911e60894576f018230da63aceeb27939a00921
7
+ data.tar.gz: fa77a74cef513c27b2e09101f20b0357c1cf163c1f94b273137a0738fd163bce9700f4e48b76bdfcd2a12e72ba4c3baaf24f0ce86738143f23f87f5a806fcda5
data/.gitignore CHANGED
@@ -20,7 +20,7 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
-
23
+ .vendor
24
24
  # Xcode
25
25
  #
26
26
  *.pbxuser
data/.travis.yml CHANGED
@@ -1,10 +1,12 @@
1
1
  language: objective-c
2
2
  script: bundle exec rake
3
- osx_image: xcode9.2
3
+ osx_image: xcode12.2
4
+
5
+ cache: bundler
4
6
 
5
7
  before_install:
6
8
  - 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
9
+ - gem install bundler -v "~> 2.0" --no-document
8
10
 
9
11
  install:
10
12
  - bundle install --without=documentation
data/CHANGELOG.md CHANGED
@@ -1,5 +1,105 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v2.7.5
4
+
5
+ * Add `--cdn-assets` flag
6
+ [sushant-here](https://github.com/sushant-here)
7
+ [#537](https://github.com/SlatherOrg/slather/pull/537)
8
+
9
+ * Update nokogiri version
10
+
11
+ ## v2.7.4
12
+
13
+ * Support Ruby 3.2.0
14
+ [crazymanish](https://github.com/crazymanish)
15
+ [#532](https://github.com/SlatherOrg/slather/pull/532)
16
+
17
+ ## v2.7.3
18
+
19
+ * Support Coveralls parallel runs
20
+ [paulz](https://github.com/paulz)
21
+ [#523](https://github.com/SlatherOrg/slather/pull/523)
22
+
23
+ * Update nokogiri version
24
+ [anil291987](https://github.com/anil291987)
25
+ [#518](https://github.com/SlatherOrg/slather/pull/518)
26
+ [#524](https://github.com/SlatherOrg/slather/pull/524)
27
+
28
+ ## v2.7.2
29
+
30
+ * Update xcodeproj version
31
+ [adamyanalunas](https://github.com/adamyanalunas)
32
+ [#502](https://github.com/SlatherOrg/slather/pull/502)
33
+
34
+ * Update nokogiri version
35
+ [jwelton](https://github.com/jwelton)
36
+ [#503](https://github.com/SlatherOrg/slather/pull/503)
37
+
38
+ * Support alternate CI systems in coveralls output
39
+ [fermoyadrop](https://github.com/fermoyadrop)
40
+ [#504](https://github.com/SlatherOrg/slather/pull/504)
41
+
42
+ * Add Bitrise support to coveralls output
43
+ [fermoyadrop](https://github.com/fermoyadrop)
44
+ [#504](https://github.com/SlatherOrg/slather/pull/505)
45
+
46
+ ## v2.7.1
47
+
48
+ * Support generating coverage for framework targets
49
+ [onato](https://github.com/onato)
50
+ [#482](https://github.com/SlatherOrg/slather/pull/482)
51
+
52
+ * Show number of lines in HTML report
53
+ [SiemianHS](https://github.com/SiemianHS)
54
+ [#494](https://github.com/SlatherOrg/slather/pull/494)
55
+
56
+ * Fixed issues with HTML report generation
57
+ [fchiba](https://github.com/fchiba)
58
+ [#483](https://github.com/SlatherOrg/slather/pull/483)
59
+ [#484](https://github.com/SlatherOrg/slather/pull/484)
60
+
61
+ * Don't fail if a source file doesn't exist
62
+ [chillpop](https://github.com/chillpop)
63
+ [#492](https://github.com/SlatherOrg/slather/pull/492)
64
+
65
+ ## v2.7.0
66
+
67
+ * Add Branch Coverage data for ProfData coverage files
68
+ [hborawski](https://github.com/hborawski)
69
+ [#477](https://github.com/SlatherOrg/slather/pull/477)
70
+
71
+ * Fixed 'Argument list too long' when running 'xcrun llvm-cov'
72
+ [samuelsainz](https://github.com/samuelsainz)
73
+ [#476](https://github.com/SlatherOrg/slather/pull/476)
74
+
75
+ ## v2.6.1
76
+
77
+ * Update nokogiri to 1.11
78
+ [ashin-omg](https://github.com/ashin-omg)
79
+ [#473](https://github.com/SlatherOrg/slather/pull/473)
80
+
81
+ ## v2.6.0
82
+
83
+ * Added GitHub actions support
84
+ [martin-key](https://github.com/martin-key), [troyfontaine](https://github.com/troyfontaine)
85
+ [#468](https://github.com/SlatherOrg/slather/pull/468)
86
+
87
+ ## v2.5.0
88
+
89
+ * Fixed activesupport and cocoapods dependencies
90
+ [daneov](https://github.com/daneov)
91
+ [#456](https://github.com/SlatherOrg/slather/pull/467)
92
+
93
+ * Fixed typo in documentation
94
+ [descorp](https://github.com/descorp)
95
+ [#456](https://github.com/SlatherOrg/slather/pull/463)
96
+
97
+ ## v2.4.9
98
+
99
+ * Added support for Sonarqube output
100
+ [adellibovi](https://github.com/adellibovi)
101
+ [#456](https://github.com/SlatherOrg/slather/pull/456)
102
+
3
103
  ## v2.4.8
4
104
 
5
105
  * Optimize performance for many binaries
data/README.md CHANGED
@@ -134,13 +134,14 @@ test:
134
134
 
135
135
  ### Usage with Coveralls
136
136
 
137
- Login to [Coveralls](https://coveralls.io/) and enable your repository. Right now, `slather` supports Coveralls via [Travis CI](https://travis-ci.org) and [CircleCI](https://circleci.com).
137
+ Login to [Coveralls](https://coveralls.io/) and enable your repository. Right now, `slather` supports Coveralls via [Travis CI](https://travis-ci.org), [CircleCI](https://circleci.com), [Jenkins](https://www.jenkins.io/), [Teamcity](https://www.jetbrains.com/teamcity/), [Buildkite](https://buildkite.com/), and [Bitrise](https://bitrise.io/).
138
138
 
139
- Make a `.slather.yml` file:
139
+ Make a `.slather.yml` file and specify the CI Service you're using:
140
140
 
141
141
  ```yml
142
142
  # .slather.yml
143
143
 
144
+ ci_service: circleci | travis_ci | travis_pro | jenkins | buildkite | teamcity
144
145
  coverage_service: coveralls
145
146
  xcodeproj: path/to/project.xcodeproj
146
147
  scheme: YourXcodeSchemeName
@@ -149,7 +150,7 @@ ignore:
149
150
  - ProjectTestsGroup/*
150
151
  ```
151
152
 
152
- And then in your `.travis.yml` or `circle.yml`, call `slather` after a successful build:
153
+ And then in your `.travis.yml` or `circle.yml` or `github-action.yml`, call `slather` after a successful build:
153
154
 
154
155
  ```yml
155
156
  # .travis.yml
@@ -168,6 +169,25 @@ test:
168
169
 
169
170
  ```
170
171
 
172
+ ```yml
173
+ # github-action.yml
174
+ myjob:
175
+ steps:
176
+ - run: |
177
+ bundle config path vendor/bundle
178
+ bundle install --without=documentation --jobs 4 --retry 3
179
+ - name: Extract branch name
180
+ shell: bash
181
+ run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
182
+ id: get_branch
183
+ - run: bundle exec slather
184
+ env:
185
+ GIT_BRANCH: ${{ steps.get_branch.outputs.branch }}
186
+ CI_PULL_REQUEST: ${{ github.event.number }}
187
+ COVERAGE_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
188
+
189
+ ```
190
+
171
191
  #### Usage with Travis CI Pro
172
192
 
173
193
  To use Coveralls with Travis CI Pro (for private repos), add following lines along with other settings to `.slather.yml`:
@@ -214,6 +234,8 @@ $ slather coverage --html --scheme YourXcodeSchemeName path/to/project.xcodeproj
214
234
 
215
235
  This will make a directory named `html` in your root directory (unless `--output-directory` is specified) and will generate all the reports as static html pages inside the directory. It will print out the report's path by default, but you can also specify `--show` flag to open it in your browser automatically.
216
236
 
237
+ By default, the generated HTML will reference locally hosted assets (js, css). You can specify the `--cdn-assets` to specify that you prefer for the generated HTML to use externally hosted assets. This can be useful if publishing the HTML file as a build artifact.
238
+
217
239
  ### TeamCity Reporting
218
240
 
219
241
  To report the coverage statistics to TeamCity:
@@ -265,3 +287,4 @@ Please make sure to follow our general coding style and add test coverage for ne
265
287
  * [@jhersh](https://github.com/jhersh), CircleCI support.
266
288
  * [@tarbrain](https://github.com/tarbrain), Cobertura support and bugfixing.
267
289
  * [@ikhsan](https://github.com/ikhsan), html support.
290
+ * [@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
  }
@@ -8,15 +8,18 @@ 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"
19
21
  option ["--show"], :flag, "Indicate that the static html pages will open automatically"
22
+ option ["--cdn-assets"], :flag, "Indicate that the static html pages will load assets from a CDN"
20
23
 
21
24
  option ["--build-directory", "-b"], "BUILD_DIRECTORY", "The directory where gcno files will be written to. Defaults to derived data."
22
25
  option ["--source-directory"], "SOURCE_DIRECTORY", "The directory where your source files are located."
@@ -28,7 +31,7 @@ class CoverageCommand < Clamp::Command
28
31
  option ["--scheme"], "SCHEME", "The scheme for which the coverage was generated"
29
32
  option ["--configuration"], "CONFIGURATION", "The configuration for test that the project was set"
30
33
  option ["--workspace"], "WORKSPACE", "The workspace that the project was built in"
31
- option ["--binary-file"], "BINARY_FILE", "The binary file against the which the coverage will be run", :multivalued => true
34
+ option ["--binary-file"], "BINARY_FILE", "The binary file against which the coverage will be run", :multivalued => true
32
35
  option ["--binary-basename"], "BINARY_BASENAME", "Basename of the file against which the coverage will be run", :multivalued => true
33
36
  option ["--arch"], "ARCH", "Architecture to use from universal binaries"
34
37
  option ["--source-files"], "SOURCE_FILES", "A Dir.glob compatible pattern used to limit the lookup to specific source files. Ignored in gcov mode.", :multivalued => true
@@ -90,6 +93,8 @@ class CoverageCommand < Clamp::Command
90
93
  project.ci_service = :buildkite
91
94
  elsif teamcity?
92
95
  project.ci_service = :teamcity
96
+ elsif github?
97
+ project.ci_service = :github
93
98
  end
94
99
  end
95
100
 
@@ -122,8 +127,11 @@ class CoverageCommand < Clamp::Command
122
127
  elsif html?
123
128
  project.coverage_service = :html
124
129
  project.show_html = show?
130
+ project.cdn_assets = cdn_assets?
125
131
  elsif json?
126
132
  project.coverage_service = :json
133
+ elsif sonarqube_xml?
134
+ project.coverage_service = :sonarqube_xml
127
135
  end
128
136
  end
129
137
 
@@ -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.exist?(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,31 @@ 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 bitrise_job_id
45
+ ENV['BITRISE_BUILD_NUMBER']
46
+ end
47
+ private :bitrise_job_id
48
+
49
+ def bitrise_pull_request
50
+ ENV['BITRISE_PULL_REQUEST']
51
+ end
52
+ private :bitrise_pull_request
53
+
54
+ def github_pull_request
55
+ ENV['CI_PULL_REQUEST'] || ""
56
+ end
57
+ private :github_pull_request
58
+
59
+ def github_repo_name
60
+ ENV['GITHUB_REPOSITORY'] || ""
61
+ end
62
+ private :github_repo_name
63
+
39
64
  def jenkins_branch_name
40
65
  branch_name = ENV['GIT_BRANCH'] || ENV['BRANCH_NAME']
41
66
  if branch_name.include? 'origin/'
@@ -51,6 +76,16 @@ module Slather
51
76
  end
52
77
  private :teamcity_branch_name
53
78
 
79
+ def github_branch_name
80
+ ENV['GIT_BRANCH'] || `git ls-remote --heads origin | grep $(git rev-parse HEAD) | cut -d / -f 3-`.chomp
81
+ end
82
+ private :github_branch_name
83
+
84
+ def bitrise_branch_name
85
+ ENV['BITRISE_GIT_BRANCH'] || `git ls-remote --heads origin | grep $(git rev-parse HEAD) | cut -d / -f 3-`.chomp
86
+ end
87
+ private :bitrise_branch_name
88
+
54
89
  def buildkite_job_id
55
90
  ENV['BUILDKITE_BUILD_NUMBER']
56
91
  end
@@ -119,11 +154,51 @@ module Slather
119
154
  "https://buildkite.com/" + ENV['BUILDKITE_PROJECT_SLUG'] + "/builds/" + ENV['BUILDKITE_BUILD_NUMBER'] + "#"
120
155
  end
121
156
 
157
+ def github_git_info
158
+ {
159
+ :head => {
160
+ :id => ENV['GITHUB_SHA'],
161
+ :author_name => ENV['GITHUB_ACTOR'],
162
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
163
+ },
164
+ :branch => github_branch_name
165
+ }
166
+ end
167
+ private :github_git_info
168
+
169
+ def bitrise_git_info
170
+ {
171
+ :head => {
172
+ :id => ENV['BITRISE_GIT_COMMIT'],
173
+ :committer_name => (ENV['GIT_CLONE_COMMIT_AUTHOR_NAME'] || `git log --format=%an -n 1 HEAD`.chomp || ""),
174
+ :committer_email => (ENV['GIT_CLONE_COMMIT_AUTHOR_EMAIL'] || `git log --format=%ae -n 1 HEAD`.chomp || ""),
175
+ :message => (ENV['BITRISE_GIT_MESSAGE'] || `git log --format=%s -n 1 HEAD`.chomp || "")
176
+ },
177
+ :branch => bitrise_branch_name
178
+ }
179
+ end
180
+ private :bitrise_git_info
181
+
182
+ def github_build_url
183
+ "https://github.com/" + ENV['GITHUB_REPOSITORY'] + "/actions/runs/" + ENV['GITHUB_RUN_ID']
184
+ end
185
+ private :github_build_url
186
+
187
+ def is_parallel
188
+ ENV['IS_PARALLEL'] != nil
189
+ end
190
+ private :is_parallel
191
+
192
+ def github_job_name
193
+ ENV['GITHUB_JOB']
194
+ end
195
+ private :github_job_name
196
+
122
197
  def coveralls_coverage_data
123
198
  if ci_service == :travis_ci || ci_service == :travis_pro
124
199
  if travis_job_id
125
200
  if ci_service == :travis_ci
126
-
201
+
127
202
  if coverage_access_token.to_s.strip.length > 0
128
203
  raise StandardError, "Access token is set. Uploading coverage data for public repositories doesn't require an access token."
129
204
  end
@@ -133,7 +208,7 @@ module Slather
133
208
  :service_name => "travis-ci",
134
209
  :source_files => coverage_files.map(&:as_json)
135
210
  }.to_json
136
- elsif ci_service == :travis_pro
211
+ elsif ci_service == :travis_pro
137
212
 
138
213
  if coverage_access_token.to_s.strip.length == 0
139
214
  raise StandardError, "Access token is not set. Uploading coverage data for private repositories requires an access token."
@@ -206,8 +281,57 @@ module Slather
206
281
  else
207
282
  raise StandardError, "Environment variable `TC_BUILD_NUMBER` not set. Is this running on a teamcity build?"
208
283
  end
284
+ elsif ci_service == :github
285
+
286
+ if coverage_access_token.to_s.strip.length == 0
287
+ raise StandardError, "Access token is not set. Uploading coverage data for private repositories requires an access token."
288
+ end
289
+
290
+ if github_job_id
291
+ {
292
+ :service_job_id => github_job_id,
293
+ :service_name => "github",
294
+ :repo_token => coverage_access_token,
295
+ :repo_name => github_repo_name,
296
+ :source_files => coverage_files.map(&:as_json),
297
+ :service_build_url => github_build_url,
298
+ :service_pull_request => github_pull_request,
299
+ :git => github_git_info,
300
+ :parallel => is_parallel,
301
+ :flag_name => github_job_name
302
+ }.to_json
303
+ else
304
+ raise StandardError, "Environment variable `GITHUB_RUN_ID` not set. Is this running on github build?"
305
+ end
306
+ elsif ci_service == :bitrise
307
+ {
308
+ :service_job_id => bitrise_job_id,
309
+ :service_name => 'bitrise',
310
+ :repo_token => coverage_access_token,
311
+ :source_files => coverage_files.map(&:as_json),
312
+ :service_pull_request => bitrise_pull_request,
313
+ :service_branch => bitrise_branch_name,
314
+ :git => bitrise_git_info
315
+ }.to_json
209
316
  else
210
- raise StandardError, "No support for ci named #{ci_service}"
317
+ {
318
+ :service_job_id => ENV['CI_BUILD_NUMBER'],
319
+ :service_name => ENV['CI_NAME'] || ci_service,
320
+ :repo_token => coverage_access_token,
321
+ :source_files => coverage_files.map(&:as_json),
322
+ :service_build_url => ENV['CI_BUILD_URL'],
323
+ :service_pull_request => ENV['CI_PULL_REQUEST'],
324
+ :service_branch => ENV['CI_BRANCH'],
325
+ :git => {
326
+ :head => {
327
+ :id => ENV['CI_COMMIT'],
328
+ :committer_name => (`git log --format=%an -n 1 HEAD`.chomp || ""),
329
+ :committer_email => (`git log --format=%ae -n 1 HEAD`.chomp || ""),
330
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
331
+ },
332
+ :branch => ENV['CI_BRANCH']
333
+ }
334
+ }.to_json
211
335
  end
212
336
  end
213
337
  private :coveralls_coverage_data
@@ -220,8 +344,8 @@ module Slather
220
344
 
221
345
  curl_result = `curl -s --form json_file=@#{f.path} #{coveralls_api_jobs_path}`
222
346
 
223
- if curl_result.is_a? String
224
- curl_result_json = JSON.parse(curl_result)
347
+ if curl_result.is_a? String
348
+ curl_result_json = JSON.parse(curl_result)
225
349
 
226
350
  if curl_result_json["error"]
227
351
  error_message = curl_result_json["message"]
@@ -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|
@@ -82,6 +87,22 @@ module Slather
82
87
  percentage = (total_tested_lines / total_relevant_lines.to_f) * 100.0
83
88
  cov.span "Total Coverage : "
84
89
  cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
90
+ cov.span " ("
91
+ cov.span total_tested_lines, :id => "total_tested_lines"
92
+ cov.span " of "
93
+ cov.span total_relevant_lines, :id => "total_relevant_lines"
94
+ cov.span " lines)"
95
+ }
96
+
97
+ cov.h4 {
98
+ percentage = (total_branches_tested / total_relevant_branches.to_f) * 100.0
99
+ cov.span "Total Branch Coverage : "
100
+ cov.span decimal_f(percentage) + '%', :class => class_for_coverage_percentage(percentage), :id => "total_coverage"
101
+ cov.span " ("
102
+ cov.span total_branches_tested, :id => "total_branches_tested"
103
+ cov.span " of "
104
+ cov.span total_relevant_branches, :id => "total_relevant_branches"
105
+ cov.span " lines)"
85
106
  }
86
107
 
87
108
  cov.input(:class => "search", :placeholder => "Search")
@@ -133,6 +154,7 @@ module Slather
133
154
  filepath = coverage_file.source_file_pathname_relative_to_repo_root
134
155
  filename = File.basename(filepath)
135
156
  percentage = coverage_file.percentage_lines_tested
157
+ branch_percentage = coverage_file.rate_branches_tested * 100
136
158
 
137
159
  cleaned_gcov_lines = coverage_file.cleaned_gcov_data.split("\n")
138
160
  is_file_empty = (cleaned_gcov_lines.count <= 0)
@@ -142,7 +164,10 @@ module Slather
142
164
  builder = Nokogiri::HTML::Builder.with(template.at('#reports')) { |cov|
143
165
  cov.h2(:class => "cov_title") {
144
166
  cov.span("Coverage for \"#{filename}\"" + (!is_file_empty ? " : " : ""))
167
+ cov.span("Lines: ") unless is_file_empty
145
168
  cov.span("#{decimal_f(percentage)}%", :class => class_for_coverage_percentage(percentage)) unless is_file_empty
169
+ cov.span(" Branches: ") unless is_file_empty
170
+ cov.span("#{decimal_f(branch_percentage)}%", :class => class_for_coverage_percentage(branch_percentage)) unless is_file_empty
146
171
  }
147
172
 
148
173
  cov.h4("(#{coverage_file.num_lines_tested} of #{coverage_file.num_lines_testable} relevant lines covered)", :class => "cov_subtitle")
@@ -157,8 +182,9 @@ module Slather
157
182
 
158
183
  cov.table(:class => "source_code") {
159
184
  cleaned_gcov_lines.each do |line|
160
-
161
185
  line_number = coverage_file.line_number_in_line(line)
186
+ missed_regions = coverage_file.branch_region_data[line_number]
187
+ hits = coverage_file.coverage_for_line(line)
162
188
  next unless line_number > 0
163
189
 
164
190
  line_source = line.split(line_number_separator, 3)[2]
@@ -171,7 +197,30 @@ module Slather
171
197
  cov.td(line, :class => classes[idx])
172
198
  else
173
199
  cov.td(:class => classes[idx]) {
174
- cov.pre { cov.code(line, :class => "objc") }
200
+ cov.pre {
201
+ # If the line has coverage and missed regions, split up
202
+ # the line to show regions that weren't covered
203
+ if missed_regions != nil && hits != nil && hits > 0
204
+ regions = missed_regions.map do |region|
205
+ region_start, region_length = region
206
+ if region_length != nil
207
+ line[region_start, region_length]
208
+ else
209
+ line[region_start, line.length - region_start]
210
+ end
211
+ end
212
+ current_line = line
213
+ regions.each do |region|
214
+ covered, remainder = current_line.split(region, 2)
215
+ cov.code(covered, :class => "objc")
216
+ cov.code(region, :class => "objc missed")
217
+ current_line = remainder
218
+ end
219
+ cov.code(current_line, :class => "objc")
220
+ else
221
+ cov.code(line, :class => "objc")
222
+ end
223
+ }
175
224
  }
176
225
  end
177
226
  }
@@ -184,10 +233,17 @@ module Slather
184
233
  end
185
234
 
186
235
  def generate_html_template(title, is_index, is_file_empty)
187
- logo_path = "logo.jpg"
188
- css_path = "slather.css"
189
- highlight_js_path = "highlight.pack.js"
190
- list_js_path = "list.min.js"
236
+ if cdn_assets
237
+ logo_path = "https://cdn.jsdelivr.net/gh/SlatherOrg/slather/docs/logo.jpg"
238
+ css_path = "https://cdn.jsdelivr.net/gh/SlatherOrg/slather/assets/slather.css"
239
+ highlight_js_path = "https://cdn.jsdelivr.net/gh/SlatherOrg/slather/assets/highlight.pack.js"
240
+ list_js_path = "https://cdn.jsdelivr.net/gh/SlatherOrg/slather/assets/list.min.js"
241
+ else
242
+ logo_path = "logo.jpg"
243
+ css_path = "slather.css"
244
+ highlight_js_path = "highlight.pack.js"
245
+ list_js_path = "list.min.js"
246
+ end
191
247
 
192
248
  builder = Nokogiri::HTML::Builder.new do |doc|
193
249
  doc.html {
@@ -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