xcov 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -3
- data/lib/xcov-core.rb +19 -20
- data/lib/xcov.rb +1 -1
- data/lib/xcov/commands_generator.rb +1 -1
- data/lib/xcov/coveralls_handler.rb +98 -0
- data/lib/xcov/error_handler.rb +15 -24
- data/lib/xcov/ignore_handler.rb +1 -1
- data/lib/xcov/manager.rb +126 -3
- data/lib/xcov/model/base.rb +0 -1
- data/lib/xcov/model/function.rb +2 -2
- data/lib/xcov/model/line.rb +3 -3
- data/lib/xcov/model/range.rb +2 -2
- data/lib/xcov/model/report.rb +3 -3
- data/lib/xcov/model/source.rb +4 -4
- data/lib/xcov/model/target.rb +4 -4
- data/lib/xcov/options.rb +191 -124
- data/lib/xcov/project_extensions.rb +2 -2
- data/lib/xcov/slack_poster.rb +5 -3
- data/lib/xcov/version.rb +1 -1
- metadata +17 -3
- data/lib/xcov/runner.rb +0 -123
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3471895be03f8b9d1f02805ac5a0e72775d67c9
|
4
|
+
data.tar.gz: fce99c62ab472f32c6db79659cbfc473aa5afa2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dca0119f6dfe20839137d471738a7a5d1ca275a49a89c05805db8daf6e8d2368f1747546d3c6f866395e07a9770421b2047f2ea44aa2b4a79459a536d131ead8
|
7
|
+
data.tar.gz: 944c9806c4f941d67c59463a3119ca50604673346fa68237437ad25a879015ea779a1b15c19e3dfb3aba14185146d0e3d7257c0e2a1b59510cce15d2a612d37f
|
data/README.md
CHANGED
@@ -13,9 +13,10 @@ sudo gem install xcov
|
|
13
13
|
```
|
14
14
|
|
15
15
|
## Features
|
16
|
-
* Built on top of [
|
16
|
+
* Built on top of [fastlane](https://fastlane.tools), you can easily plug it on to your CI environment.
|
17
17
|
* Blacklisting of those files which coverage you want to ignore.
|
18
18
|
* Minimum acceptable coverage percentage.
|
19
|
+
* Compatible with [Coveralls](https://coveralls.io).
|
19
20
|
* Nice HTML reports.
|
20
21
|
|
21
22
|
![/assets_readme/report.png](/assets_readme/report.png)
|
@@ -34,7 +35,7 @@ In order to make *xcov* run you must:
|
|
34
35
|
![/assets_readme/gather_coverage.png](/assets_readme/gather_coverage.png)
|
35
36
|
|
36
37
|
## Usage
|
37
|
-
*xcov* analyzes the `.xccoverage` files created after running your tests therefore, before executing xcov, you need to run your tests with either `Xcode`, `xcodebuild` or [scan](https://github.com/fastlane/scan). Once completed, obtain your coverage report by providing a few parameters:
|
38
|
+
*xcov* analyzes the `.xccoverage` files created after running your tests therefore, before executing xcov, you need to run your tests with either `Xcode`, `xcodebuild` or [scan](https://github.com/fastlane/fastlane/tree/master/scan). Once completed, obtain your coverage report by providing a few parameters:
|
38
39
|
```
|
39
40
|
xcov -w LystSDK.xcworkspace -s LystSDK -o xcov_output
|
40
41
|
```
|
@@ -47,7 +48,7 @@ xcov -w LystSDK.xcworkspace -s LystSDK -o xcov_output
|
|
47
48
|
* `--output_directory` `-o`: Path for the output folder where the report files will be saved.
|
48
49
|
* `--source_directory` `-r`: The path to project's root directory.
|
49
50
|
* `--derived_data_path` `-j`: Path of your project `Derived Data` folder (optional).
|
50
|
-
* `--minimum_coverage_percentage` `-m`: Raise exception if overall coverage percentage is under this value (ie. 75).
|
51
|
+
* `--minimum_coverage_percentage` `-m`: Raise exception if overall coverage percentage is under this value (ie. 75.0).
|
51
52
|
* `--include_test_targets`: Enables coverage reports for `.xctest` targets.
|
52
53
|
* `--ignore_file_path` `-x`: Relative or absolute path to the file containing the list of ignored files.
|
53
54
|
* `--exclude_targets`: Comma separated list of targets to exclude from coverage report.
|
@@ -59,6 +60,9 @@ xcov -w LystSDK.xcworkspace -s LystSDK -o xcov_output
|
|
59
60
|
* `--markdown_report`: Enables the creation of a markdown report (optional).
|
60
61
|
* `--skip_slack`: Add this flag to avoid publishing results on Slack (optional).
|
61
62
|
* `--only_project_targets`: Display the coverage only for main project targets (e.g. skip Pods targets).
|
63
|
+
* `--coveralls_service_name`: Name of the CI service compatible with Coveralls. i.e. travis-ci. This option must be defined along with coveralls_service_job_id.
|
64
|
+
* `--coveralls_service_job_id`: Name of the current job running on a CI service compatible with Coveralls. This option must be defined along with coveralls_service_name.
|
65
|
+
* `--coveralls_repo_token`: Repository token to be used by integrations not compatible with Coveralls.
|
62
66
|
|
63
67
|
_**Note:** All paths you provide should be absolute and unescaped_
|
64
68
|
|
data/lib/xcov-core.rb
CHANGED
@@ -20,27 +20,26 @@ module Xcov
|
|
20
20
|
JSON.parse(output_file)
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.execute_command
|
24
|
-
FastlaneCore::CommandExecutor
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
)
|
23
|
+
def self.execute_command(command, description)
|
24
|
+
FastlaneCore::CommandExecutor.execute(
|
25
|
+
command: command,
|
26
|
+
print_all: true,
|
27
|
+
print_command: true,
|
28
|
+
prefix: description,
|
29
|
+
loading: "Loading...",
|
30
|
+
error: proc do |error_output|
|
31
|
+
begin
|
32
|
+
Xcov::ErrorHandler.handle_error(error_output)
|
33
|
+
rescue => ex
|
34
|
+
Xcov::SlackPoster.new.run({
|
35
|
+
build_errors: 1
|
36
|
+
})
|
37
|
+
raise ex
|
38
|
+
end
|
39
|
+
end
|
40
|
+
)
|
42
41
|
end
|
43
|
-
|
42
|
+
|
44
43
|
end
|
45
44
|
|
46
45
|
end
|
data/lib/xcov.rb
CHANGED
@@ -2,9 +2,9 @@ require 'json'
|
|
2
2
|
require 'xcov/version'
|
3
3
|
require 'xcov/manager'
|
4
4
|
require 'xcov/options'
|
5
|
-
require 'xcov/runner'
|
6
5
|
require 'xcov/ignore_handler'
|
7
6
|
require 'xcov/error_handler'
|
7
|
+
require 'xcov/coveralls_handler'
|
8
8
|
require 'xcov/slack_poster'
|
9
9
|
require 'xcov/model/base'
|
10
10
|
require 'xcov/model/report'
|
@@ -38,7 +38,7 @@ module Xcov
|
|
38
38
|
c.description = Xcov::DESCRIPTION
|
39
39
|
c.action do |_args, options|
|
40
40
|
config = FastlaneCore::Configuration.create(Xcov::Options.available_options, convert_options(options))
|
41
|
-
Xcov::Manager.new
|
41
|
+
Xcov::Manager.new(config).run()
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "tempfile"
|
2
|
+
|
3
|
+
module Xcov
|
4
|
+
class CoverallsHandler
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def submit(report)
|
9
|
+
coveralls_json_path = convert_and_store_coveralls_json(report)
|
10
|
+
perform_request(coveralls_json_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def convert_and_store_coveralls_json(report)
|
16
|
+
root_path = `git rev-parse --show-toplevel`
|
17
|
+
root_path.delete!("\n")
|
18
|
+
root_path << '/'
|
19
|
+
|
20
|
+
# Iterate through targets
|
21
|
+
source_files = []
|
22
|
+
report.targets.each do |target|
|
23
|
+
# Iterate through target files
|
24
|
+
target.files.each do |file|
|
25
|
+
next if file.ignored
|
26
|
+
|
27
|
+
# Iterate through file lines
|
28
|
+
lines = []
|
29
|
+
file.lines.each do |line|
|
30
|
+
lines << line.execution_count if line.executable
|
31
|
+
lines << nil unless line.executable
|
32
|
+
end
|
33
|
+
|
34
|
+
relative_path = file.location
|
35
|
+
relative_path.slice!(root_path)
|
36
|
+
source_files << {
|
37
|
+
name: relative_path,
|
38
|
+
source_digest: digest_for_file(relative_path),
|
39
|
+
coverage: lines
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
json = {
|
45
|
+
service_job_id: Xcov.config[:coveralls_service_job_id],
|
46
|
+
service_name: Xcov.config[:coveralls_service_name],
|
47
|
+
repo_token: Xcov.config[:coveralls_repo_token],
|
48
|
+
source_files: source_files
|
49
|
+
}
|
50
|
+
|
51
|
+
require "json"
|
52
|
+
|
53
|
+
# Persist
|
54
|
+
coveralls_json_file = Tempfile.new("coveralls_report.json")
|
55
|
+
File.open(coveralls_json_file.path, "wb") do |file|
|
56
|
+
file.puts JSON.pretty_generate(json)
|
57
|
+
file.close
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return path
|
61
|
+
return coveralls_json_file.path
|
62
|
+
end
|
63
|
+
|
64
|
+
def perform_request(coveralls_json_path)
|
65
|
+
require 'net/http/post/multipart'
|
66
|
+
|
67
|
+
# Build request
|
68
|
+
url = URI.parse("https://coveralls.io/api/v1/jobs")
|
69
|
+
UI.message "Uploading coverage report to coveralls.io".yellow
|
70
|
+
request = Net::HTTP::Post::Multipart.new(
|
71
|
+
url.path,
|
72
|
+
"json_file" => UploadIO.new(File.new(coveralls_json_path), "text/plain", "coveralls_report.json")
|
73
|
+
)
|
74
|
+
|
75
|
+
# Perform request
|
76
|
+
http = Net::HTTP.new(url.host, url.port)
|
77
|
+
http.use_ssl = true
|
78
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
79
|
+
response = http.request(request)
|
80
|
+
|
81
|
+
if response.code == "200"
|
82
|
+
UI.message "Submitted report to coveralls.io successfully".green
|
83
|
+
else
|
84
|
+
UI.message "There was an error submitting the report to coveralls.io".red
|
85
|
+
UI.message response.body.red
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def digest_for_file(file_path)
|
90
|
+
hash = `git hash-object #{file_path}`
|
91
|
+
hash.delete!("\n")
|
92
|
+
return hash
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
data/lib/xcov/error_handler.rb
CHANGED
@@ -3,36 +3,26 @@ module Xcov
|
|
3
3
|
class ErrorHandler
|
4
4
|
|
5
5
|
class << self
|
6
|
-
|
7
|
-
# This method should raise an exception in any case, as the return code indicated a failed build
|
6
|
+
|
8
7
|
def handle_error(output)
|
9
|
-
# The order of the handling below is import
|
10
8
|
case output
|
11
|
-
when /
|
12
|
-
print "Your shell environment is not correctly configured"
|
13
|
-
print "Instead of UTF-8 your shell uses US-ASCII"
|
14
|
-
print "Please add the following to your '~/.bashrc':"
|
15
|
-
print ""
|
16
|
-
print " export LANG=en_US.UTF-8"
|
17
|
-
print " export LANGUAGE=en_US.UTF-8"
|
18
|
-
print " export LC_ALL=en_US.UTF-8"
|
19
|
-
print ""
|
20
|
-
print "You'll have to restart your shell session after updating the file."
|
21
|
-
print "If you are using zshell or another shell, make sure to edit the correct bash file."
|
22
|
-
print "For more information visit this stackoverflow answer:"
|
23
|
-
print "https://stackoverflow.com/a/17031697/445598"
|
24
|
-
when /CoverageNotFound/
|
9
|
+
when /XccoverageFileNotFound/
|
25
10
|
print "Unable to find any .xccoverage file."
|
26
11
|
print "Make sure you have enabled 'Gather code coverage' setting on your scheme settings."
|
27
12
|
print "Alternatively you can provide the full path to your .xccoverage file."
|
28
|
-
when /
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
13
|
+
when /UnableToParseXccoverageFile/
|
14
|
+
print "There was an error converting the .xccoverage file to json."
|
15
|
+
when /CoverageUnderThreshold/
|
16
|
+
print "The build has been marked as failed because minimum overall coverage has not been reached."
|
17
|
+
when /UnableToMapJsonToXcovModel/
|
18
|
+
print "There was an error converting the json file to xcov's model objects."
|
34
19
|
end
|
35
|
-
raise "Error
|
20
|
+
raise "Error creating your coverage report - see the log above".red
|
21
|
+
end
|
22
|
+
|
23
|
+
def handle_error_with_custom_message(error, custom_message)
|
24
|
+
print custom_message
|
25
|
+
handle_error error
|
36
26
|
end
|
37
27
|
|
38
28
|
private
|
@@ -40,6 +30,7 @@ module Xcov
|
|
40
30
|
def print(text)
|
41
31
|
UI.message text.red
|
42
32
|
end
|
33
|
+
|
43
34
|
end
|
44
35
|
|
45
36
|
end
|
data/lib/xcov/ignore_handler.rb
CHANGED
@@ -25,7 +25,7 @@ module Xcov
|
|
25
25
|
# Ignore specific files
|
26
26
|
filename = File.basename(path)
|
27
27
|
return true if should_ignore_file(filename)
|
28
|
-
|
28
|
+
|
29
29
|
# Also ignore the files from ignored folders
|
30
30
|
relative = relative_path(path).downcase
|
31
31
|
return @list.any? { |ignored_path| relative.start_with? ignored_path }
|
data/lib/xcov/manager.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require 'fastlane_core'
|
2
|
+
require 'pty'
|
3
|
+
require 'open3'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'terminal-table'
|
6
|
+
require 'xcov-core'
|
7
|
+
require 'pathname'
|
8
|
+
require 'json'
|
2
9
|
|
3
10
|
module Xcov
|
4
11
|
class Manager
|
5
12
|
|
6
|
-
def
|
13
|
+
def initialize(options)
|
7
14
|
# Set command options
|
8
15
|
Xcov.config = options
|
9
16
|
|
@@ -16,9 +23,125 @@ module Xcov
|
|
16
23
|
|
17
24
|
# Print summary
|
18
25
|
FastlaneCore::PrintTable.print_values(config: options, hide_keys: [:slack_url], title: "Summary for xcov #{Xcov::VERSION}")
|
26
|
+
end
|
19
27
|
|
28
|
+
def run
|
20
29
|
# Run xcov
|
21
|
-
|
30
|
+
json_report = parse_xccoverage
|
31
|
+
report = generate_xcov_report(json_report)
|
32
|
+
validate_report(report)
|
33
|
+
submit_to_coveralls(report)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def parse_xccoverage
|
39
|
+
# Find .xccoverage file
|
40
|
+
test_logs_path = derived_data_path + "Logs/Test/"
|
41
|
+
xccoverage_files = Dir["#{test_logs_path}*.xccoverage"].sort_by { |filename| File.mtime(filename) }.reverse
|
42
|
+
|
43
|
+
unless test_logs_path.directory? && !xccoverage_files.empty?
|
44
|
+
ErrorHandler.handle_error("XccoverageFileNotFound")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Convert .xccoverage file to json
|
48
|
+
json_report = Xcov::Core::Parser.parse(xccoverage_files.first)
|
49
|
+
ErrorHandler.handle_error("UnableToParseXccoverageFile") if json_report.nil?
|
50
|
+
|
51
|
+
json_report
|
52
|
+
end
|
53
|
+
|
54
|
+
def generate_xcov_report(json_report)
|
55
|
+
# Create output path
|
56
|
+
output_path = Xcov.config[:output_directory]
|
57
|
+
FileUtils.mkdir_p(output_path)
|
58
|
+
|
59
|
+
# Convert report to xcov model objects
|
60
|
+
report = Report.map(json_report)
|
61
|
+
|
62
|
+
# Raise exception in case of failure
|
63
|
+
ErrorHandler.handle_error("UnableToMapJsonToXcovModel") if report.nil?
|
64
|
+
|
65
|
+
if Xcov.config[:html_report] then
|
66
|
+
resources_path = File.join(output_path, "resources")
|
67
|
+
FileUtils.mkdir_p(resources_path)
|
68
|
+
|
69
|
+
# Copy images to output resources folder
|
70
|
+
Dir[File.join(File.dirname(__FILE__), "../../assets/images/*")].each do |path|
|
71
|
+
FileUtils.cp_r(path, resources_path)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Copy stylesheets to output resources folder
|
75
|
+
Dir[File.join(File.dirname(__FILE__), "../../assets/stylesheets/*")].each do |path|
|
76
|
+
FileUtils.cp_r(path, resources_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Copy javascripts to output resources folder
|
80
|
+
Dir[File.join(File.dirname(__FILE__), "../../assets/javascripts/*")].each do |path|
|
81
|
+
FileUtils.cp_r(path, resources_path)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create HTML report
|
85
|
+
File.open(File.join(output_path, "index.html"), "wb") do |file|
|
86
|
+
file.puts report.html_value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Create Markdown report
|
91
|
+
if Xcov.config[:markdown_report] then
|
92
|
+
File.open(File.join(output_path, "report.md"), "wb") do |file|
|
93
|
+
file.puts report.markdown_value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Create JSON report
|
98
|
+
if Xcov.config[:json_report] then
|
99
|
+
File.open(File.join(output_path, "report.json"), "wb") do |file|
|
100
|
+
file.puts report.json_value.to_json
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Post result
|
105
|
+
SlackPoster.new.run(report)
|
106
|
+
|
107
|
+
# Print output
|
108
|
+
table_rows = []
|
109
|
+
report.targets.each do |target|
|
110
|
+
table_rows << [target.name, target.displayable_coverage]
|
111
|
+
end
|
112
|
+
puts Terminal::Table.new({
|
113
|
+
title: "xcov Coverage Report".green,
|
114
|
+
rows: table_rows
|
115
|
+
})
|
116
|
+
puts ""
|
117
|
+
|
118
|
+
report
|
119
|
+
end
|
120
|
+
|
121
|
+
def validate_report(report)
|
122
|
+
# Raise exception if overall coverage is under threshold
|
123
|
+
minimumPercentage = Xcov.config[:minimum_coverage_percentage] / 100
|
124
|
+
if minimumPercentage > report.coverage
|
125
|
+
error_message = "Actual Code Coverage (#{"%.2f%" % (report.coverage*100)}) below threshold of #{"%.2f%" % (minimumPercentage*100)}"
|
126
|
+
ErrorHandler.handle_error_with_custom_message("CoverageUnderThreshold", error_message)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def submit_to_coveralls(report)
|
131
|
+
if !Xcov.config[:coveralls_repo_token].nil? || !(Xcov.config[:coveralls_service_name].nil? && Xcov.config[:coveralls_service_job_id].nil?)
|
132
|
+
CoverallsHandler.submit(report)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Auxiliar methods
|
137
|
+
|
138
|
+
def derived_data_path
|
139
|
+
# If DerivedData path was supplied, return
|
140
|
+
return Pathname.new(Xcov.config[:derived_data_path]) unless Xcov.config[:derived_data_path].nil?
|
141
|
+
|
142
|
+
# Otherwise check project file
|
143
|
+
product_builds_path = Pathname.new(Xcov.project.default_build_settings(key: "SYMROOT"))
|
144
|
+
return product_builds_path.parent.parent
|
22
145
|
end
|
23
146
|
|
24
147
|
end
|
data/lib/xcov/model/base.rb
CHANGED
data/lib/xcov/model/function.rb
CHANGED
@@ -3,7 +3,7 @@ require 'cgi'
|
|
3
3
|
module Xcov
|
4
4
|
class Function < Xcov::Base
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize(name, coverage)
|
7
7
|
@name = CGI::escapeHTML(name)
|
8
8
|
@coverage = coverage
|
9
9
|
@displayable_coverage = self.create_displayable_coverage
|
@@ -27,7 +27,7 @@ module Xcov
|
|
27
27
|
|
28
28
|
# Class methods
|
29
29
|
|
30
|
-
def self.map
|
30
|
+
def self.map(dictionary)
|
31
31
|
Function.new(dictionary["name"], dictionary["coverage"])
|
32
32
|
end
|
33
33
|
|
data/lib/xcov/model/line.rb
CHANGED
@@ -5,7 +5,7 @@ module Xcov
|
|
5
5
|
attr_reader :executable
|
6
6
|
attr_reader :ranges
|
7
7
|
|
8
|
-
def initialize
|
8
|
+
def initialize(execution_count, executable, ranges = nil)
|
9
9
|
@execution_count = execution_count
|
10
10
|
@executable = executable
|
11
11
|
@ranges = ranges
|
@@ -17,12 +17,12 @@ module Xcov
|
|
17
17
|
|
18
18
|
# Class methods
|
19
19
|
|
20
|
-
def self.map
|
20
|
+
def self.map(dictionary)
|
21
21
|
ranges = map_ranges(dictionary["ranges"])
|
22
22
|
Line.new(dictionary["executionCount"], dictionary["executable"], ranges)
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.map_ranges
|
25
|
+
def self.map_ranges(dictionaries)
|
26
26
|
return nil if dictionaries.nil?
|
27
27
|
dictionaries.map { |dictionary| Range.map(dictionary) }
|
28
28
|
end
|
data/lib/xcov/model/range.rb
CHANGED
@@ -5,7 +5,7 @@ module Xcov
|
|
5
5
|
attr_reader :location
|
6
6
|
attr_reader :length
|
7
7
|
|
8
|
-
def initialize
|
8
|
+
def initialize(execution_count, location, length)
|
9
9
|
@execution_count = execution_count
|
10
10
|
@location = location
|
11
11
|
@length = length
|
@@ -13,7 +13,7 @@ module Xcov
|
|
13
13
|
|
14
14
|
# Class methods
|
15
15
|
|
16
|
-
def self.map
|
16
|
+
def self.map(dictionary)
|
17
17
|
Range.new(
|
18
18
|
dictionary["executionCount"],
|
19
19
|
dictionary["location"],
|
data/lib/xcov/model/report.rb
CHANGED
@@ -7,7 +7,7 @@ module Xcov
|
|
7
7
|
attr_accessor :summary
|
8
8
|
attr_accessor :target_templates
|
9
9
|
|
10
|
-
def initialize
|
10
|
+
def initialize(targets)
|
11
11
|
@targets = targets
|
12
12
|
@coverage = average_coverage(targets)
|
13
13
|
@displayable_coverage = self.create_displayable_coverage
|
@@ -61,7 +61,7 @@ module Xcov
|
|
61
61
|
|
62
62
|
# Class methods
|
63
63
|
|
64
|
-
def self.map
|
64
|
+
def self.map(dictionary)
|
65
65
|
targets = Report.filter_targets dictionary["targets"]
|
66
66
|
|
67
67
|
# Create target objects
|
@@ -70,7 +70,7 @@ module Xcov
|
|
70
70
|
Report.new(targets)
|
71
71
|
end
|
72
72
|
|
73
|
-
def self.filter_targets
|
73
|
+
def self.filter_targets(targets)
|
74
74
|
filtered_targets = Array.new(targets)
|
75
75
|
filtered_targets = filtered_targets.select { |target| !target["name"].include?(".xctest") } if !Xcov.config[:include_test_targets]
|
76
76
|
|
data/lib/xcov/model/source.rb
CHANGED
@@ -12,7 +12,7 @@ module Xcov
|
|
12
12
|
attr_accessor :function_templates
|
13
13
|
attr_accessor :lines
|
14
14
|
|
15
|
-
def initialize
|
15
|
+
def initialize(name, location, coverage, functions, lines = nil)
|
16
16
|
@name = CGI::escapeHTML(name)
|
17
17
|
@location = CGI::escapeHTML(location)
|
18
18
|
@coverage = coverage
|
@@ -74,7 +74,7 @@ module Xcov
|
|
74
74
|
|
75
75
|
# Class methods
|
76
76
|
|
77
|
-
def self.map
|
77
|
+
def self.map(dictionary)
|
78
78
|
name = dictionary["name"]
|
79
79
|
location = dictionary["location"]
|
80
80
|
coverage = dictionary["coverage"]
|
@@ -83,12 +83,12 @@ module Xcov
|
|
83
83
|
Source.new(name, location, coverage, functions, lines)
|
84
84
|
end
|
85
85
|
|
86
|
-
def self.map_lines
|
86
|
+
def self.map_lines(dictionaries)
|
87
87
|
return nil if dictionaries.nil?
|
88
88
|
dictionaries.map { |line| Line.map(line) }
|
89
89
|
end
|
90
90
|
|
91
|
-
def self.type
|
91
|
+
def self.type(name)
|
92
92
|
types_map = {
|
93
93
|
".swift" => "swift",
|
94
94
|
".m" => "objc",
|
data/lib/xcov/model/target.rb
CHANGED
@@ -9,7 +9,7 @@ module Xcov
|
|
9
9
|
attr_accessor :files
|
10
10
|
attr_accessor :file_templates
|
11
11
|
|
12
|
-
def initialize
|
12
|
+
def initialize(name, executable, covered, files)
|
13
13
|
@name = CGI::escapeHTML(name)
|
14
14
|
@executable_lines = executable
|
15
15
|
@covered_lines = covered
|
@@ -56,7 +56,7 @@ module Xcov
|
|
56
56
|
|
57
57
|
# Class methods
|
58
58
|
|
59
|
-
def self.map
|
59
|
+
def self.map(dictionary)
|
60
60
|
name = dictionary["name"]
|
61
61
|
files = dictionary["files"].map { |file| Source.map(file)}
|
62
62
|
files = files.sort &by_coverage_with_ignored_at_the_end
|
@@ -86,7 +86,7 @@ module Xcov
|
|
86
86
|
files.select { |file| !file.ignored }
|
87
87
|
end
|
88
88
|
|
89
|
-
def self.calculate_number_of_covered_lines
|
89
|
+
def self.calculate_number_of_covered_lines(files)
|
90
90
|
return 0 if files.nil? || files.empty?
|
91
91
|
|
92
92
|
files.reduce(0) do |partial_result, file|
|
@@ -94,7 +94,7 @@ module Xcov
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
def self.calculate_number_of_executable_lines
|
97
|
+
def self.calculate_number_of_executable_lines(files)
|
98
98
|
return 0 if files.nil? || files.empty?
|
99
99
|
|
100
100
|
files.reduce(0) do |partial_result, file|
|
data/lib/xcov/options.rb
CHANGED
@@ -7,131 +7,198 @@ module Xcov
|
|
7
7
|
def self.available_options
|
8
8
|
containing = FastlaneCore::Helper.fastlane_enabled? ? './fastlane' : '.'
|
9
9
|
|
10
|
-
[
|
11
|
-
FastlaneCore::ConfigItem.new(key: :workspace,
|
12
|
-
short_option: "-w",
|
13
|
-
env_name: "XCOV_WORKSPACE",
|
14
|
-
optional: true,
|
15
|
-
description: "Path the workspace file",
|
16
|
-
verify_block: proc do |value|
|
17
|
-
v = File.expand_path(value.to_s)
|
18
|
-
raise "Workspace file not found at path '#{v}'".red unless File.exist?(v)
|
19
|
-
raise "Workspace file invalid".red unless File.directory?(v)
|
20
|
-
raise "Workspace file is not a workspace, must end with .xcworkspace".red unless v.include?(".xcworkspace")
|
21
|
-
end),
|
22
|
-
FastlaneCore::ConfigItem.new(key: :project,
|
23
|
-
short_option: "-p",
|
24
|
-
optional: true,
|
25
|
-
env_name: "XCOV_PROJECT",
|
26
|
-
description: "Path the project file",
|
27
|
-
verify_block: proc do |value|
|
28
|
-
v = File.expand_path(value.to_s)
|
29
|
-
raise "Project file not found at path '#{v}'".red unless File.exist?(v)
|
30
|
-
raise "Project file invalid".red unless File.directory?(v)
|
31
|
-
raise "Project file is not a project file, must end with .xcodeproj".red unless v.include?(".xcodeproj")
|
32
|
-
end),
|
33
|
-
FastlaneCore::ConfigItem.new(key: :scheme,
|
34
|
-
short_option: "-s",
|
35
|
-
optional: true,
|
36
|
-
env_name: "XCOV_SCHEME",
|
37
|
-
description: "The project's scheme. Make sure it's marked as `Shared`"),
|
38
|
-
FastlaneCore::ConfigItem.new(key: :configuration,
|
39
|
-
short_option: "-q",
|
40
|
-
env_name: "XCOV_CONFIGURATION",
|
41
|
-
description: "The configuration used when building the app. Defaults to 'Release'",
|
42
|
-
optional: true),
|
43
|
-
FastlaneCore::ConfigItem.new(key: :source_directory,
|
44
|
-
short_option: "-r",
|
45
|
-
optional: true,
|
46
|
-
env_name: "XCOV_SOURCE_DIRECTORY",
|
47
|
-
description: "The path to project's root directory",
|
48
|
-
verify_block: proc do |value|
|
49
|
-
v = File.expand_path(value.to_s)
|
50
|
-
raise "Specified source directory does not exist".red unless File.exist?(v)
|
51
|
-
raise "Invalid source directory path, it must point to a directory".red unless File.directory?(v)
|
52
|
-
end
|
53
|
-
),
|
54
|
-
FastlaneCore::ConfigItem.new(key: :derived_data_path,
|
55
|
-
short_option: "-j",
|
56
|
-
env_name: "XCOV_DERIVED_DATA_PATH",
|
57
|
-
description: "The directory where build products and other derived data will go",
|
58
|
-
optional: true,
|
59
|
-
verify_block: proc do |value|
|
60
|
-
v = File.expand_path(value.to_s)
|
61
|
-
raise "Specified derived data directory does not exist".red unless File.exist?(v)
|
62
|
-
raise "Invalid derived data path, it must point to a directory".red unless File.directory?(v)
|
63
|
-
end),
|
64
|
-
FastlaneCore::ConfigItem.new(key: :output_directory,
|
65
|
-
short_option: "-o",
|
66
|
-
env_name: "XCOV_OUTPUT_DIRECTORY",
|
67
|
-
description: "The directory in which all reports will be stored",
|
68
|
-
default_value: File.join(containing, "xcov_report")),
|
69
|
-
FastlaneCore::ConfigItem.new(key: :html_report,
|
70
|
-
env_name: "XCOV_HTML_REPORT",
|
71
|
-
description: "Produce an HTML report",
|
72
|
-
optional: true,
|
73
|
-
is_string: false,
|
74
|
-
default_value: true),
|
75
|
-
FastlaneCore::ConfigItem.new(key: :markdown_report,
|
76
|
-
env_name: "XCOV_MARKDOWN_REPORT",
|
77
|
-
description: "Produce a Markdown report",
|
78
|
-
optional: true,
|
79
|
-
is_string: false,
|
80
|
-
default_value: false),
|
81
|
-
FastlaneCore::ConfigItem.new(key: :json_report,
|
82
|
-
env_name: "XCOV_JSON_REPORT",
|
83
|
-
description: "Produce a JSON report",
|
84
|
-
optional: true,
|
85
|
-
is_string: false,
|
86
|
-
default_value: false),
|
87
|
-
FastlaneCore::ConfigItem.new(key: :minimum_coverage_percentage,
|
88
|
-
short_option: "-m",
|
89
|
-
env_name: "XCOV_MINIMUM_COVERAGE_PERCENTAGE",
|
90
|
-
description: "Raise exception if overall coverage percentage is under this value (ie. 75)",
|
91
|
-
type: Float,
|
92
|
-
default_value: 0),
|
93
|
-
FastlaneCore::ConfigItem.new(key: :ignore_file_path,
|
94
|
-
short_option: "-x",
|
95
|
-
env_name: "XCOV_IGNORE_FILE_PATH",
|
96
|
-
description: "Relative or absolute path to the file containing the list of ignored files",
|
97
|
-
default_value: File.join(containing, ".xcovignore")),
|
98
|
-
FastlaneCore::ConfigItem.new(key: :include_test_targets,
|
99
|
-
env_name: "XCOV_INCLUDE_TEST_TARGETS",
|
100
|
-
description: "Enables coverage reports for .xctest targets",
|
101
|
-
is_string: false,
|
102
|
-
default_value: false),
|
103
|
-
FastlaneCore::ConfigItem.new(key: :slack_url,
|
104
|
-
short_option: "-i",
|
105
|
-
env_name: "SLACK_URL",
|
106
|
-
description: "Create an Incoming WebHook for your Slack group to post results there",
|
107
|
-
optional: true,
|
108
|
-
verify_block: proc do |value|
|
109
|
-
raise "Invalid URL, must start with https://" unless value.start_with? "https://"
|
110
|
-
end),
|
111
|
-
FastlaneCore::ConfigItem.new(key: :slack_channel,
|
112
|
-
short_option: "-e",
|
113
|
-
env_name: "XCOV_SLACK_CHANNEL",
|
114
|
-
description: "#channel or @username",
|
115
|
-
optional: true),
|
116
|
-
FastlaneCore::ConfigItem.new(key: :skip_slack,
|
117
|
-
description: "Don't publish to slack, even when an URL is given",
|
118
|
-
is_string: false,
|
119
|
-
default_value: false),
|
120
|
-
FastlaneCore::ConfigItem.new(key: :exclude_targets,
|
121
|
-
optional: true,
|
122
|
-
conflicting_options: [:include_targets, :only_project_targets],
|
123
|
-
description: "Comma separated list of targets to exclude from coverage report"),
|
124
|
-
FastlaneCore::ConfigItem.new(key: :include_targets,
|
125
|
-
optional: true,
|
126
|
-
conflicting_options: [:exclude_targets, :only_project_targets],
|
127
|
-
description: "Comma separated list of targets to include in coverage report. If specified then exlude_targets will be ignored"),
|
128
|
-
FastlaneCore::ConfigItem.new(key: :only_project_targets,
|
129
|
-
optional: true,
|
130
|
-
conflicting_options: [:exclude_targets, :include_targets],
|
131
|
-
description: "Display the coverage only for main project targets (e.g. skip Pods targets)",
|
132
|
-
is_string: false,
|
133
|
-
default_value: false)
|
10
|
+
return [
|
134
11
|
|
12
|
+
# Project options
|
13
|
+
FastlaneCore::ConfigItem.new(
|
14
|
+
key: :workspace,
|
15
|
+
short_option: "-w",
|
16
|
+
env_name: "XCOV_WORKSPACE",
|
17
|
+
optional: true,
|
18
|
+
description: "Path the workspace file",
|
19
|
+
verify_block: proc do |value|
|
20
|
+
v = File.expand_path(value.to_s)
|
21
|
+
raise "Workspace file not found at path '#{v}'".red unless File.exist?(v)
|
22
|
+
raise "Workspace file invalid".red unless File.directory?(v)
|
23
|
+
raise "Workspace file is not a workspace, must end with .xcworkspace".red unless v.include?(".xcworkspace")
|
24
|
+
end
|
25
|
+
),
|
26
|
+
FastlaneCore::ConfigItem.new(
|
27
|
+
key: :project,
|
28
|
+
short_option: "-p",
|
29
|
+
optional: true,
|
30
|
+
env_name: "XCOV_PROJECT",
|
31
|
+
description: "Path the project file",
|
32
|
+
verify_block: proc do |value|
|
33
|
+
v = File.expand_path(value.to_s)
|
34
|
+
raise "Project file not found at path '#{v}'".red unless File.exist?(v)
|
35
|
+
raise "Project file invalid".red unless File.directory?(v)
|
36
|
+
raise "Project file is not a project file, must end with .xcodeproj".red unless v.include?(".xcodeproj")
|
37
|
+
end
|
38
|
+
),
|
39
|
+
FastlaneCore::ConfigItem.new(
|
40
|
+
key: :scheme,
|
41
|
+
short_option: "-s",
|
42
|
+
optional: true,
|
43
|
+
env_name: "XCOV_SCHEME",
|
44
|
+
description: "The project's scheme. Make sure it's marked as `Shared`"
|
45
|
+
),
|
46
|
+
FastlaneCore::ConfigItem.new(
|
47
|
+
key: :configuration,
|
48
|
+
short_option: "-q",
|
49
|
+
env_name: "XCOV_CONFIGURATION",
|
50
|
+
description: "The configuration used when building the app. Defaults to 'Release'",
|
51
|
+
optional: true
|
52
|
+
),
|
53
|
+
FastlaneCore::ConfigItem.new(
|
54
|
+
key: :source_directory,
|
55
|
+
short_option: "-r",
|
56
|
+
optional: true,
|
57
|
+
env_name: "XCOV_SOURCE_DIRECTORY",
|
58
|
+
description: "The path to project's root directory",
|
59
|
+
verify_block: proc do |value|
|
60
|
+
v = File.expand_path(value.to_s)
|
61
|
+
raise "Specified source directory does not exist".red unless File.exist?(v)
|
62
|
+
raise "Invalid source directory path, it must point to a directory".red unless File.directory?(v)
|
63
|
+
end
|
64
|
+
),
|
65
|
+
FastlaneCore::ConfigItem.new(
|
66
|
+
key: :derived_data_path,
|
67
|
+
short_option: "-j",
|
68
|
+
env_name: "XCOV_DERIVED_DATA_PATH",
|
69
|
+
description: "The directory where build products and other derived data will go",
|
70
|
+
optional: true,
|
71
|
+
verify_block: proc do |value|
|
72
|
+
v = File.expand_path(value.to_s)
|
73
|
+
raise "Specified derived data directory does not exist".red unless File.exist?(v)
|
74
|
+
raise "Invalid derived data path, it must point to a directory".red unless File.directory?(v)
|
75
|
+
end
|
76
|
+
),
|
77
|
+
FastlaneCore::ConfigItem.new(
|
78
|
+
key: :output_directory,
|
79
|
+
short_option: "-o",
|
80
|
+
env_name: "XCOV_OUTPUT_DIRECTORY",
|
81
|
+
description: "The directory in which all reports will be stored",
|
82
|
+
default_value: File.join(containing, "xcov_report")
|
83
|
+
),
|
84
|
+
|
85
|
+
# Report options
|
86
|
+
FastlaneCore::ConfigItem.new(
|
87
|
+
key: :html_report,
|
88
|
+
env_name: "XCOV_HTML_REPORT",
|
89
|
+
description: "Produce an HTML report",
|
90
|
+
optional: true,
|
91
|
+
is_string: false,
|
92
|
+
default_value: true
|
93
|
+
),
|
94
|
+
FastlaneCore::ConfigItem.new(
|
95
|
+
key: :markdown_report,
|
96
|
+
env_name: "XCOV_MARKDOWN_REPORT",
|
97
|
+
description: "Produce a Markdown report",
|
98
|
+
optional: true,
|
99
|
+
is_string: false,
|
100
|
+
default_value: false
|
101
|
+
),
|
102
|
+
FastlaneCore::ConfigItem.new(
|
103
|
+
key: :json_report,
|
104
|
+
env_name: "XCOV_JSON_REPORT",
|
105
|
+
description: "Produce a JSON report",
|
106
|
+
optional: true,
|
107
|
+
is_string: false,
|
108
|
+
default_value: false
|
109
|
+
),
|
110
|
+
FastlaneCore::ConfigItem.new(
|
111
|
+
key: :minimum_coverage_percentage,
|
112
|
+
short_option: "-m",
|
113
|
+
env_name: "XCOV_MINIMUM_COVERAGE_PERCENTAGE",
|
114
|
+
description: "Raise exception if overall coverage percentage is under this value (ie. 75)",
|
115
|
+
type: Float,
|
116
|
+
default_value: 0
|
117
|
+
),
|
118
|
+
|
119
|
+
# Slack options
|
120
|
+
FastlaneCore::ConfigItem.new(
|
121
|
+
key: :slack_url,
|
122
|
+
short_option: "-i",
|
123
|
+
env_name: "SLACK_URL",
|
124
|
+
description: "Create an Incoming WebHook for your Slack group to post results there",
|
125
|
+
optional: true,
|
126
|
+
verify_block: proc do |value|
|
127
|
+
raise "Invalid URL, must start with https://" unless value.start_with? "https://"
|
128
|
+
end
|
129
|
+
),
|
130
|
+
FastlaneCore::ConfigItem.new(
|
131
|
+
key: :slack_channel,
|
132
|
+
short_option: "-e",
|
133
|
+
env_name: "XCOV_SLACK_CHANNEL",
|
134
|
+
description: "#channel or @username",
|
135
|
+
optional: true
|
136
|
+
),
|
137
|
+
FastlaneCore::ConfigItem.new(
|
138
|
+
key: :skip_slack,
|
139
|
+
description: "Don't publish to slack, even when an URL is given",
|
140
|
+
is_string: false,
|
141
|
+
default_value: false
|
142
|
+
),
|
143
|
+
|
144
|
+
# Exclusion options
|
145
|
+
FastlaneCore::ConfigItem.new(
|
146
|
+
key: :ignore_file_path,
|
147
|
+
short_option: "-x",
|
148
|
+
env_name: "XCOV_IGNORE_FILE_PATH",
|
149
|
+
description: "Relative or absolute path to the file containing the list of ignored files",
|
150
|
+
default_value: File.join(containing, ".xcovignore")
|
151
|
+
),
|
152
|
+
FastlaneCore::ConfigItem.new(
|
153
|
+
key: :include_test_targets,
|
154
|
+
env_name: "XCOV_INCLUDE_TEST_TARGETS",
|
155
|
+
description: "Enables coverage reports for .xctest targets",
|
156
|
+
is_string: false,
|
157
|
+
default_value: false
|
158
|
+
),
|
159
|
+
FastlaneCore::ConfigItem.new(
|
160
|
+
key: :exclude_targets,
|
161
|
+
optional: true,
|
162
|
+
conflicting_options: [:include_targets, :only_project_targets],
|
163
|
+
description: "Comma separated list of targets to exclude from coverage report"
|
164
|
+
),
|
165
|
+
FastlaneCore::ConfigItem.new(
|
166
|
+
key: :include_targets,
|
167
|
+
optional: true,
|
168
|
+
conflicting_options: [:exclude_targets, :only_project_targets],
|
169
|
+
description: "Comma separated list of targets to include in coverage report. If specified then exlude_targets will be ignored"
|
170
|
+
),
|
171
|
+
FastlaneCore::ConfigItem.new(
|
172
|
+
key: :only_project_targets,
|
173
|
+
optional: true,
|
174
|
+
conflicting_options: [:exclude_targets, :include_targets],
|
175
|
+
description: "Display the coverage only for main project targets (e.g. skip Pods targets)",
|
176
|
+
is_string: false,
|
177
|
+
default_value: false
|
178
|
+
),
|
179
|
+
|
180
|
+
# Coveralls options
|
181
|
+
FastlaneCore::ConfigItem.new(
|
182
|
+
key: :coveralls_service_name,
|
183
|
+
env_name: "COVERALLS_SERVICE_NAME",
|
184
|
+
optional: true,
|
185
|
+
conflicting_options: [:coveralls_repo_token],
|
186
|
+
description: "Name of the CI service compatible with Coveralls. i.e. travis-ci. This option must be defined along with coveralls_service_job_id"
|
187
|
+
),
|
188
|
+
FastlaneCore::ConfigItem.new(
|
189
|
+
key: :coveralls_service_job_id,
|
190
|
+
env_name: "COVERALLS_SERVICE_JOB_ID",
|
191
|
+
optional: true,
|
192
|
+
conflicting_options: [:coveralls_repo_token],
|
193
|
+
description: "Name of the current job running on a CI service compatible with Coveralls. This option must be defined along with coveralls_service_name"
|
194
|
+
),
|
195
|
+
FastlaneCore::ConfigItem.new(
|
196
|
+
key: :coveralls_repo_token,
|
197
|
+
env_name: "COVERALLS_REPO_TOKEN",
|
198
|
+
optional: true,
|
199
|
+
conflicting_options: [:coveralls_service_name, :coveralls_service_job_id],
|
200
|
+
description: "Repository token to be used by integrations not compatible with Coveralls"
|
201
|
+
)
|
135
202
|
]
|
136
203
|
end
|
137
204
|
|
@@ -10,14 +10,14 @@ module FastlaneCore
|
|
10
10
|
return [] if project_path.nil?
|
11
11
|
|
12
12
|
proj = Xcodeproj::Project.open(project_path)
|
13
|
-
|
13
|
+
|
14
14
|
proj.targets.map do |target|
|
15
15
|
target.name
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
20
|
-
|
20
|
+
|
21
21
|
def get_project_path
|
22
22
|
# Given the workspace and scheme, we can compute project path
|
23
23
|
if workspace?
|
data/lib/xcov/slack_poster.rb
CHANGED
@@ -25,9 +25,11 @@ module Xcov
|
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
|
-
result = notifier.ping
|
29
|
-
|
30
|
-
|
28
|
+
result = notifier.ping(
|
29
|
+
"Your *xcov* coverage report",
|
30
|
+
icon_url: 'https://s3-eu-west-1.amazonaws.com/fastlane.tools/fastlane.png',
|
31
|
+
attachments: attachments
|
32
|
+
)
|
31
33
|
|
32
34
|
if result.code.to_i == 200
|
33
35
|
UI.message 'Successfully sent Slack notification'.green
|
data/lib/xcov/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xcov
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Vidal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastlane
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: multipart-post
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
90
|
name: bundler
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,6 +226,7 @@ files:
|
|
212
226
|
- lib/xcov-core/version.rb
|
213
227
|
- lib/xcov.rb
|
214
228
|
- lib/xcov/commands_generator.rb
|
229
|
+
- lib/xcov/coveralls_handler.rb
|
215
230
|
- lib/xcov/error_handler.rb
|
216
231
|
- lib/xcov/ignore_handler.rb
|
217
232
|
- lib/xcov/manager.rb
|
@@ -224,7 +239,6 @@ files:
|
|
224
239
|
- lib/xcov/model/target.rb
|
225
240
|
- lib/xcov/options.rb
|
226
241
|
- lib/xcov/project_extensions.rb
|
227
|
-
- lib/xcov/runner.rb
|
228
242
|
- lib/xcov/slack_poster.rb
|
229
243
|
- lib/xcov/version.rb
|
230
244
|
- views/file.erb
|
data/lib/xcov/runner.rb
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'pty'
|
2
|
-
require 'open3'
|
3
|
-
require 'fileutils'
|
4
|
-
require 'terminal-table'
|
5
|
-
require 'xcov-core'
|
6
|
-
require 'pathname'
|
7
|
-
require 'json'
|
8
|
-
|
9
|
-
module Xcov
|
10
|
-
class Runner
|
11
|
-
|
12
|
-
def run
|
13
|
-
report_json = parse_xccoverage
|
14
|
-
report = generate_xcov_report(report_json)
|
15
|
-
validate_report(report)
|
16
|
-
end
|
17
|
-
|
18
|
-
def parse_xccoverage
|
19
|
-
# Find .xccoverage file
|
20
|
-
test_logs_path = derived_data_path + "Logs/Test/"
|
21
|
-
xccoverage_files = Dir["#{test_logs_path}*.xccoverage"].sort_by { |filename| File.mtime(filename) }.reverse
|
22
|
-
|
23
|
-
unless test_logs_path.directory? && !xccoverage_files.empty?
|
24
|
-
ErrorHandler.handle_error("CoverageNotFound")
|
25
|
-
end
|
26
|
-
|
27
|
-
Xcov::Core::Parser.parse(xccoverage_files.first)
|
28
|
-
end
|
29
|
-
|
30
|
-
def generate_xcov_report report_json
|
31
|
-
# Create output path
|
32
|
-
output_path = Xcov.config[:output_directory]
|
33
|
-
FileUtils.mkdir_p(output_path)
|
34
|
-
|
35
|
-
# Convert report to xCov model objects
|
36
|
-
report = Report.map(report_json)
|
37
|
-
|
38
|
-
if Xcov.config[:html_report] then
|
39
|
-
resources_path = File.join(output_path, "resources")
|
40
|
-
FileUtils.mkdir_p(resources_path)
|
41
|
-
|
42
|
-
# Copy images to output resources folder
|
43
|
-
Dir[File.join(File.dirname(__FILE__), "../../assets/images/*")].each do |path|
|
44
|
-
FileUtils.cp_r(path, resources_path)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Copy stylesheets to output resources folder
|
48
|
-
Dir[File.join(File.dirname(__FILE__), "../../assets/stylesheets/*")].each do |path|
|
49
|
-
FileUtils.cp_r(path, resources_path)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Copy javascripts to output resources folder
|
53
|
-
Dir[File.join(File.dirname(__FILE__), "../../assets/javascripts/*")].each do |path|
|
54
|
-
FileUtils.cp_r(path, resources_path)
|
55
|
-
end
|
56
|
-
|
57
|
-
# Create HTML report
|
58
|
-
File.open(File.join(output_path, "index.html"), "wb") do |file|
|
59
|
-
file.puts report.html_value
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Create Markdown report
|
64
|
-
if Xcov.config[:markdown_report] then
|
65
|
-
File.open(File.join(output_path, "report.md"), "wb") do |file|
|
66
|
-
file.puts report.markdown_value
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Create JSON report
|
71
|
-
if Xcov.config[:json_report] then
|
72
|
-
File.open(File.join(output_path, "report.json"), "wb") do |file|
|
73
|
-
file.puts report.json_value.to_json
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Post result
|
78
|
-
SlackPoster.new.run(report)
|
79
|
-
|
80
|
-
# Print output
|
81
|
-
table_rows = []
|
82
|
-
report.targets.each do |target|
|
83
|
-
table_rows << [target.name, target.displayable_coverage]
|
84
|
-
end
|
85
|
-
puts Terminal::Table.new({
|
86
|
-
title: "xcov Coverage Report".green,
|
87
|
-
rows: table_rows
|
88
|
-
})
|
89
|
-
puts ""
|
90
|
-
|
91
|
-
# Raise exception in case of failure
|
92
|
-
raise "Unable to create coverage report" if report.nil?
|
93
|
-
|
94
|
-
report
|
95
|
-
end
|
96
|
-
|
97
|
-
def validate_report report
|
98
|
-
exit_status = 0
|
99
|
-
|
100
|
-
# Raise exception if overall coverage
|
101
|
-
minimumPercentage = Xcov.config[:minimum_coverage_percentage] / 100
|
102
|
-
if minimumPercentage > report.coverage
|
103
|
-
exit_status = 1
|
104
|
-
|
105
|
-
UI.user_error!("Actual Code Coverage (#{"%.2f%" % (report.coverage*100)}) below threshold of #{"%.2f%" % (minimumPercentage*100)}")
|
106
|
-
end
|
107
|
-
|
108
|
-
exit_status
|
109
|
-
end
|
110
|
-
|
111
|
-
# Auxiliar methods
|
112
|
-
|
113
|
-
def derived_data_path
|
114
|
-
# If DerivedData path was supplied, return
|
115
|
-
return Pathname.new(Xcov.config[:derived_data_path]) unless Xcov.config[:derived_data_path].nil?
|
116
|
-
|
117
|
-
# Otherwise check project file
|
118
|
-
product_builds_path = Pathname.new(Xcov.project.default_build_settings(key: "SYMROOT"))
|
119
|
-
return product_builds_path.parent.parent
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
end
|