xcov 1.0.1 → 1.1.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 +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
|

|
@@ -34,7 +35,7 @@ In order to make *xcov* run you must:
|
|
34
35
|

|
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
|