slather 2.3.0 → 2.4.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
  SHA1:
3
- metadata.gz: 5e27d1218948f82525f0b2ed8a6a98204b717fc1
4
- data.tar.gz: bbaffb2b00075ab13a568ae40992d1cb09138e0f
3
+ metadata.gz: 0b3fb54ecb063ddb137572a81d78d071c3abe64c
4
+ data.tar.gz: 7f18e0dce826e19e5929eff17d02368e5d0b27cc
5
5
  SHA512:
6
- metadata.gz: 751fde31c23722c6c143ac0a1bd04421dcb9be6ef3074c97209667ac6e6da393b02dae0457ba36b9223f5d785657be191cba67336d9a960861a0089619bcd43c
7
- data.tar.gz: 31953c5059db5e6197f6fc61fd2b7b1c6173f6c9a77a7dadd4888cf45cca8c88c7bb460271aa8529655c519bd8b90cba15ab84044d041245ac6a9c28b12d1606
6
+ metadata.gz: 47ae378522e002970dea520e193b5de1bed30ed69a259cc1ddc492a54b703a796295faba7535c5749dc5323e18a3f583b1674700ca893a3d6082b0cb2f73b1cd
7
+ data.tar.gz: b87f45afcafb2d8add2baff4b01eaa21e45ed1ae630c017aff8447b6c9703197019e531420e5507a7013acebec6f73059b4e2ab26feb3ad9e92024d9c23a8d15
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  language: objective-c
2
2
  script: bundle exec rake
3
- osx_image: xcode7.3
3
+ osx_image: xcode8.3
4
4
 
5
5
  # Sets Travis to run the Ruby specs on OS X machines which are required to
6
6
  # build the native extensions of Xcodeproj.
data/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## v2.4.0
6
+
7
+ * Xcode 8.3 support.
8
+ [ksuther](https://github.com/ksuther)
9
+ [#291](https://github.com/SlatherOrg/slather/pull/291)
10
+
11
+ * Automatically ignore headers in Xcode platform SDKs.
12
+ [ksuther](https://github.com/ksuther)
13
+ [#286](https://github.com/SlatherOrg/slather/pull/286)
14
+
15
+ * Automatically handle schemes with multiple build or test targets
16
+ [serges147](https://github.com/serges147)
17
+ [#275](https://github.com/SlatherOrg/slather/pull/275)
18
+
19
+ * Added TeamCity as a CI service option
20
+ [joshrlesch](https://github.com/joshrlesch)
21
+ [#279](https://github.com/SlatherOrg/slather/pull/279)
22
+
23
+ * Handle UTF-8 characters correctly in HTML reports
24
+ [0xced](https://github.com/0xced)
25
+ [#259](https://github.com/SlatherOrg/slather/pull/259)
26
+
27
+ * Fix hanging `xcodebuild` invocation when getting derived data path.
28
+ [arthurtoper](https://github.com/arthurtoper)
29
+ [#238](https://github.com/SlatherOrg/slather/pull/238), [#197](https://github.com/SlatherOrg/slather/issues/197), [#212](https://github.com/SlatherOrg/slather/issues/212), [#234](https://github.com/SlatherOrg/slather/issues/234)
30
+
5
31
  ## v2.3.0
6
32
 
7
33
  * Fixes broken fallback value of `input_format` inside `configure_input_format`
data/README.md CHANGED
@@ -91,7 +91,7 @@ before_install: rvm use $RVM_RUBY_VERSION
91
91
  install: bundle install --without=documentation --path ../travis_bundle_dir
92
92
  after_success:
93
93
  - slather
94
- - bash <(curl -s https://codecov.io/bash) -f path/to/xml_report/cobertura.xml
94
+ - bash <(curl -s https://codecov.io/bash) -f path/to/xml_report/cobertura.xml -X coveragepy -X gcov -X xcode
95
95
  ```
96
96
 
97
97
  ```yml
@@ -100,7 +100,7 @@ after_success:
100
100
  test:
101
101
  post:
102
102
  - bundle exec slather
103
- - bash <(curl -s https://codecov.io/bash)
103
+ - bash <(curl -s https://codecov.io/bash) -f path/to/xml_report/cobertura.xml -X coveragepy -X gcov -X xcode
104
104
  ```
105
105
 
106
106
  > Private repo? Add `-t :uuid-repo-token` to the codecov uploader. Read more about uploading report to Codecov [here](https://github.com/codecov/codecov-bash)
@@ -26,6 +26,11 @@ module Slather
26
26
  end
27
27
  private :circleci_pull_request
28
28
 
29
+ def teamcity_job_id
30
+ ENV['TC_BUILD_NUMBER']
31
+ end
32
+ private :teamcity_job_id
33
+
29
34
  def jenkins_job_id
30
35
  ENV['BUILD_ID']
31
36
  end
@@ -41,6 +46,11 @@ module Slather
41
46
  end
42
47
  private :jenkins_branch_name
43
48
 
49
+ def teamcity_branch_name
50
+ ENV['GIT_BRANCH'] || `git ls-remote --heads origin | grep $(git rev-parse HEAD) | cut -d / -f 3-`.chomp
51
+ end
52
+ private :teamcity_branch_name
53
+
44
54
  def buildkite_job_id
45
55
  ENV['BUILDKITE_BUILD_NUMBER']
46
56
  end
@@ -63,6 +73,19 @@ module Slather
63
73
  end
64
74
  private :jenkins_git_info
65
75
 
76
+ def teamcity_git_info
77
+ {
78
+ head: {
79
+ :id => (`git log --format=%H -n 1 HEAD`.chomp || ""),
80
+ :author_name => (`git log --format=%an -n 1 HEAD`.chomp || ""),
81
+ :author_email => (`git log --format=%ae -n 1 HEAD`.chomp || ""),
82
+ :message => (`git log --format=%s -n 1 HEAD`.chomp || "")
83
+ },
84
+ :branch => teamcity_branch_name
85
+ }
86
+ end
87
+ private :teamcity_git_info
88
+
66
89
  def circleci_build_url
67
90
  "https://circleci.com/gh/" + ENV['CIRCLE_PROJECT_USERNAME'] || "" + "/" + ENV['CIRCLE_PROJECT_REPONAME'] || "" + "/" + ENV['CIRCLE_BUILD_NUM'] || ""
68
91
  end
@@ -171,6 +194,18 @@ module Slather
171
194
  else
172
195
  raise StandardError, "Environment variable `BUILDKITE_BUILD_NUMBER` not set. Is this running on a buildkite build?"
173
196
  end
197
+ elsif ci_service == :teamcity
198
+ if teamcity_job_id
199
+ {
200
+ :service_job_id => teamcity_job_id,
201
+ :service_name => "teamcity",
202
+ :repo_token => coverage_access_token,
203
+ :source_files => coverage_files.map(&:as_json),
204
+ :git => teamcity_git_info
205
+ }.to_json
206
+ else
207
+ raise StandardError, "Environment variable `TC_BUILD_NUMBER` not set. Is this running on a teamcity build?"
208
+ end
174
209
  else
175
210
  raise StandardError, "No support for ci named #{ci_service}"
176
211
  end
@@ -157,13 +157,12 @@ module Slather
157
157
 
158
158
  cov.table(:class => "source_code") {
159
159
  cleaned_gcov_lines.each do |line|
160
- data = line.split(line_number_separator, 3)
161
160
 
162
- line_number = data[1].to_i
161
+ line_number = coverage_file.line_number_in_line(line)
163
162
  next unless line_number > 0
164
163
 
165
- coverage_data = data[0].strip
166
- line_data = [line_number, data[2], hits_for_coverage_line(coverage_file, line)]
164
+ line_source = line.split(line_number_separator, 3)[2]
165
+ line_data = [line_number, line_source, hits_for_coverage_line(coverage_file, line)]
167
166
  classes = ["num", "src", "coverage"]
168
167
 
169
168
  cov.tr(:class => class_for_coverage_line(coverage_file,line)) {
@@ -1,5 +1,6 @@
1
1
  require 'slather/coverage_info'
2
2
  require 'slather/coveralls_coverage'
3
+ require 'digest/md5'
3
4
 
4
5
  module Slather
5
6
  class ProfdataCoverageFile
@@ -7,31 +8,50 @@ module Slather
7
8
  include CoverageInfo
8
9
  include CoverallsCoverage
9
10
 
10
- attr_accessor :project, :source, :line_data
11
+ attr_accessor :project, :source, :line_numbers_first, :line_data
11
12
 
12
- def initialize(project, source)
13
+ def initialize(project, source, line_numbers_first)
13
14
  self.project = project
14
15
  self.source = source
16
+ self.line_numbers_first = line_numbers_first
15
17
  create_line_data
16
18
  end
17
19
 
18
20
  def create_line_data
19
21
  all_lines = source_code_lines
20
22
  line_data = Hash.new
21
- all_lines.each { |line| line_data[line_number_in_line(line)] = line }
23
+ all_lines.each { |line| line_data[line_number_in_line(line, self.line_numbers_first)] = line }
22
24
  self.line_data = line_data
23
25
  end
24
26
  private :create_line_data
25
27
 
26
28
  def path_on_first_line?
27
29
  path = self.source.split("\n")[0].sub ":", ""
28
- !path.include?("1|//")
30
+ !path.include?("|//")
29
31
  end
30
32
 
31
33
  def source_file_pathname
32
34
  @source_file_pathname ||= begin
33
- path = self.source.split("\n")[0].sub ":", ""
34
- path &&= Pathname(path)
35
+ if path_on_first_line?
36
+ path = self.source.split("\n")[0].sub ":", ""
37
+ path &&= Pathname(path)
38
+ else
39
+ # llvm-cov was run with just one matching source file
40
+ # It doesn't print the source path in this case, so we have to find it ourselves
41
+ # This is slow because we read every source file and compare it, but this should only happen if there aren't many source files
42
+ digest = Digest::MD5.digest(self.raw_source)
43
+ path = nil
44
+
45
+ project.find_source_files.each do |file|
46
+ file_digest = Digest::MD5.digest(File.read(file).strip)
47
+
48
+ if digest == file_digest
49
+ path = file
50
+ end
51
+ end
52
+
53
+ path
54
+ end
35
55
  end
36
56
  end
37
57
 
@@ -58,6 +78,12 @@ module Slather
58
78
  @all_lines
59
79
  end
60
80
 
81
+ def raw_source
82
+ self.source.lines.map do |line|
83
+ line.split('|').last
84
+ end.join
85
+ end
86
+
61
87
  def cleaned_gcov_data
62
88
  source_data
63
89
  end
@@ -66,10 +92,17 @@ module Slather
66
92
  self.source
67
93
  end
68
94
 
69
- def line_number_in_line(line)
70
- line =~ /^(\s*)(\d*)\|(\s*)(\d+)\|/
71
- if $4 != nil
72
- match = $4.strip
95
+ def line_number_in_line(line, line_numbers_first = self.line_numbers_first)
96
+ if line_numbers_first
97
+ line =~ /^(\s*)(\d*)/
98
+ group = $2
99
+ else
100
+ line =~ /^(\s*)(\d*)\|(\s*)(\d+)\|/
101
+ group = $4
102
+ end
103
+
104
+ if group != nil
105
+ match = group.strip
73
106
  case match
74
107
  when /[0-9]+/
75
108
  return match.to_i
@@ -91,28 +124,43 @@ module Slather
91
124
 
92
125
  def line_coverage_data
93
126
  source_code_lines.map do |line|
94
- coverage_for_line(line)
127
+ coverage_for_line(line, self.line_numbers_first)
95
128
  end
96
129
  end
97
130
 
98
- def coverage_for_line(line)
131
+ def coverage_for_line(line, line_numbers_first = self.line_numbers_first)
99
132
  line = line.gsub(":", "|")
100
- line =~ /^(\s*)(\d*)\|/
101
133
 
102
- if $2 == nil
134
+ if line_numbers_first
135
+ line =~ /^(\s*)(\d*)\|(\s*)(\d+)\|/
136
+ group = $4
137
+ else
138
+ line =~ /^(\s*)(\d*)\|/
139
+ group = $2
140
+ end
141
+
142
+ if group == nil
103
143
  # Check for thousands or millions (llvm-cov outputs hit counts as 25.3k or 3.8M)
104
- did_match = line =~ /^(\s*)(\d+\.\d+)(k|M)\|/
144
+ if line_numbers_first
145
+ did_match = line =~ /^(\s*)(\d+)\|(\s*)(\d+\.\d+)(k|M)\|/
146
+ group = $4
147
+ units_group = $5
148
+ else
149
+ did_match = line =~ /^(\s*)(\d+\.\d+)(k|M)\|/
150
+ group = $2
151
+ units_group = $3
152
+ end
105
153
 
106
154
  if did_match
107
- count = $2.strip
108
- units = $3 == 'k' ? 1000 : 1000000
155
+ count = group.strip
156
+ units = units_group == 'k' ? 1000 : 1000000
109
157
 
110
158
  (count.to_f * units).to_i
111
159
  else
112
160
  return nil
113
161
  end
114
162
  else
115
- match = $2.strip
163
+ match = group.strip
116
164
  case match
117
165
  when /[0-9]+/
118
166
  match.to_i
@@ -144,24 +192,16 @@ module Slather
144
192
  private :supported_file_extensions
145
193
 
146
194
  def ignored?
147
- ignore = false
148
- platform_ignore_list.map do |ignore_suffix|
149
- ignore = source_file_pathname.to_s.end_with? ignore_suffix
150
- if ignore
151
- break
152
- end
195
+ # This indicates a llvm-cov coverage warning (occurs if a passed in source file
196
+ # is not covered or with ccache in some cases).
197
+ ignore = source_file_pathname.to_s.end_with? "isn't covered."
198
+
199
+ if !ignore
200
+ # Ignore source files inside of platform SDKs
201
+ ignore = (/Xcode.*\.app\/Contents\/Developer\/Platforms/ =~ source_file_pathname.to_s) != nil
153
202
  end
154
- ignore ? ignore : super
155
- end
156
203
 
157
- def platform_ignore_list
158
- ["MacOSX.platform/Developer/Library/Frameworks/XCTest.framework/Headers/XCTestAssertionsImpl.h",
159
- "MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/objc/objc.h",
160
- "MacOSX.platform/Developer/Library/Frameworks/XCTest.framework/Headers/XCTestAssertions.h",
161
- # This indicates a llvm-cov coverage warning (occurs if a passed in source file
162
- # is not covered or with ccache in some cases).
163
- "isn't covered."]
204
+ ignore ? ignore : super
164
205
  end
165
- private :platform_ignore_list
166
206
  end
167
207
  end
@@ -52,7 +52,7 @@ module Slather
52
52
 
53
53
  attr_accessor :build_directory, :ignore_list, :ci_service, :coverage_service, :coverage_access_token, :source_directory,
54
54
  :output_directory, :xcodeproj, :show_html, :verbose_mode, :input_format, :scheme, :workspace, :binary_file, :binary_basename, :source_files,
55
- :decimals
55
+ :decimals, :llvm_version
56
56
 
57
57
  alias_method :setup_for_coverage, :slather_setup_for_coverage
58
58
 
@@ -84,7 +84,7 @@ module Slather
84
84
  end
85
85
 
86
86
  # redirect stderr to avoid xcodebuild errors being printed.
87
- build_settings = `xcodebuild #{projectOrWorkspaceArgument} #{schemeArgument} -showBuildSettings #{buildAction} 2>&1`
87
+ build_settings = `xcodebuild #{projectOrWorkspaceArgument} #{schemeArgument} -showBuildSettings #{buildAction} CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO 2>&1`
88
88
 
89
89
  if build_settings
90
90
  derived_data_path = build_settings.match(/ OBJROOT = (.+)/)
@@ -126,13 +126,14 @@ module Slather
126
126
  def profdata_coverage_files
127
127
  coverage_files = []
128
128
  source_files = find_source_files || []
129
+ line_numbers_first = Gem::Version.new(self.llvm_version) >= Gem::Version.new('8.1.0')
129
130
 
130
131
  if self.binary_file
131
132
  self.binary_file.each do |binary_path|
132
133
  files = profdata_llvm_cov_output(binary_path, source_files).split("\n\n")
133
134
 
134
135
  coverage_files.concat(files.map do |source|
135
- coverage_file = coverage_file_class.new(self, source)
136
+ coverage_file = coverage_file_class.new(self, source, line_numbers_first)
136
137
  # If a single source file is used, the resulting output does not contain the file name.
137
138
  coverage_file.source_file_pathname = source_files.first if source_files.count == 1
138
139
  !coverage_file.ignored? ? coverage_file : nil
@@ -208,7 +209,8 @@ module Slather
208
209
  private :unsafe_profdata_llvm_cov_output
209
210
 
210
211
  def profdata_llvm_cov_output(binary_path, source_files)
211
- unsafe_profdata_llvm_cov_output(binary_path, source_files).encode!('UTF-8', 'binary', :invalid => :replace, undef: :replace)
212
+ output = unsafe_profdata_llvm_cov_output(binary_path, source_files)
213
+ output.valid_encoding? ? output : output.encode!('UTF-8', 'binary', :invalid => :replace, undef: :replace)
212
214
  end
213
215
  private :profdata_llvm_cov_output
214
216
 
@@ -239,6 +241,8 @@ module Slather
239
241
  configure_input_format
240
242
  configure_binary_file
241
243
  configure_decimals
244
+
245
+ self.llvm_version = `xcrun llvm-cov --version`.match(/Apple LLVM version ([\d\.]+)/).captures[0]
242
246
  rescue => e
243
247
  puts e.message
244
248
  puts failure_help_string
@@ -391,20 +395,9 @@ module Slather
391
395
 
392
396
  xcscheme = Xcodeproj::XCScheme.new(xcscheme_path)
393
397
 
394
- begin
395
- buildable_name = xcscheme.build_action.entries[0].buildable_references[0].buildable_name
396
- rescue
397
- # xcodeproj will raise an exception if there are no entries in the build action
398
- end
399
-
400
- if buildable_name == nil or buildable_name.end_with? ".a"
401
- # Can't run code coverage on static libraries, look for an associated test bundle
402
- buildable_name = xcscheme.test_action.testables[0].buildable_references[0].buildable_name
403
- end
404
-
405
398
  configuration = xcscheme.test_action.build_configuration
406
399
 
407
- search_list = binary_basename || [buildable_name]
400
+ search_list = binary_basename || find_buildable_names(xcscheme)
408
401
 
409
402
  search_list.each do |search_for|
410
403
  found_product = Dir["#{profdata_coverage_dir}/Products/#{configuration}*/#{search_for}*"].sort { |x, y|
@@ -461,6 +454,37 @@ module Slather
461
454
  found_binaries.map { |binary| File.expand_path(binary) }
462
455
  end
463
456
 
457
+ def find_buildable_names(xcscheme)
458
+ found_buildable_names = []
459
+
460
+ # enumerate build action entries
461
+ begin
462
+ xcscheme.build_action.entries.each do |entry|
463
+ buildable_name = entry.buildable_references[0].buildable_name
464
+
465
+ if !buildable_name.end_with? ".a"
466
+ # Can't run code coverage on static libraries
467
+ found_buildable_names.push(buildable_name)
468
+ end
469
+ end
470
+ rescue
471
+ # xcodeproj will raise an exception if there are no entries in the build action
472
+ end
473
+
474
+ # enumerate test action entries
475
+ begin
476
+ xcscheme.test_action.testables.each do |entry|
477
+ buildable_name = entry.buildable_references[0].buildable_name
478
+ found_buildable_names.push(buildable_name)
479
+ end
480
+ rescue
481
+ # just in case if there are no entries in the test action
482
+ end
483
+
484
+ # some items are both buildable and testable, so return only unique ones
485
+ found_buildable_names.uniq
486
+ end
487
+
464
488
  def find_source_files
465
489
  source_files = load_option_array("source_files")
466
490
  return if source_files.nil?
@@ -1,3 +1,3 @@
1
1
  module Slather
2
- VERSION = '2.3.0' unless defined?(Slather::VERSION)
2
+ VERSION = '2.4.0' unless defined?(Slather::VERSION)
3
3
  end