slather 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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