fastlane-plugin-xccov 0.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +206 -0
- data/lib/fastlane/plugin/xccov/actions/xccov_action.rb +64 -0
- data/lib/fastlane/plugin/xccov/actions/xccov_diff_action.rb +100 -0
- data/lib/fastlane/plugin/xccov/actions/xccov_merge_action.rb +103 -0
- data/lib/fastlane/plugin/xccov/actions/xccov_view_action.rb +146 -0
- data/lib/fastlane/plugin/xccov/helper/xccov_helper.rb +32 -0
- data/lib/fastlane/plugin/xccov/version.rb +5 -0
- data/lib/fastlane/plugin/xccov.rb +16 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 412fbf91781da61f5772cbc4d3968df23fbd0ce06500e95c89e74e22fa8eb2f4
|
4
|
+
data.tar.gz: 3d4e2832af54b56ead2dce3ae1515cc3a786f71bdd9f480b86c3fb1fe90b80a3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cab98982bf7e5f69720f4f7b87efbede989f9b0a4aed56a0661cfd5649786c5b261fb8c9bf385b7f18c5bd350a1b065e158f8e86c2cff23f0c1af5b4658d4566
|
7
|
+
data.tar.gz: 2c69a18ff3b0e1c42ee1b3a0945824458cd727a85c2af31ac5abc6a42c9a6e695787cbab912b4fec85cce3f9a495dd9d77bfcd7d12922e888b05f303a2ab25f1
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 Manish Rathi <i.am.manish.rathi@gmail.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
# xccov plugin
|
2
|
+
|
3
|
+
[](https://rubygems.org/gems/fastlane-plugin-xccov)
|
4
|
+
|
5
|
+
## Getting Started
|
6
|
+
|
7
|
+
This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-xccov`, add it to your project by running:
|
8
|
+
|
9
|
+
```bash
|
10
|
+
fastlane add_plugin xccov
|
11
|
+
```
|
12
|
+
|
13
|
+
## About xccov
|
14
|
+
|
15
|
+
A fastlane plugin that provides integration with Apple's `xccov` command-line tool for code coverage analysis. This plugin allows you to easily view, compare, and merge code coverage reports from your iOS and macOS test runs directly in your fastlane workflows.
|
16
|
+
|
17
|
+
The plugin supports all major xccov commands:
|
18
|
+
- **view**: Examine code coverage data from .xccovarchive, .xccovreport, or .xcresult files
|
19
|
+
- **diff**: Compare code coverage between two reports
|
20
|
+
- **merge**: Combine multiple coverage reports into a single report
|
21
|
+
|
22
|
+
## Actions
|
23
|
+
|
24
|
+
### xccov_view
|
25
|
+
|
26
|
+
View code coverage data from .xccovarchive, .xccovreport, or .xcresult files.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
# View code coverage data from an xcresult bundle
|
30
|
+
xccov_view(
|
31
|
+
file_path: "test_result.xcresult",
|
32
|
+
json: true
|
33
|
+
)
|
34
|
+
|
35
|
+
# View files for a specific target
|
36
|
+
xccov_view(
|
37
|
+
file_path: "test_result.xcresult",
|
38
|
+
report: true,
|
39
|
+
files_for_target: "MyAppTarget",
|
40
|
+
json: true
|
41
|
+
)
|
42
|
+
|
43
|
+
# View only the targets from a coverage report
|
44
|
+
xccov_view(
|
45
|
+
file_path: "coverage.xccovreport",
|
46
|
+
only_targets: true
|
47
|
+
)
|
48
|
+
|
49
|
+
# List files in an xccovarchive
|
50
|
+
xccov_view(
|
51
|
+
file_path: "coverage.xccovarchive",
|
52
|
+
file_list: true
|
53
|
+
)
|
54
|
+
|
55
|
+
# View coverage for a specific file
|
56
|
+
xccov_view(
|
57
|
+
file_path: "coverage.xccovarchive",
|
58
|
+
file: "MyApp/MyClass.swift"
|
59
|
+
)
|
60
|
+
|
61
|
+
# View functions for a specific file
|
62
|
+
xccov_view(
|
63
|
+
file_path: "coverage.xccovreport",
|
64
|
+
functions_for_file: "MyApp/MyClass.swift"
|
65
|
+
)
|
66
|
+
```
|
67
|
+
|
68
|
+
### xccov_diff
|
69
|
+
|
70
|
+
Compare code coverage between two .xccovreport or .xcresult files.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# Compare coverage between two xccovreport files
|
74
|
+
xccov_diff(
|
75
|
+
before_path: "before.xccovreport",
|
76
|
+
after_path: "after.xccovreport",
|
77
|
+
json: true
|
78
|
+
)
|
79
|
+
|
80
|
+
# Compare coverage between two xcresult bundles
|
81
|
+
xccov_diff(
|
82
|
+
before_path: "before.xcresult",
|
83
|
+
after_path: "after.xcresult",
|
84
|
+
json: true
|
85
|
+
)
|
86
|
+
|
87
|
+
# Compare coverage with path equivalence for files that moved
|
88
|
+
xccov_diff(
|
89
|
+
before_path: "before.xcresult",
|
90
|
+
after_path: "after.xcresult",
|
91
|
+
path_equivalence: "/OldPath,/NewPath",
|
92
|
+
json: true
|
93
|
+
)
|
94
|
+
```
|
95
|
+
|
96
|
+
### xccov_merge
|
97
|
+
|
98
|
+
Merge multiple .xccovreport and (optionally) .xccovarchive files into a single coverage report.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
# Merge multiple xccovreport files
|
102
|
+
xccov_merge(
|
103
|
+
reports: ["report1.xccovreport", "report2.xccovreport"],
|
104
|
+
out_report: "merged.xccovreport"
|
105
|
+
)
|
106
|
+
|
107
|
+
# Merge multiple xccovreport files with their corresponding archives
|
108
|
+
xccov_merge(
|
109
|
+
reports: ["report1.xccovreport", "report2.xccovreport"],
|
110
|
+
archives: ["archive1.xccovarchive", "archive2.xccovarchive"],
|
111
|
+
out_report: "merged.xccovreport",
|
112
|
+
out_archive: "merged.xccovarchive"
|
113
|
+
)
|
114
|
+
```
|
115
|
+
|
116
|
+
### Wrapper Action
|
117
|
+
|
118
|
+
You can also use the main `xccov` action as a wrapper that delegates to the specific command actions:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
# Using the wrapper action for view
|
122
|
+
xccov(
|
123
|
+
command: :view,
|
124
|
+
file_path: "coverage.xcresult",
|
125
|
+
json: true
|
126
|
+
)
|
127
|
+
|
128
|
+
# Using the wrapper action for diff
|
129
|
+
xccov(
|
130
|
+
command: :diff,
|
131
|
+
before_path: "before.xcresult",
|
132
|
+
after_path: "after.xcresult",
|
133
|
+
json: true
|
134
|
+
)
|
135
|
+
|
136
|
+
# Using the wrapper action for merge
|
137
|
+
xccov(
|
138
|
+
command: :merge,
|
139
|
+
reports: ["report1.xccovreport", "report2.xccovreport"],
|
140
|
+
out_report: "merged.xccovreport"
|
141
|
+
)
|
142
|
+
```
|
143
|
+
|
144
|
+
## Example Fastfile
|
145
|
+
|
146
|
+
Here's an example of how you might integrate xccov into your fastlane workflow:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
lane :analyze_coverage do
|
150
|
+
# Run tests and generate coverage report
|
151
|
+
scan(
|
152
|
+
scheme: "MyApp",
|
153
|
+
code_coverage: true,
|
154
|
+
derived_data_path: "./DerivedData",
|
155
|
+
result_bundle: true
|
156
|
+
)
|
157
|
+
|
158
|
+
# Get the path to the latest test result
|
159
|
+
xcresult_path = Dir["./DerivedData/Logs/Test/Run-*.xcresult"].sort_by { |f| File.mtime(f) }.last
|
160
|
+
|
161
|
+
# View coverage summary
|
162
|
+
coverage_data = xccov_view(
|
163
|
+
file_path: xcresult_path,
|
164
|
+
report: true,
|
165
|
+
only_targets: true,
|
166
|
+
json: true
|
167
|
+
)
|
168
|
+
|
169
|
+
# Parse the coverage data and fail if below threshold
|
170
|
+
total_coverage = coverage_data.first["lineCoverage"]
|
171
|
+
UI.message "Total coverage: #{(total_coverage * 100).round(2)}%"
|
172
|
+
|
173
|
+
if total_coverage < 0.7 # 70% threshold
|
174
|
+
UI.user_error!("Code coverage is below the required threshold of 70%")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
## Run tests for this plugin
|
180
|
+
|
181
|
+
To run both the tests, and code style validation, run
|
182
|
+
|
183
|
+
```
|
184
|
+
rake
|
185
|
+
```
|
186
|
+
|
187
|
+
To automatically fix many of the styling issues, use
|
188
|
+
```
|
189
|
+
rubocop -a
|
190
|
+
```
|
191
|
+
|
192
|
+
## Issues and Feedback
|
193
|
+
|
194
|
+
For any other issues and feedback about this plugin, please submit it to this repository.
|
195
|
+
|
196
|
+
## Troubleshooting
|
197
|
+
|
198
|
+
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
|
199
|
+
|
200
|
+
## Using _fastlane_ Plugins
|
201
|
+
|
202
|
+
For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
|
203
|
+
|
204
|
+
## About _fastlane_
|
205
|
+
|
206
|
+
_fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/xccov_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class XccovAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
UI.user_error!("No command specified. Use :view, :diff, or :merge") unless params[:command]
|
9
|
+
|
10
|
+
case params[:command]
|
11
|
+
when :view
|
12
|
+
return other_action.xccov_view(params.except(:command))
|
13
|
+
when :diff
|
14
|
+
return other_action.xccov_diff(params.except(:command))
|
15
|
+
when :merge
|
16
|
+
return other_action.xccov_merge(params.except(:command))
|
17
|
+
else
|
18
|
+
UI.user_error!("Unknown command: #{params[:command]}. Use :view, :diff, or :merge")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.description
|
23
|
+
"A fastlane plugin for xccov tool that provides code coverage functionality"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.authors
|
27
|
+
["crazymanish"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.return_value
|
31
|
+
"Returns the result of the xccov command execution"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.details
|
35
|
+
"A fastlane plugin for the xccov tool that allows you to view, diff, and merge code coverage reports 🚀"
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.available_options
|
39
|
+
[
|
40
|
+
FastlaneCore::ConfigItem.new(key: :command,
|
41
|
+
env_name: "XCCOV_COMMAND",
|
42
|
+
description: "Which xccov command to run: view, diff, or merge",
|
43
|
+
optional: false,
|
44
|
+
type: Symbol,
|
45
|
+
verify_block: proc do |value|
|
46
|
+
UI.user_error!("Command must be one of: :view, :diff, :merge") unless [:view, :diff, :merge].include?(value)
|
47
|
+
end)
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.is_supported?(platform)
|
52
|
+
[:ios, :mac].include?(platform)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.example_code
|
56
|
+
[
|
57
|
+
'xccov(command: :view, file_path: "coverage.xcresult", json: true)',
|
58
|
+
'xccov(command: :diff, before_path: "before.xcresult", after_path: "after.xcresult", json: true)',
|
59
|
+
'xccov(command: :merge, reports: ["report1.xccovreport", "report2.xccovreport"], archives: ["archive1.xccovarchive", "archive2.xccovarchive"], out_report: "merged.xccovreport")'
|
60
|
+
]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/xccov_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class XccovDiffAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
cmd = ["xcrun", "xccov", "diff"]
|
9
|
+
|
10
|
+
# Add json flag if requested
|
11
|
+
cmd << "--json" if params[:json]
|
12
|
+
|
13
|
+
# Add path equivalence if provided
|
14
|
+
if params[:path_equivalence]
|
15
|
+
from, to = params[:path_equivalence].split(",")
|
16
|
+
cmd << "--path-equivalence" << "#{from},#{to}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add before and after paths
|
20
|
+
cmd << params[:before_path]
|
21
|
+
cmd << params[:after_path]
|
22
|
+
|
23
|
+
# Execute command
|
24
|
+
result = Helper::XccovHelper.run_command(cmd.join(" "))
|
25
|
+
|
26
|
+
# Parse JSON if requested
|
27
|
+
if params[:json] && result
|
28
|
+
require 'json'
|
29
|
+
begin
|
30
|
+
return JSON.parse(result)
|
31
|
+
rescue JSON::ParserError => e
|
32
|
+
UI.error("Failed to parse JSON: #{e.message}")
|
33
|
+
return result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
return result
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.description
|
41
|
+
"Compare code coverage data using Apple's xccov diff command"
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.authors
|
45
|
+
["crazymanish"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.return_value
|
49
|
+
"Returns the output of the xccov diff command (string or parsed JSON)"
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.details
|
53
|
+
"This action allows you to compare code coverage between two .xccovreport or .xcresult files"
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.available_options
|
57
|
+
[
|
58
|
+
FastlaneCore::ConfigItem.new(key: :before_path,
|
59
|
+
env_name: "XCCOV_DIFF_BEFORE_PATH",
|
60
|
+
description: "Path to the 'before' coverage file (.xccovreport or .xcresult)",
|
61
|
+
optional: false,
|
62
|
+
type: String,
|
63
|
+
verify_block: proc do |value|
|
64
|
+
UI.user_error!("File does not exist at path '#{value}'") unless File.exist?(value)
|
65
|
+
end),
|
66
|
+
FastlaneCore::ConfigItem.new(key: :after_path,
|
67
|
+
env_name: "XCCOV_DIFF_AFTER_PATH",
|
68
|
+
description: "Path to the 'after' coverage file (.xccovreport or .xcresult)",
|
69
|
+
optional: false,
|
70
|
+
type: String,
|
71
|
+
verify_block: proc do |value|
|
72
|
+
UI.user_error!("File does not exist at path '#{value}'") unless File.exist?(value)
|
73
|
+
end),
|
74
|
+
FastlaneCore::ConfigItem.new(key: :json,
|
75
|
+
env_name: "XCCOV_DIFF_JSON",
|
76
|
+
description: "Output in JSON format",
|
77
|
+
optional: true,
|
78
|
+
is_string: false,
|
79
|
+
default_value: false),
|
80
|
+
FastlaneCore::ConfigItem.new(key: :path_equivalence,
|
81
|
+
env_name: "XCCOV_DIFF_PATH_EQUIVALENCE",
|
82
|
+
description: "Path equivalence for different file paths in comma-separated format 'from,to'",
|
83
|
+
optional: true,
|
84
|
+
type: String)
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.is_supported?(platform)
|
89
|
+
[:ios, :mac].include?(platform)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.example_code
|
93
|
+
[
|
94
|
+
'xccov_diff(before_path: "before.xccovreport", after_path: "after.xccovreport", json: true)',
|
95
|
+
'xccov_diff(before_path: "before.xcresult", after_path: "after.xcresult", json: true, path_equivalence: "/OldPath,/NewPath")'
|
96
|
+
]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/xccov_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class XccovMergeAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
cmd = ["xcrun", "xccov", "merge"]
|
9
|
+
|
10
|
+
# Add output report path if provided
|
11
|
+
cmd << "--outReport" << params[:out_report] if params[:out_report]
|
12
|
+
|
13
|
+
# Add output archive path if provided
|
14
|
+
cmd << "--outArchive" << params[:out_archive] if params[:out_archive]
|
15
|
+
|
16
|
+
# Add all report and archive pairs
|
17
|
+
if params[:reports] && params[:archives]
|
18
|
+
if params[:reports].length != params[:archives].length
|
19
|
+
UI.user_error!("The number of reports and archives must be the same")
|
20
|
+
end
|
21
|
+
|
22
|
+
params[:reports].each_with_index do |report, index|
|
23
|
+
cmd << report
|
24
|
+
cmd << params[:archives][index]
|
25
|
+
end
|
26
|
+
elsif params[:reports]
|
27
|
+
# Just add reports if provided without archives
|
28
|
+
params[:reports].each { |report| cmd << report }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Execute command
|
32
|
+
return Helper::XccovHelper.run_command(cmd.join(" "))
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.description
|
36
|
+
"Merge code coverage data using Apple's xccov merge command"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.authors
|
40
|
+
["crazymanish"]
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.return_value
|
44
|
+
"Returns the output of the xccov merge command"
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.details
|
48
|
+
"This action allows you to merge multiple .xccovreport and .xccovarchive files into a single coverage report"
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.available_options
|
52
|
+
[
|
53
|
+
FastlaneCore::ConfigItem.new(key: :reports,
|
54
|
+
env_name: "XCCOV_MERGE_REPORTS",
|
55
|
+
description: "Paths to the .xccovreport files to merge",
|
56
|
+
optional: false,
|
57
|
+
type: Array,
|
58
|
+
verify_block: proc do |value|
|
59
|
+
value.each do |path|
|
60
|
+
UI.user_error!("Report does not exist at path '#{path}'") unless File.exist?(path)
|
61
|
+
end
|
62
|
+
end),
|
63
|
+
FastlaneCore::ConfigItem.new(key: :archives,
|
64
|
+
env_name: "XCCOV_MERGE_ARCHIVES",
|
65
|
+
description: "Paths to the .xccovarchive files to merge (should match the number of reports)",
|
66
|
+
optional: true,
|
67
|
+
type: Array,
|
68
|
+
verify_block: proc do |value|
|
69
|
+
value.each do |path|
|
70
|
+
UI.user_error!("Archive does not exist at path '#{path}'") unless File.exist?(path)
|
71
|
+
end
|
72
|
+
end),
|
73
|
+
FastlaneCore::ConfigItem.new(key: :out_report,
|
74
|
+
env_name: "XCCOV_MERGE_OUT_REPORT",
|
75
|
+
description: "Path where the merged .xccovreport will be saved",
|
76
|
+
optional: true,
|
77
|
+
type: String),
|
78
|
+
FastlaneCore::ConfigItem.new(key: :out_archive,
|
79
|
+
env_name: "XCCOV_MERGE_OUT_ARCHIVE",
|
80
|
+
description: "Path where the merged .xccovarchive will be saved",
|
81
|
+
optional: true,
|
82
|
+
type: String)
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.is_supported?(platform)
|
87
|
+
[:ios, :mac].include?(platform)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.example_code
|
91
|
+
[
|
92
|
+
'xccov_merge(reports: ["report1.xccovreport", "report2.xccovreport"], out_report: "merged.xccovreport")',
|
93
|
+
'xccov_merge(
|
94
|
+
reports: ["report1.xccovreport", "report2.xccovreport"],
|
95
|
+
archives: ["archive1.xccovarchive", "archive2.xccovarchive"],
|
96
|
+
out_report: "merged.xccovreport",
|
97
|
+
out_archive: "merged.xccovarchive"
|
98
|
+
)'
|
99
|
+
]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require_relative '../helper/xccov_helper'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class XccovViewAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
cmd = ["xcrun", "xccov", "view"]
|
9
|
+
|
10
|
+
# Handle file viewing options
|
11
|
+
if params[:file_list]
|
12
|
+
cmd << "--file-list"
|
13
|
+
elsif params[:file]
|
14
|
+
cmd << "--file" << params[:file]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Handle target viewing options
|
18
|
+
if params[:only_targets]
|
19
|
+
cmd << "--only-targets"
|
20
|
+
elsif params[:files_for_target]
|
21
|
+
cmd << "--files-for-target" << params[:files_for_target]
|
22
|
+
elsif params[:functions_for_file]
|
23
|
+
cmd << "--functions-for-file" << params[:functions_for_file]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Handle result bundle modes
|
27
|
+
if params[:archive]
|
28
|
+
cmd << "--archive"
|
29
|
+
elsif params[:report]
|
30
|
+
cmd << "--report"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Handle JSON output
|
34
|
+
cmd << "--json" if params[:json]
|
35
|
+
|
36
|
+
# Add the file path at the end
|
37
|
+
cmd << params[:file_path]
|
38
|
+
|
39
|
+
# Execute command
|
40
|
+
result = Helper::XccovHelper.run_command(cmd.join(" "))
|
41
|
+
|
42
|
+
# Parse JSON if requested
|
43
|
+
if params[:json] && result
|
44
|
+
require 'json'
|
45
|
+
begin
|
46
|
+
return JSON.parse(result)
|
47
|
+
rescue JSON::ParserError => e
|
48
|
+
UI.error("Failed to parse JSON: #{e.message}")
|
49
|
+
return result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
return result
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.description
|
57
|
+
"View code coverage data using Apple's xccov tool"
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.authors
|
61
|
+
["crazymanish"]
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.return_value
|
65
|
+
"Returns the output of the xccov view command (string or parsed JSON)"
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.details
|
69
|
+
"This action allows you to view code coverage data from .xccovarchive, .xccovreport, or .xcresult files"
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.available_options
|
73
|
+
[
|
74
|
+
FastlaneCore::ConfigItem.new(key: :file_path,
|
75
|
+
env_name: "XCCOV_FILE_PATH",
|
76
|
+
description: "Path to the coverage file (.xccovarchive, .xccovreport, or .xcresult)",
|
77
|
+
optional: false,
|
78
|
+
type: String,
|
79
|
+
verify_block: proc do |value|
|
80
|
+
UI.user_error!("File does not exist at path '#{value}'") unless File.exist?(value)
|
81
|
+
end),
|
82
|
+
FastlaneCore::ConfigItem.new(key: :file_list,
|
83
|
+
env_name: "XCCOV_FILE_LIST",
|
84
|
+
description: "Display list of files",
|
85
|
+
optional: true,
|
86
|
+
is_string: false,
|
87
|
+
default_value: false),
|
88
|
+
FastlaneCore::ConfigItem.new(key: :file,
|
89
|
+
env_name: "XCCOV_FILE",
|
90
|
+
description: "Path to a specific file to view coverage for",
|
91
|
+
optional: true,
|
92
|
+
type: String),
|
93
|
+
FastlaneCore::ConfigItem.new(key: :only_targets,
|
94
|
+
env_name: "XCCOV_ONLY_TARGETS",
|
95
|
+
description: "Display only the targets from the report",
|
96
|
+
optional: true,
|
97
|
+
is_string: false,
|
98
|
+
default_value: false),
|
99
|
+
FastlaneCore::ConfigItem.new(key: :files_for_target,
|
100
|
+
env_name: "XCCOV_FILES_FOR_TARGET",
|
101
|
+
description: "Display the files for a specific target",
|
102
|
+
optional: true,
|
103
|
+
type: String),
|
104
|
+
FastlaneCore::ConfigItem.new(key: :functions_for_file,
|
105
|
+
env_name: "XCCOV_FUNCTIONS_FOR_FILE",
|
106
|
+
description: "Display the functions for a specific file",
|
107
|
+
optional: true,
|
108
|
+
type: String),
|
109
|
+
FastlaneCore::ConfigItem.new(key: :json,
|
110
|
+
env_name: "XCCOV_JSON",
|
111
|
+
description: "Output in JSON format",
|
112
|
+
optional: true,
|
113
|
+
is_string: false,
|
114
|
+
default_value: false),
|
115
|
+
FastlaneCore::ConfigItem.new(key: :archive,
|
116
|
+
env_name: "XCCOV_ARCHIVE",
|
117
|
+
description: "Treat .xcresult as an archive",
|
118
|
+
optional: true,
|
119
|
+
is_string: false,
|
120
|
+
default_value: false),
|
121
|
+
FastlaneCore::ConfigItem.new(key: :report,
|
122
|
+
env_name: "XCCOV_REPORT",
|
123
|
+
description: "Treat .xcresult as a report",
|
124
|
+
optional: true,
|
125
|
+
is_string: false,
|
126
|
+
default_value: false)
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.is_supported?(platform)
|
131
|
+
[:ios, :mac].include?(platform)
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.example_code
|
135
|
+
[
|
136
|
+
'xccov_view(file_path: "coverage.xcresult", json: true)',
|
137
|
+
'xccov_view(file_path: "coverage.xccovarchive", file_list: true)',
|
138
|
+
'xccov_view(file_path: "coverage.xccovreport", only_targets: true)',
|
139
|
+
'xccov_view(file_path: "coverage.xccovarchive", file: "MyApp/MyClass.swift")',
|
140
|
+
'xccov_view(file_path: "coverage.xcresult", archive: true, json: true)',
|
141
|
+
'xccov_view(file_path: "coverage.xcresult", report: true, files_for_target: "MyTarget")'
|
142
|
+
]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
|
6
|
+
|
7
|
+
module Helper
|
8
|
+
class XccovHelper
|
9
|
+
# Executes a shell command and returns the output
|
10
|
+
def self.run_command(command)
|
11
|
+
UI.verbose("Running command: #{command}")
|
12
|
+
|
13
|
+
stdout, stderr, status = Open3.capture3(command)
|
14
|
+
|
15
|
+
if status.success?
|
16
|
+
return stdout.strip
|
17
|
+
else
|
18
|
+
UI.error("Command failed: #{command}")
|
19
|
+
UI.error("Error: #{stderr}")
|
20
|
+
UI.user_error!("Failed to execute xccov command")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# class methods that you define here become available in your action
|
25
|
+
# as `Helper::XccovHelper.your_method`
|
26
|
+
#
|
27
|
+
def self.show_message
|
28
|
+
UI.message("Hello from the xccov plugin helper!")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fastlane/plugin/xccov/version'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Xccov
|
5
|
+
# Return all .rb files inside the "actions" and "helper" directory
|
6
|
+
def self.all_classes
|
7
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# By default we want to import all available actions and helpers
|
13
|
+
# A plugin can contain any number of actions and plugins
|
14
|
+
Fastlane::Xccov.all_classes.each do |current|
|
15
|
+
require current
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fastlane-plugin-xccov
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manish Rathi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: i.am.manish.rathi@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- LICENSE
|
20
|
+
- README.md
|
21
|
+
- lib/fastlane/plugin/xccov.rb
|
22
|
+
- lib/fastlane/plugin/xccov/actions/xccov_action.rb
|
23
|
+
- lib/fastlane/plugin/xccov/actions/xccov_diff_action.rb
|
24
|
+
- lib/fastlane/plugin/xccov/actions/xccov_merge_action.rb
|
25
|
+
- lib/fastlane/plugin/xccov/actions/xccov_view_action.rb
|
26
|
+
- lib/fastlane/plugin/xccov/helper/xccov_helper.rb
|
27
|
+
- lib/fastlane/plugin/xccov/version.rb
|
28
|
+
homepage:
|
29
|
+
licenses:
|
30
|
+
- MIT
|
31
|
+
metadata:
|
32
|
+
rubygems_mfa_required: 'true'
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '2.6'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.4.19
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: A fastlane plugin for xcov.
|
52
|
+
test_files: []
|