fastlane-plugin-xcresulttool 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ee69d18cababb1b2c84287da4398ede97454e53dcd475ca3a6881baae3acaf67
4
+ data.tar.gz: fa1eb81b29668ee7e021c3c03f296f0d6a8450b0532d4fddbe07b282b72d50b3
5
+ SHA512:
6
+ metadata.gz: '07249854ad5aafc583a198fdf4507da6716c0540f33d956f973bdb94a1e5daa26fd0164f84f56aa05788a49dfb9fdc60fa93709f7dde55aed0913b144c31e532'
7
+ data.tar.gz: f8bbc21fe1090db04fcda35e3e53ca9d7bf98ea7574fc7f06c4312fd43a2f03009abf18d4073bb03c5f79c9c29a1630bae8f6573537c43382b3951e54cff33f0
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,135 @@
1
+ # xcresulttool plugin
2
+
3
+ [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-xcresulttool)
4
+
5
+ ## Getting Started
6
+
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-xcresulttool`, add it to your project by running:
8
+
9
+ ```bash
10
+ fastlane add_plugin xcresulttool
11
+ ```
12
+
13
+ ## About xcresulttool
14
+
15
+ A fastlane plugin that provides an interface to Apple's `xcrun xcresulttool` command line utility. This plugin allows you to extract, export, merge, compare, and analyze data from Xcode test result bundles (.xcresult) files.
16
+
17
+ The plugin includes dedicated actions for each `xcresulttool` subcommand, making it easy to integrate with your fastlane workflows.
18
+
19
+ ## Actions
20
+
21
+ ### xcresulttool
22
+
23
+ The main action that supports all subcommands. You can use this action with a `subcommand` parameter to access all functionalities.
24
+
25
+ ```ruby
26
+ xcresulttool(
27
+ subcommand: "get",
28
+ result_bundle_path: "path/to/Test.xcresult",
29
+ format: "json",
30
+ type: "action-testSummary"
31
+ )
32
+ ```
33
+
34
+ ### xcresulttool_get
35
+
36
+ Extract content from an .xcresult bundle:
37
+
38
+ ```ruby
39
+ xcresulttool_get(
40
+ result_bundle_path: "path/to/Test.xcresult",
41
+ type: "action-testSummary",
42
+ format: "json",
43
+ output_path: "test_summary.json" # optional
44
+ )
45
+ ```
46
+
47
+ ### xcresulttool_export
48
+
49
+ Export content from an .xcresult bundle:
50
+
51
+ ```ruby
52
+ xcresulttool_export(
53
+ result_bundle_path: "path/to/Test.xcresult",
54
+ output_path: "output.json",
55
+ format: "json"
56
+ )
57
+ ```
58
+
59
+ ### xcresulttool_metadata
60
+
61
+ Get metadata from an .xcresult bundle:
62
+
63
+ ```ruby
64
+ xcresulttool_metadata(
65
+ result_bundle_path: "path/to/Test.xcresult",
66
+ format: "human-readable",
67
+ output_path: "metadata.txt" # optional
68
+ )
69
+ ```
70
+
71
+ ### xcresulttool_merge
72
+
73
+ Merge multiple .xcresult bundles into a single bundle:
74
+
75
+ ```ruby
76
+ xcresulttool_merge(
77
+ source_results: ["path/to/Test1.xcresult", "path/to/Test2.xcresult"],
78
+ output_path: "path/to/MergedResults.xcresult"
79
+ )
80
+ ```
81
+
82
+ ### xcresulttool_compare
83
+
84
+ Compare two .xcresult bundles and report differences:
85
+
86
+ ```ruby
87
+ xcresulttool_compare(
88
+ result_bundle_path: "path/to/Test.xcresult",
89
+ baseline_path: "path/to/Baseline.xcresult",
90
+ format: "human-readable",
91
+ only_changes: true,
92
+ output_path: "comparison_results.txt" # optional
93
+ )
94
+ ```
95
+
96
+ ## Example
97
+
98
+ Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
99
+
100
+ ## Common Use Cases
101
+
102
+ - Extract test summaries to track pass/fail rates over time
103
+ - Export test attachments (screenshots, logs) for debugging
104
+ - Merge test results from parallel test runs
105
+ - Compare test results between different runs or branches
106
+ - Access test metadata for reporting
107
+
108
+ ## Run tests for this plugin
109
+
110
+ To run both the tests, and code style validation, run
111
+
112
+ ```
113
+ rake
114
+ ```
115
+
116
+ To automatically fix many of the styling issues, use
117
+ ```
118
+ rubocop -a
119
+ ```
120
+
121
+ ## Issues and Feedback
122
+
123
+ For any other issues and feedback about this plugin, please submit it to this repository.
124
+
125
+ ## Troubleshooting
126
+
127
+ If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
128
+
129
+ ## Using _fastlane_ Plugins
130
+
131
+ For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
132
+
133
+ ## About _fastlane_
134
+
135
+ _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,239 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/xcresulttool_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class XcresulttoolAction < Action
7
+ def self.run(params)
8
+ subcommand = params[:subcommand]
9
+ args = [subcommand]
10
+
11
+ # Common parameters
12
+ result_bundle_path = params[:result_bundle_path]
13
+ Helper::XcresulttoolHelper.validate_result_bundle_path(result_bundle_path) if result_bundle_path
14
+
15
+ case subcommand
16
+ when "get"
17
+ args << "--path" << params[:result_bundle_path]
18
+ args << "--format" << params[:format] if params[:format]
19
+ args << "--id" << params[:id] if params[:id]
20
+ args << "--output-path" << params[:output_path] if params[:output_path]
21
+ args << "--type" << params[:type] if params[:type]
22
+
23
+ when "export"
24
+ args << "--path" << params[:result_bundle_path]
25
+ args << "--format" << params[:format] if params[:format]
26
+ args << "--output-path" << params[:output_path] if params[:output_path]
27
+ args << "--output-dir" << params[:output_dir] if params[:output_dir]
28
+ args << "--export-items" << params[:export_items].join(" ") if params[:export_items]
29
+
30
+ when "graph"
31
+ UI.important("Warning: 'graph' subcommand is deprecated and will be removed in a future release.")
32
+ UI.important("Consider using 'xcresulttool get test-report' instead.")
33
+ args << "--path" << params[:result_bundle_path]
34
+ args << "--format" << params[:format] if params[:format]
35
+
36
+ when "metadata"
37
+ args << "--path" << params[:result_bundle_path]
38
+ args << "--format" << params[:format] if params[:format]
39
+
40
+ when "formatDescription"
41
+ UI.important("Warning: 'formatDescription' subcommand is deprecated and will be removed in a future release.")
42
+
43
+ when "merge"
44
+ args << "--output-path" << params[:output_path] if params[:output_path]
45
+ args += params[:source_results].map { |path| ["--input-path", path] }.flatten if params[:source_results]
46
+
47
+ when "compare"
48
+ args << "--path" << params[:result_bundle_path]
49
+ args << "--baseline-path" << params[:baseline_path] if params[:baseline_path]
50
+ args << "--format" << params[:format] if params[:format]
51
+ args << "--only-changes" if params[:only_changes]
52
+ args << "--only-new-tests" if params[:only_new_tests]
53
+ args << "--only-deleted-tests" if params[:only_deleted_tests]
54
+ args << "--only-test-status-changes" if params[:only_test_status_changes]
55
+ args << "--only-performance-changes" if params[:only_performance_changes]
56
+
57
+ else
58
+ UI.user_error!("Unsupported subcommand: #{subcommand}. Available subcommands: get, export, graph, metadata, formatDescription, merge, compare")
59
+ end
60
+
61
+ # Additional parameters that could be passed to any subcommand
62
+ args << "--verbose" if params[:verbose]
63
+
64
+ # Execute the command
65
+ result = Helper::XcresulttoolHelper.execute_command(args)
66
+
67
+ if params[:output_path]
68
+ UI.success("Results saved to #{params[:output_path]}")
69
+ else
70
+ return result
71
+ end
72
+ end
73
+
74
+ def self.description
75
+ "A fastlane plugin for xcresulttool"
76
+ end
77
+
78
+ def self.authors
79
+ ["crazymanish"]
80
+ end
81
+
82
+ def self.return_value
83
+ "For most subcommands, returns the output of the xcresulttool command as a string. When an output path is specified, returns nil but saves the output to the specified path."
84
+ end
85
+
86
+ def self.details
87
+ "This plugin provides a fastlane interface to Apple's xcresulttool command line utility, which is used to extract and process data from Xcode's .xcresult bundles. It supports all xcresulttool subcommands: get, export, graph, metadata, formatDescription, merge, and compare."
88
+ end
89
+
90
+ def self.available_options
91
+ [
92
+ FastlaneCore::ConfigItem.new(
93
+ key: :subcommand,
94
+ description: "The xcresulttool subcommand to run (get, export, graph, metadata, formatDescription, merge, compare)",
95
+ verify_block: proc do |value|
96
+ valid_subcommands = ["get", "export", "graph", "metadata", "formatDescription", "merge", "compare"]
97
+ UI.user_error!("Unsupported subcommand: '#{value}'. Available subcommands: #{valid_subcommands.join(", ")}") unless valid_subcommands.include?(value)
98
+ end,
99
+ optional: false,
100
+ type: String
101
+ ),
102
+ FastlaneCore::ConfigItem.new(
103
+ key: :result_bundle_path,
104
+ description: "Path to the .xcresult bundle",
105
+ optional: true,
106
+ type: String
107
+ ),
108
+ FastlaneCore::ConfigItem.new(
109
+ key: :format,
110
+ description: "Output format (json, flat, human-readable)",
111
+ optional: true,
112
+ type: String
113
+ ),
114
+ FastlaneCore::ConfigItem.new(
115
+ key: :id,
116
+ description: "ID for the get subcommand",
117
+ optional: true,
118
+ type: String
119
+ ),
120
+ FastlaneCore::ConfigItem.new(
121
+ key: :type,
122
+ description: "Content type for the get subcommand (e.g., 'action-testSummary', 'test-report')",
123
+ optional: true,
124
+ type: String
125
+ ),
126
+ FastlaneCore::ConfigItem.new(
127
+ key: :output_path,
128
+ description: "Path to save output",
129
+ optional: true,
130
+ type: String
131
+ ),
132
+ FastlaneCore::ConfigItem.new(
133
+ key: :output_dir,
134
+ description: "Directory to save output files",
135
+ optional: true,
136
+ type: String
137
+ ),
138
+ FastlaneCore::ConfigItem.new(
139
+ key: :export_items,
140
+ description: "Items to export (array of strings)",
141
+ optional: true,
142
+ type: Array
143
+ ),
144
+ FastlaneCore::ConfigItem.new(
145
+ key: :source_results,
146
+ description: "Array of xcresult bundle paths to merge",
147
+ optional: true,
148
+ type: Array
149
+ ),
150
+ FastlaneCore::ConfigItem.new(
151
+ key: :baseline_path,
152
+ description: "Path to baseline .xcresult bundle for comparison",
153
+ optional: true,
154
+ type: String
155
+ ),
156
+ FastlaneCore::ConfigItem.new(
157
+ key: :only_changes,
158
+ description: "Show only changes in comparison",
159
+ optional: true,
160
+ default_value: false,
161
+ is_string: false
162
+ ),
163
+ FastlaneCore::ConfigItem.new(
164
+ key: :only_new_tests,
165
+ description: "Show only new tests in comparison",
166
+ optional: true,
167
+ default_value: false,
168
+ is_string: false
169
+ ),
170
+ FastlaneCore::ConfigItem.new(
171
+ key: :only_deleted_tests,
172
+ description: "Show only deleted tests in comparison",
173
+ optional: true,
174
+ default_value: false,
175
+ is_string: false
176
+ ),
177
+ FastlaneCore::ConfigItem.new(
178
+ key: :only_test_status_changes,
179
+ description: "Show only test status changes in comparison",
180
+ optional: true,
181
+ default_value: false,
182
+ is_string: false
183
+ ),
184
+ FastlaneCore::ConfigItem.new(
185
+ key: :only_performance_changes,
186
+ description: "Show only performance changes in comparison",
187
+ optional: true,
188
+ default_value: false,
189
+ is_string: false
190
+ ),
191
+ FastlaneCore::ConfigItem.new(
192
+ key: :verbose,
193
+ description: "Enable verbose output",
194
+ optional: true,
195
+ default_value: false,
196
+ is_string: false
197
+ )
198
+ ]
199
+ end
200
+
201
+ def self.is_supported?(platform)
202
+ [:ios, :mac].include?(platform)
203
+ end
204
+
205
+ def self.example_code
206
+ [
207
+ 'xcresulttool(
208
+ subcommand: "get",
209
+ result_bundle_path: "path/to/Test.xcresult",
210
+ format: "json",
211
+ type: "action-testSummary"
212
+ )',
213
+ 'xcresulttool(
214
+ subcommand: "export",
215
+ result_bundle_path: "path/to/Test.xcresult",
216
+ output_path: "output.json",
217
+ format: "json"
218
+ )',
219
+ 'xcresulttool(
220
+ subcommand: "compare",
221
+ result_bundle_path: "path/to/Test.xcresult",
222
+ baseline_path: "path/to/Baseline.xcresult",
223
+ format: "json",
224
+ only_changes: true
225
+ )',
226
+ 'xcresulttool(
227
+ subcommand: "merge",
228
+ output_path: "merged.xcresult",
229
+ source_results: ["result1.xcresult", "result2.xcresult"]
230
+ )'
231
+ ]
232
+ end
233
+
234
+ def self.category
235
+ :testing
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,165 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/xcresulttool_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class XcresulttoolCompareAction < Action
7
+ def self.run(params)
8
+ args = ["compare"]
9
+
10
+ # Validate result bundle paths
11
+ Helper::XcresulttoolHelper.validate_result_bundle_path(params[:result_bundle_path])
12
+ Helper::XcresulttoolHelper.validate_result_bundle_path(params[:baseline_path])
13
+
14
+ # Add required arguments
15
+ args << params[:result_bundle_path] # Use positional argument for comparison path
16
+ args << "--baseline-path" << params[:baseline_path]
17
+
18
+ # Add comparison output options
19
+ args << "--summary" if params[:summary]
20
+ args << "--test-failures" if params[:test_failures]
21
+ args << "--tests" if params[:tests]
22
+ args << "--build-warnings" if params[:build_warnings]
23
+ args << "--analyzer-issues" if params[:analyzer_issues]
24
+
25
+ # Add optional output format and path if supported
26
+ args << "--format" << params[:format] if params[:format] && params[:format_supported]
27
+ args << "--output-path" << params[:output_path] if params[:output_path]
28
+
29
+ args << "--verbose" if params[:verbose]
30
+
31
+ # Execute the command
32
+ result = Helper::XcresulttoolHelper.execute_command(args)
33
+
34
+ if params[:output_path]
35
+ UI.success("Comparison results saved to #{params[:output_path]}")
36
+ else
37
+ return result
38
+ end
39
+ end
40
+
41
+ def self.description
42
+ "Compare two Result Bundles using xcresulttool"
43
+ end
44
+
45
+ def self.authors
46
+ ["crazymanish"]
47
+ end
48
+
49
+ def self.return_value
50
+ "The output of the xcresulttool compare command as a string, or nil if output_path is specified"
51
+ end
52
+
53
+ def self.details
54
+ "This action compares two Xcode result bundles (.xcresult) and reports differences using Apple's xcresulttool compare subcommand"
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(
60
+ key: :result_bundle_path,
61
+ description: "Path to the .xcresult bundle to be compared",
62
+ optional: false,
63
+ type: String
64
+ ),
65
+ FastlaneCore::ConfigItem.new(
66
+ key: :baseline_path,
67
+ description: "Path to the baseline .xcresult bundle for comparison",
68
+ optional: false,
69
+ type: String
70
+ ),
71
+ FastlaneCore::ConfigItem.new(
72
+ key: :summary,
73
+ description: "Include the differential summary info in the output",
74
+ optional: true,
75
+ default_value: true,
76
+ is_string: false
77
+ ),
78
+ FastlaneCore::ConfigItem.new(
79
+ key: :test_failures,
80
+ description: "Include the differential test failures info in the output",
81
+ optional: true,
82
+ default_value: false,
83
+ is_string: false
84
+ ),
85
+ FastlaneCore::ConfigItem.new(
86
+ key: :tests,
87
+ description: "Include the differential tests info in the output",
88
+ optional: true,
89
+ default_value: false,
90
+ is_string: false
91
+ ),
92
+ FastlaneCore::ConfigItem.new(
93
+ key: :build_warnings,
94
+ description: "Include the differential build warnings info in the output",
95
+ optional: true,
96
+ default_value: false,
97
+ is_string: false
98
+ ),
99
+ FastlaneCore::ConfigItem.new(
100
+ key: :analyzer_issues,
101
+ description: "Include the differential analyzer issues info in the output",
102
+ optional: true,
103
+ default_value: false,
104
+ is_string: false
105
+ ),
106
+ FastlaneCore::ConfigItem.new(
107
+ key: :format,
108
+ description: "Output format (json, flat, human-readable)",
109
+ optional: true,
110
+ default_value: "json",
111
+ type: String
112
+ ),
113
+ FastlaneCore::ConfigItem.new(
114
+ key: :format_supported,
115
+ description: "Whether the format option is supported by your version of xcresulttool (newer versions only)",
116
+ optional: true,
117
+ default_value: false,
118
+ is_string: false
119
+ ),
120
+ FastlaneCore::ConfigItem.new(
121
+ key: :output_path,
122
+ description: "Path to save comparison results",
123
+ optional: true,
124
+ type: String
125
+ ),
126
+ FastlaneCore::ConfigItem.new(
127
+ key: :verbose,
128
+ description: "Enable verbose output",
129
+ optional: true,
130
+ default_value: false,
131
+ is_string: false
132
+ )
133
+ ]
134
+ end
135
+
136
+ def self.is_supported?(platform)
137
+ [:ios, :mac].include?(platform)
138
+ end
139
+
140
+ def self.example_code
141
+ [
142
+ 'xcresulttool_compare(
143
+ result_bundle_path: "path/to/Test.xcresult",
144
+ baseline_path: "path/to/Baseline.xcresult",
145
+ summary: true,
146
+ test_failures: true
147
+ )',
148
+ 'xcresulttool_compare(
149
+ result_bundle_path: "path/to/Test.xcresult",
150
+ baseline_path: "path/to/Baseline.xcresult",
151
+ summary: true,
152
+ tests: true,
153
+ build_warnings: true,
154
+ analyzer_issues: true,
155
+ output_path: "comparison_results.txt"
156
+ )'
157
+ ]
158
+ end
159
+
160
+ def self.category
161
+ :testing
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,123 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/xcresulttool_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class XcresulttoolExportAction < Action
7
+ def self.run(params)
8
+ args = ["export"]
9
+
10
+ # Validate result bundle path
11
+ Helper::XcresulttoolHelper.validate_result_bundle_path(params[:result_bundle_path])
12
+
13
+ # Add required arguments
14
+ args << "--path" << params[:result_bundle_path]
15
+
16
+ # Add optional arguments
17
+ args << "--format" << params[:format] if params[:format]
18
+ args << "--output-path" << params[:output_path] if params[:output_path]
19
+ args << "--output-dir" << params[:output_dir] if params[:output_dir]
20
+
21
+ # Handle export items
22
+ if params[:export_items]
23
+ params[:export_items].each do |item|
24
+ args << "--export-item" << item
25
+ end
26
+ end
27
+
28
+ args << "--verbose" if params[:verbose]
29
+
30
+ # Execute the command
31
+ result = Helper::XcresulttoolHelper.execute_command(args)
32
+
33
+ output_location = params[:output_path] || params[:output_dir]
34
+ if output_location
35
+ UI.success("Results exported to #{output_location}")
36
+ else
37
+ return result
38
+ end
39
+ end
40
+
41
+ def self.description
42
+ "Export Result Bundle contents using xcresulttool"
43
+ end
44
+
45
+ def self.authors
46
+ ["crazymanish"]
47
+ end
48
+
49
+ def self.return_value
50
+ "The output of the xcresulttool export command as a string, or nil if output_path or output_dir is specified"
51
+ end
52
+
53
+ def self.details
54
+ "This action exports content from an Xcode result bundle (.xcresult) using Apple's xcresulttool export subcommand"
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(
60
+ key: :result_bundle_path,
61
+ description: "Path to the .xcresult bundle",
62
+ optional: false,
63
+ type: String
64
+ ),
65
+ FastlaneCore::ConfigItem.new(
66
+ key: :format,
67
+ description: "Output format (json, flat, human-readable)",
68
+ optional: true,
69
+ default_value: "json",
70
+ type: String
71
+ ),
72
+ FastlaneCore::ConfigItem.new(
73
+ key: :output_path,
74
+ description: "Path to save output file",
75
+ optional: true,
76
+ type: String
77
+ ),
78
+ FastlaneCore::ConfigItem.new(
79
+ key: :output_dir,
80
+ description: "Directory to save output files",
81
+ optional: true,
82
+ type: String
83
+ ),
84
+ FastlaneCore::ConfigItem.new(
85
+ key: :export_items,
86
+ description: "Array of items to export",
87
+ optional: true,
88
+ type: Array
89
+ ),
90
+ FastlaneCore::ConfigItem.new(
91
+ key: :verbose,
92
+ description: "Enable verbose output",
93
+ optional: true,
94
+ default_value: false,
95
+ is_string: false
96
+ )
97
+ ]
98
+ end
99
+
100
+ def self.is_supported?(platform)
101
+ [:ios, :mac].include?(platform)
102
+ end
103
+
104
+ def self.example_code
105
+ [
106
+ 'xcresulttool_export(
107
+ result_bundle_path: "path/to/Test.xcresult",
108
+ output_path: "output.json"
109
+ )',
110
+ 'xcresulttool_export(
111
+ result_bundle_path: "path/to/Test.xcresult",
112
+ output_dir: "export_directory",
113
+ export_items: ["logs", "diagnostics"]
114
+ )'
115
+ ]
116
+ end
117
+
118
+ def self.category
119
+ :testing
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,119 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/xcresulttool_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class XcresulttoolGetAction < Action
7
+ def self.run(params)
8
+ args = ["get"]
9
+
10
+ # Validate result bundle path
11
+ Helper::XcresulttoolHelper.validate_result_bundle_path(params[:result_bundle_path])
12
+
13
+ # Add required arguments
14
+ args << "--path" << params[:result_bundle_path]
15
+
16
+ # Add optional arguments
17
+ args << "--format" << params[:format] if params[:format]
18
+ args << "--id" << params[:id] if params[:id]
19
+ args << "--output-path" << params[:output_path] if params[:output_path]
20
+ args << "--type" << params[:type] if params[:type]
21
+ args << "--verbose" if params[:verbose]
22
+
23
+ # Execute the command
24
+ result = Helper::XcresulttoolHelper.execute_command(args)
25
+
26
+ if params[:output_path]
27
+ UI.success("Results saved to #{params[:output_path]}")
28
+ else
29
+ return result
30
+ end
31
+ end
32
+
33
+ def self.description
34
+ "Get Result Bundle contents using xcresulttool"
35
+ end
36
+
37
+ def self.authors
38
+ ["crazymanish"]
39
+ end
40
+
41
+ def self.return_value
42
+ "The output of the xcresulttool get command as a string, or nil if output_path is specified"
43
+ end
44
+
45
+ def self.details
46
+ "This action extracts content from an Xcode result bundle (.xcresult) using Apple's xcresulttool get subcommand"
47
+ end
48
+
49
+ def self.available_options
50
+ [
51
+ FastlaneCore::ConfigItem.new(
52
+ key: :result_bundle_path,
53
+ description: "Path to the .xcresult bundle",
54
+ optional: false,
55
+ type: String
56
+ ),
57
+ FastlaneCore::ConfigItem.new(
58
+ key: :format,
59
+ description: "Output format (json, flat, human-readable)",
60
+ optional: true,
61
+ default_value: "json",
62
+ type: String
63
+ ),
64
+ FastlaneCore::ConfigItem.new(
65
+ key: :id,
66
+ description: "ID for the get subcommand",
67
+ optional: true,
68
+ type: String
69
+ ),
70
+ FastlaneCore::ConfigItem.new(
71
+ key: :type,
72
+ description: "Content type for the get subcommand (e.g., 'action-testSummary', 'test-report')",
73
+ optional: true,
74
+ type: String
75
+ ),
76
+ FastlaneCore::ConfigItem.new(
77
+ key: :output_path,
78
+ description: "Path to save output",
79
+ optional: true,
80
+ type: String
81
+ ),
82
+ FastlaneCore::ConfigItem.new(
83
+ key: :verbose,
84
+ description: "Enable verbose output",
85
+ optional: true,
86
+ default_value: false,
87
+ is_string: false
88
+ )
89
+ ]
90
+ end
91
+
92
+ def self.is_supported?(platform)
93
+ [:ios, :mac].include?(platform)
94
+ end
95
+
96
+ def self.example_code
97
+ [
98
+ 'xcresulttool_get(
99
+ result_bundle_path: "path/to/Test.xcresult",
100
+ format: "json"
101
+ )',
102
+ 'xcresulttool_get(
103
+ result_bundle_path: "path/to/Test.xcresult",
104
+ type: "action-testSummary",
105
+ output_path: "test_summary.json"
106
+ )',
107
+ 'xcresulttool_get(
108
+ result_bundle_path: "path/to/Test.xcresult",
109
+ type: "test-report"
110
+ )'
111
+ ]
112
+ end
113
+
114
+ def self.category
115
+ :testing
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,95 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/xcresulttool_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class XcresulttoolMergeAction < Action
7
+ def self.run(params)
8
+ args = ["merge"]
9
+
10
+ # Validate source result bundles
11
+ source_results = params[:source_results]
12
+ UI.user_error!("At least one source result bundle path must be provided") if source_results.nil? || source_results.empty?
13
+
14
+ source_results.each do |path|
15
+ Helper::XcresulttoolHelper.validate_result_bundle_path(path)
16
+ end
17
+
18
+ # Add required output path
19
+ output_path = params[:output_path]
20
+ UI.user_error!("Output path must be provided") if output_path.nil? || output_path.empty?
21
+ args << "--output-path" << output_path
22
+
23
+ # Add source result bundle paths directly as arguments
24
+ source_results.each do |path|
25
+ args << path
26
+ end
27
+
28
+ # Add verbose option if needed
29
+ args << "--verbose" if params[:verbose]
30
+
31
+ # Execute the command
32
+ Helper::XcresulttoolHelper.execute_command(args)
33
+
34
+ UI.success("Result bundles merged to #{output_path}")
35
+ end
36
+
37
+ def self.description
38
+ "Merge multiple Result Bundles using xcresulttool"
39
+ end
40
+
41
+ def self.authors
42
+ ["crazymanish"]
43
+ end
44
+
45
+ def self.return_value
46
+ nil
47
+ end
48
+
49
+ def self.details
50
+ "This action merges multiple Xcode result bundles (.xcresult) into a single bundle using Apple's xcresulttool merge subcommand"
51
+ end
52
+
53
+ def self.available_options
54
+ [
55
+ FastlaneCore::ConfigItem.new(
56
+ key: :source_results,
57
+ description: "Array of paths to .xcresult bundles to merge",
58
+ optional: false,
59
+ type: Array
60
+ ),
61
+ FastlaneCore::ConfigItem.new(
62
+ key: :output_path,
63
+ description: "Path where to save the merged result bundle",
64
+ optional: false,
65
+ type: String
66
+ ),
67
+ FastlaneCore::ConfigItem.new(
68
+ key: :verbose,
69
+ description: "Enable verbose output",
70
+ optional: true,
71
+ default_value: false,
72
+ is_string: false
73
+ )
74
+ ]
75
+ end
76
+
77
+ def self.is_supported?(platform)
78
+ [:ios, :mac].include?(platform)
79
+ end
80
+
81
+ def self.example_code
82
+ [
83
+ 'xcresulttool_merge(
84
+ source_results: ["path/to/Test1.xcresult", "path/to/Test2.xcresult"],
85
+ output_path: "path/to/MergedResults.xcresult"
86
+ )'
87
+ ]
88
+ end
89
+
90
+ def self.category
91
+ :testing
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,100 @@
1
+ require 'fastlane/action'
2
+ require_relative '../helper/xcresulttool_helper'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class XcresulttoolMetadataAction < Action
7
+ def self.run(params)
8
+ args = ["metadata"]
9
+
10
+ # Validate result bundle path
11
+ Helper::XcresulttoolHelper.validate_result_bundle_path(params[:result_bundle_path])
12
+
13
+ # Add required arguments
14
+ args << "--path" << params[:result_bundle_path]
15
+
16
+ # Add optional arguments
17
+ args << "--format" << params[:format] if params[:format]
18
+ args << "--output-path" << params[:output_path] if params[:output_path]
19
+ args << "--verbose" if params[:verbose]
20
+
21
+ # Execute the command
22
+ result = Helper::XcresulttoolHelper.execute_command(args)
23
+
24
+ if params[:output_path]
25
+ UI.success("Metadata saved to #{params[:output_path]}")
26
+ else
27
+ return result
28
+ end
29
+ end
30
+
31
+ def self.description
32
+ "Get Result Bundle metadata using xcresulttool"
33
+ end
34
+
35
+ def self.authors
36
+ ["crazymanish"]
37
+ end
38
+
39
+ def self.return_value
40
+ "The output of the xcresulttool metadata command as a string, or nil if output_path is specified"
41
+ end
42
+
43
+ def self.details
44
+ "This action extracts metadata from an Xcode result bundle (.xcresult) using Apple's xcresulttool metadata subcommand"
45
+ end
46
+
47
+ def self.available_options
48
+ [
49
+ FastlaneCore::ConfigItem.new(
50
+ key: :result_bundle_path,
51
+ description: "Path to the .xcresult bundle",
52
+ optional: false,
53
+ type: String
54
+ ),
55
+ FastlaneCore::ConfigItem.new(
56
+ key: :format,
57
+ description: "Output format (json, flat, human-readable)",
58
+ optional: true,
59
+ default_value: "json",
60
+ type: String
61
+ ),
62
+ FastlaneCore::ConfigItem.new(
63
+ key: :output_path,
64
+ description: "Path to save output",
65
+ optional: true,
66
+ type: String
67
+ ),
68
+ FastlaneCore::ConfigItem.new(
69
+ key: :verbose,
70
+ description: "Enable verbose output",
71
+ optional: true,
72
+ default_value: false,
73
+ is_string: false
74
+ )
75
+ ]
76
+ end
77
+
78
+ def self.is_supported?(platform)
79
+ [:ios, :mac].include?(platform)
80
+ end
81
+
82
+ def self.example_code
83
+ [
84
+ 'xcresulttool_metadata(
85
+ result_bundle_path: "path/to/Test.xcresult"
86
+ )',
87
+ 'xcresulttool_metadata(
88
+ result_bundle_path: "path/to/Test.xcresult",
89
+ format: "human-readable",
90
+ output_path: "metadata.txt"
91
+ )'
92
+ ]
93
+ end
94
+
95
+ def self.category
96
+ :testing
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,42 @@
1
+ require 'fastlane_core/ui/ui'
2
+
3
+ module Fastlane
4
+ UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
5
+
6
+ module Helper
7
+ class XcresulttoolHelper
8
+ # class methods that you define here become available in your action
9
+ # as `Helper::XcresulttoolHelper.your_method`
10
+ #
11
+ def self.show_message
12
+ UI.message("Hello from the xcresulttool plugin helper!")
13
+ end
14
+
15
+ # Execute xcresulttool command with given arguments
16
+ def self.execute_command(command_args)
17
+ cmd = ['xcrun', 'xcresulttool'] + command_args
18
+ UI.verbose("Executing command: #{cmd.join(' ')}")
19
+
20
+ result = ''
21
+ status = FastlaneCore::CommandExecutor.execute(
22
+ command: cmd,
23
+ print_all: false,
24
+ print_command: true
25
+ ) do |output|
26
+ result << output
27
+ end
28
+
29
+ if status != 0
30
+ UI.user_error!("Command failed with status #{status}")
31
+ end
32
+
33
+ return result
34
+ end
35
+
36
+ # Validate that a result bundle path exists
37
+ def self.validate_result_bundle_path(result_bundle_path)
38
+ UI.user_error!("Result bundle not found at path: #{result_bundle_path}") unless File.exist?(result_bundle_path)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Xcresulttool
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'fastlane/plugin/xcresulttool/version'
2
+
3
+ module Fastlane
4
+ module Xcresulttool
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::Xcresulttool.all_classes.each do |current|
15
+ require current
16
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-xcresulttool
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/xcresulttool.rb
22
+ - lib/fastlane/plugin/xcresulttool/actions/xcresulttool_action.rb
23
+ - lib/fastlane/plugin/xcresulttool/actions/xcresulttool_compare_action.rb
24
+ - lib/fastlane/plugin/xcresulttool/actions/xcresulttool_export_action.rb
25
+ - lib/fastlane/plugin/xcresulttool/actions/xcresulttool_get_action.rb
26
+ - lib/fastlane/plugin/xcresulttool/actions/xcresulttool_merge_action.rb
27
+ - lib/fastlane/plugin/xcresulttool/actions/xcresulttool_metadata_action.rb
28
+ - lib/fastlane/plugin/xcresulttool/helper/xcresulttool_helper.rb
29
+ - lib/fastlane/plugin/xcresulttool/version.rb
30
+ homepage:
31
+ licenses:
32
+ - MIT
33
+ metadata:
34
+ rubygems_mfa_required: 'true'
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '2.6'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.4.19
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: A fastlane plugin for xcresulttoo
54
+ test_files: []