fastlane-plugin-retry_tests 1.2.9 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fastlane/plugin/retry_tests.rb +3 -3
- data/lib/fastlane/plugin/retry_tests/actions/collate_junit_reports.rb +24 -19
- data/lib/fastlane/plugin/retry_tests/actions/multi_scan.rb +5 -2
- data/lib/fastlane/plugin/retry_tests/actions/suppress_tests.rb +0 -0
- data/lib/fastlane/plugin/retry_tests/actions/suppress_tests_from_junit.rb +0 -0
- data/lib/fastlane/plugin/retry_tests/actions/suppressed_tests.rb +0 -0
- data/lib/fastlane/plugin/retry_tests/actions/tests_from_junit.rb +0 -0
- data/lib/fastlane/plugin/retry_tests/actions/tests_from_xctestrun.rb +65 -0
- data/lib/fastlane/plugin/retry_tests/helper/correcting_scan_helper.rb +164 -0
- data/lib/fastlane/plugin/retry_tests/helper/junit_helper.rb +94 -0
- data/lib/fastlane/plugin/retry_tests/helper/reportname_helper.rb +70 -0
- data/lib/fastlane/plugin/retry_tests/helper/test_collector.rb +60 -0
- data/lib/fastlane/plugin/retry_tests/helper/xcodebuild_string.rb +14 -0
- data/lib/fastlane/plugin/retry_tests/version.rb +5 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad6db1868ae50026fe22c693857fb1a1a78f61fb
|
4
|
+
data.tar.gz: 103f996af1ed6c2ee7bb026ef53731233648f1e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f5106da53a539dcd50e7e3136e8a4bad77226e3d7d7cb5e3884e8206cb9bbef2f2072df341383feb574cb1a447aa5722b1ca7de40de3ebc6fac462cc9415eb1
|
7
|
+
data.tar.gz: 7e1f5374483038c240082c79dab5ad1597001ceb3d0d51c674b285005a2b770933ced8463780b02c1a329952f6587561207d8cf2d057146a6a3569d333b9bb2b
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
require 'fastlane/plugin/retry_tests/version'
|
2
2
|
|
3
3
|
module Fastlane
|
4
|
-
module
|
4
|
+
module RetryTests
|
5
5
|
# Return all .rb files inside the "actions" and "helper" directory
|
6
6
|
def self.all_classes
|
7
7
|
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
@@ -11,6 +11,6 @@ end
|
|
11
11
|
|
12
12
|
# By default we want to import all available actions and helpers
|
13
13
|
# A plugin can contain any number of actions and plugins
|
14
|
-
Fastlane::
|
14
|
+
Fastlane::RetryTests.all_classes.each do |current|
|
15
15
|
require current
|
16
16
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
#Adapted from the "fastlane-plugin-test_center" plugin
|
1
2
|
|
2
3
|
require 'nokogiri'
|
3
4
|
require 'nokogiri-plist'
|
@@ -11,9 +12,12 @@ module Fastlane
|
|
11
12
|
if report_filepaths.size == 1
|
12
13
|
FileUtils.cp(report_filepaths[0], params[:collated_report])
|
13
14
|
else
|
15
|
+
#Convert .plist reports to Nokogiri XML objects
|
14
16
|
target_report = File.open(report_filepaths.shift) {|f| Nokogiri::XML(f)}
|
15
17
|
file_name = params[:collated_report] + "/#{params[:scheme]}.test_result/1_Test/action_TestSummaries.plist"
|
16
18
|
reports = report_filepaths.map { |report_filepath| Nokogiri::XML(Nokogiri::PList(open(report_filepath)).to_plist_xml) }
|
19
|
+
|
20
|
+
#Merge .plist reports
|
17
21
|
reports.each do |retry_report|
|
18
22
|
mergeLists(target_report, retry_report, params)
|
19
23
|
end
|
@@ -22,24 +26,15 @@ module Fastlane
|
|
22
26
|
copy_log(params[:logs], params[:collated_report] + "/")
|
23
27
|
end
|
24
28
|
|
25
|
-
def self.clean_report(report)
|
26
|
-
report = report.gsub(/<(\w+): 0x(\w+)>/, '(\1: 0x\2)')
|
27
|
-
report = report.gsub(/<XCAccessibilityElement:\/>0x(\w+)/, '(XCAccessibilityElement): 0x\1')
|
28
|
-
report
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.copy_log(log_files, logs_folder)
|
32
|
-
target_log = log_files.shift
|
33
|
-
FileUtils.cp_r(target_log, logs_folder)
|
34
|
-
end
|
35
|
-
|
36
29
|
def self.mergeLists(target_report, retry_report, params)
|
37
30
|
retry_report = clean_report(retry_report)
|
38
|
-
UI.verbose("Merging retried results...")
|
39
31
|
Dir.mkdir(params[:collated_report]) unless File.exists?(params[:collated_report])
|
40
32
|
file_name = params[:collated_report] + "/action_TestSummaries.plist"
|
41
33
|
retried_tests = retry_report.xpath("//key[contains(.,'TestSummaryGUID')]/..")
|
34
|
+
|
42
35
|
current_node = retried_tests.shift
|
36
|
+
|
37
|
+
#Copy retried test results into the base report
|
43
38
|
while (current_node != nil)
|
44
39
|
testName = get_test_name(current_node)
|
45
40
|
matching_node = target_report.at_xpath("//string[contains(.,'#{testName}')]/..")
|
@@ -52,28 +47,37 @@ module Fastlane
|
|
52
47
|
end
|
53
48
|
end
|
54
49
|
|
50
|
+
def self.clean_report(report)
|
51
|
+
report = report.gsub(/<(\w+): 0x(\w+)>/, '(\1: 0x\2)')
|
52
|
+
report = report.gsub(/<XCAccessibilityElement:\/>0x(\w+)/, '(XCAccessibilityElement): 0x\1')
|
53
|
+
report
|
54
|
+
end
|
55
|
+
|
55
56
|
def self.merge_assets(asset_files, assets_folder)
|
56
|
-
|
57
|
+
#copy screenshots from all retries into the results folder
|
57
58
|
Dir.mkdir(assets_folder) unless File.exists?(assets_folder)
|
58
59
|
asset_files.each do |folder|
|
59
60
|
FileUtils.cp_r(Dir[folder + '/*'], assets_folder)
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
64
|
+
def self.copy_log(log_files, logs_folder)
|
65
|
+
target_log = log_files.shift
|
66
|
+
FileUtils.cp_r(target_log, logs_folder)
|
67
|
+
end
|
68
|
+
|
63
69
|
def self.merge_logs(log_files, logs_folder)
|
64
70
|
UI.verbose("Merging console logs...")
|
71
|
+
all = ""
|
65
72
|
target_log = log_files.shift
|
66
73
|
log_files.each do |log|
|
67
|
-
|
68
|
-
File.open(target_log, "a") do |handle|
|
69
|
-
handle.puts to_append
|
70
|
-
end
|
71
|
-
FileUtils.cp_r(target_log, logs_folder)
|
74
|
+
all = all + log + " "
|
72
75
|
end
|
76
|
+
sh("cat #{all}> #{target_log}")
|
77
|
+
FileUtils.cp_r(target_log, logs_folder)
|
73
78
|
end
|
74
79
|
|
75
80
|
def self.write_report_to_file(report, file_name)
|
76
|
-
UI.verbose("Writing merged results to file...")
|
77
81
|
File.new(file_name, 'w')
|
78
82
|
File.open(file_name, 'w') do |f|
|
79
83
|
f.write(report.to_xml)
|
@@ -167,6 +171,7 @@ module Fastlane
|
|
167
171
|
end
|
168
172
|
|
169
173
|
def self.authors
|
174
|
+
#Adapted from the "fastlane-plugin-test_center" plugin by:
|
170
175
|
["lyndsey-ferguson/@lyndseydf"]
|
171
176
|
end
|
172
177
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
#Adapted from the "fastlane-plugin-test_center" plugin
|
2
|
+
|
1
3
|
module Fastlane
|
2
4
|
module Actions
|
3
5
|
require 'fastlane/actions/scan'
|
@@ -23,7 +25,8 @@ module Fastlane
|
|
23
25
|
config = FastlaneCore::Configuration.create(Fastlane::Actions::ScanAction.available_options, scan_options)
|
24
26
|
Fastlane::Actions::ScanAction.run(config)
|
25
27
|
rescue FastlaneCore::Interface::FastlaneTestFailure => e
|
26
|
-
UI.verbose("Scan failed with #{e}")
|
28
|
+
FastlaneCore::UI.verbose("Scan failed with error #{e}")
|
29
|
+
#Retry for the specified number of times if there were failed tests
|
27
30
|
if try_count < params[:try_count]
|
28
31
|
report_filepath = junit_report_filepath(scan_options)
|
29
32
|
failed_tests = other_action.tests_from_junit(junit: report_filepath)[:failed]
|
@@ -40,7 +43,6 @@ module Fastlane
|
|
40
43
|
asset_files = Dir.glob("#{folder}*/#{scan_options[:scheme]}.test_result/1_Test/Attachments")
|
41
44
|
log_files = Dir.glob("#{folder}*/#{scan_options[:scheme]}.test_result/1_Test/action.xcactivitylog")
|
42
45
|
#Merge all reports, screenshots, and logs if there were retried tests
|
43
|
-
|
44
46
|
if report_files.size > 1
|
45
47
|
other_action.collate_junit_reports(
|
46
48
|
scheme: scan_options[:scheme],
|
@@ -132,6 +134,7 @@ module Fastlane
|
|
132
134
|
end
|
133
135
|
|
134
136
|
def self.authors
|
137
|
+
#Adapted from the "fastlane-plugin-test_center" plugin by:
|
135
138
|
["lyndsey-ferguson/@lyndseydf"]
|
136
139
|
end
|
137
140
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'plist'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Actions
|
5
|
+
class TestsFromXctestrunAction < Action
|
6
|
+
def self.run(params)
|
7
|
+
return xctestrun_tests(params[:xctestrun])
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.xctestrun_tests(xctestrun_path)
|
11
|
+
xctestrun = Plist.parse_xml(xctestrun_path)
|
12
|
+
xctestrun_rootpath = File.dirname(xctestrun_path)
|
13
|
+
tests = Hash.new([])
|
14
|
+
xctestrun.each do |testable_name, xctestrun_config|
|
15
|
+
test_identifiers = XCTestList.tests(xctest_bundle_path(xctestrun_rootpath, xctestrun_config))
|
16
|
+
if xctestrun_config.key?('SkipTestIdentifiers')
|
17
|
+
test_identifiers.reject! { |test_identifier| xctestrun_config['SkipTestIdentifiers'].include?(test_identifier) }
|
18
|
+
end
|
19
|
+
tests[testable_name] = test_identifiers.map do |test_identifier|
|
20
|
+
"#{testable_name.shellescape}/#{test_identifier}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
tests
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.xctest_bundle_path(xctestrun_rootpath, xctestrun_config)
|
27
|
+
xctest_host_path = xctestrun_config['TestHostPath'].sub('__TESTROOT__', xctestrun_rootpath)
|
28
|
+
xctestrun_config['TestBundlePath'].sub('__TESTHOST__', xctest_host_path).sub('__TESTROOT__', xctestrun_rootpath)
|
29
|
+
end
|
30
|
+
|
31
|
+
#####################################################
|
32
|
+
# @!group Documentation
|
33
|
+
#####################################################
|
34
|
+
|
35
|
+
def self.description
|
36
|
+
"Retrieves all of the tests from xctest bundles referenced by the xctestrun file"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.available_options
|
40
|
+
[
|
41
|
+
FastlaneCore::ConfigItem.new(
|
42
|
+
key: :xctestrun,
|
43
|
+
env_name: "FL_SUPPRESS_TESTS_FROM_XCTESTRUN_FILE",
|
44
|
+
description: "The xctestrun file to use to find where the xctest bundle file is for test retrieval",
|
45
|
+
verify_block: proc do |path|
|
46
|
+
UI.user_error!("Error: cannot find the xctestrun file '#{path}'") unless File.exist?(path)
|
47
|
+
end
|
48
|
+
)
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.return_value
|
53
|
+
"A Hash of testable => tests, where testable is the name of the test target and tests is an array of test identifiers"
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.authors
|
57
|
+
["lyndsey-ferguson/lyndseydf"]
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.is_supported?(platform)
|
61
|
+
platform == :ios
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module TestCenter
|
2
|
+
module Helper
|
3
|
+
require 'fastlane_core/ui/ui.rb'
|
4
|
+
require 'plist'
|
5
|
+
|
6
|
+
class CorrectingScanHelper
|
7
|
+
attr_reader :retry_total_count
|
8
|
+
|
9
|
+
def initialize(multi_scan_options)
|
10
|
+
@batch_count = multi_scan_options[:batch_count] || 1
|
11
|
+
@output_directory = multi_scan_options[:output_directory] || 'test_results'
|
12
|
+
@try_count = multi_scan_options[:try_count]
|
13
|
+
@retry_total_count = 0
|
14
|
+
@testrun_completed_block = multi_scan_options[:testrun_completed_block]
|
15
|
+
@given_custom_report_file_name = multi_scan_options[:custom_report_file_name]
|
16
|
+
@given_output_types = multi_scan_options[:output_types]
|
17
|
+
@given_output_files = multi_scan_options[:output_files]
|
18
|
+
@scan_options = multi_scan_options.reject do |option, _|
|
19
|
+
%i[
|
20
|
+
output_directory
|
21
|
+
only_testing
|
22
|
+
skip_testing
|
23
|
+
clean
|
24
|
+
try_count
|
25
|
+
batch_count
|
26
|
+
custom_report_file_name
|
27
|
+
fail_build
|
28
|
+
testrun_completed_block
|
29
|
+
].include?(option)
|
30
|
+
end
|
31
|
+
@test_collector = TestCollector.new(multi_scan_options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def scan
|
35
|
+
tests_passed = true
|
36
|
+
@testables_count = @test_collector.testables.size
|
37
|
+
@test_collector.testables.each do |testable|
|
38
|
+
tests_passed = scan_testable(testable) && tests_passed
|
39
|
+
end
|
40
|
+
tests_passed
|
41
|
+
end
|
42
|
+
|
43
|
+
def scan_testable(testable)
|
44
|
+
tests_passed = true
|
45
|
+
reportnamer = ReportNameHelper.new(
|
46
|
+
@given_output_types,
|
47
|
+
@given_output_files,
|
48
|
+
@given_custom_report_file_name
|
49
|
+
)
|
50
|
+
output_directory = @output_directory
|
51
|
+
testable_tests = @test_collector.testables_tests[testable]
|
52
|
+
if @batch_count > 1 || @testables_count > 1
|
53
|
+
current_batch = 1
|
54
|
+
testable_tests.each_slice((testable_tests.length / @batch_count.to_f).round).to_a.each do |tests_batch|
|
55
|
+
if @testables_count > 1
|
56
|
+
output_directory = File.join(@output_directory, "results-#{testable}")
|
57
|
+
end
|
58
|
+
FastlaneCore::UI.header("Starting test run on testable '#{testable}'")
|
59
|
+
tests_passed = correcting_scan(
|
60
|
+
{
|
61
|
+
only_testing: tests_batch,
|
62
|
+
output_directory: output_directory
|
63
|
+
},
|
64
|
+
current_batch,
|
65
|
+
reportnamer
|
66
|
+
) && tests_passed
|
67
|
+
current_batch += 1
|
68
|
+
reportnamer.increment
|
69
|
+
end
|
70
|
+
else
|
71
|
+
options = {
|
72
|
+
output_directory: output_directory,
|
73
|
+
only_testing: testable_tests
|
74
|
+
}
|
75
|
+
tests_passed = correcting_scan(options, 1, reportnamer) && tests_passed
|
76
|
+
end
|
77
|
+
collate_reports(output_directory, reportnamer)
|
78
|
+
tests_passed
|
79
|
+
end
|
80
|
+
|
81
|
+
def collate_reports(output_directory, reportnamer)
|
82
|
+
report_files = Dir.glob("#{output_directory}/*#{reportnamer.junit_filextension}").map do |relative_filepath|
|
83
|
+
File.absolute_path(relative_filepath)
|
84
|
+
end
|
85
|
+
if report_files.size > 1
|
86
|
+
config = FastlaneCore::Configuration.create(
|
87
|
+
Fastlane::Actions::CollateJunitReportsAction.available_options,
|
88
|
+
{
|
89
|
+
reports: report_files.sort { |f1, f2| File.mtime(f1) <=> File.mtime(f2) },
|
90
|
+
collated_report: File.absolute_path(File.join(output_directory, reportnamer.junit_reportname))
|
91
|
+
}
|
92
|
+
)
|
93
|
+
Fastlane::Actions::CollateJunitReportsAction.run(config)
|
94
|
+
end
|
95
|
+
retried_junit_reportfiles = Dir.glob("#{output_directory}/**/*-[1-9]*#{reportnamer.junit_filextension}")
|
96
|
+
FileUtils.rm_f(retried_junit_reportfiles)
|
97
|
+
end
|
98
|
+
|
99
|
+
def correcting_scan(scan_run_options, batch, reportnamer)
|
100
|
+
scan_options = @scan_options.merge(scan_run_options)
|
101
|
+
try_count = 0
|
102
|
+
tests_passed = true
|
103
|
+
begin
|
104
|
+
try_count += 1
|
105
|
+
config = FastlaneCore::Configuration.create(
|
106
|
+
Fastlane::Actions::ScanAction.available_options,
|
107
|
+
scan_options.merge(reportnamer.scan_options)
|
108
|
+
)
|
109
|
+
quit_simulators
|
110
|
+
Fastlane::Actions::ScanAction.run(config)
|
111
|
+
@testrun_completed_block && @testrun_completed_block.call(
|
112
|
+
testrun_info(batch, try_count, reportnamer, scan_options[:output_directory])
|
113
|
+
)
|
114
|
+
tests_passed = true
|
115
|
+
rescue FastlaneCore::Interface::FastlaneTestFailure => e
|
116
|
+
FastlaneCore::UI.verbose("Scan failed with #{e}")
|
117
|
+
if try_count < @try_count
|
118
|
+
@retry_total_count += 1
|
119
|
+
|
120
|
+
info = testrun_info(batch, try_count, reportnamer, scan_options[:output_directory])
|
121
|
+
@testrun_completed_block && @testrun_completed_block.call(
|
122
|
+
info
|
123
|
+
)
|
124
|
+
scan_options[:only_testing] = info[:failed].map(&:shellescape)
|
125
|
+
FastlaneCore::UI.message('Re-running scan on only failed tests')
|
126
|
+
reportnamer.increment
|
127
|
+
retry
|
128
|
+
end
|
129
|
+
tests_passed = false
|
130
|
+
end
|
131
|
+
tests_passed
|
132
|
+
end
|
133
|
+
|
134
|
+
def testrun_info(batch, try_count, reportnamer, output_directory)
|
135
|
+
report_filepath = File.join(output_directory, reportnamer.junit_last_reportname)
|
136
|
+
config = FastlaneCore::Configuration.create(
|
137
|
+
Fastlane::Actions::TestsFromJunitAction.available_options,
|
138
|
+
{
|
139
|
+
junit: File.absolute_path(report_filepath)
|
140
|
+
}
|
141
|
+
)
|
142
|
+
junit_results = Fastlane::Actions::TestsFromJunitAction.run(config)
|
143
|
+
|
144
|
+
{
|
145
|
+
failed: junit_results[:failed],
|
146
|
+
passing: junit_results[:passing],
|
147
|
+
batch: batch,
|
148
|
+
try_count: try_count,
|
149
|
+
report_filepath: report_filepath
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
def quit_simulators
|
154
|
+
Fastlane::Actions.sh("killall -9 'iPhone Simulator' 'Simulator' 'SimulatorBridge' &> /dev/null || true", log: false)
|
155
|
+
launchctl_list_count = 0
|
156
|
+
while Fastlane::Actions.sh('launchctl list | grep com.apple.CoreSimulator.CoreSimulatorService || true', log: false) != ''
|
157
|
+
break if (launchctl_list_count += 1) > 10
|
158
|
+
Fastlane::Actions.sh('launchctl remove com.apple.CoreSimulator.CoreSimulatorService &> /dev/null || true', log: false)
|
159
|
+
sleep(1)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative 'xcodebuild_string'
|
2
|
+
|
3
|
+
module TestCenter
|
4
|
+
module Helper
|
5
|
+
module XcodeJunit
|
6
|
+
require 'xcodeproj'
|
7
|
+
|
8
|
+
class Report
|
9
|
+
def initialize(junit_report_filepath)
|
10
|
+
report_file = File.open(junit_report_filepath) { |f| REXML::Document.new(f) }
|
11
|
+
UI.user_error!("Malformed XML test report file given") if report_file.root.nil?
|
12
|
+
UI.user_error!("Valid XML file is not an Xcode test report") if report_file.get_elements('testsuites').empty?
|
13
|
+
|
14
|
+
@testables = []
|
15
|
+
report_file.elements.each('testsuites') do |testsuites_element|
|
16
|
+
@testables << Testable.new(testsuites_element)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def testables
|
21
|
+
return @testables
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Testable
|
26
|
+
def initialize(xml_element)
|
27
|
+
@root = xml_element
|
28
|
+
@testsuites = []
|
29
|
+
@root.elements.each('testsuite') do |testsuite_element|
|
30
|
+
@testsuites << TestSuite.new(testsuite_element)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
return @root.attributes['name']
|
36
|
+
end
|
37
|
+
|
38
|
+
def testsuites
|
39
|
+
return @testsuites
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class TestSuite
|
44
|
+
def initialize(xml_element)
|
45
|
+
@root = xml_element
|
46
|
+
@testcases = []
|
47
|
+
@root.elements.each('testcase') do |testcase_element|
|
48
|
+
@testcases << TestCase.new(testcase_element)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def name
|
53
|
+
return @root.attributes['name']
|
54
|
+
end
|
55
|
+
|
56
|
+
def identifier
|
57
|
+
name.testsuite
|
58
|
+
end
|
59
|
+
|
60
|
+
def is_swift?
|
61
|
+
return name.include?('.')
|
62
|
+
end
|
63
|
+
|
64
|
+
def testcases
|
65
|
+
return @testcases
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class TestCase
|
70
|
+
attr_reader :identifier
|
71
|
+
attr_reader :skipped_test
|
72
|
+
|
73
|
+
def initialize(xml_element)
|
74
|
+
@root = xml_element
|
75
|
+
name = xml_element.attributes['name']
|
76
|
+
full_testsuite = xml_element.parent.attributes['name']
|
77
|
+
testsuite = full_testsuite.testsuite
|
78
|
+
is_swift = full_testsuite.testsuite_swift?
|
79
|
+
|
80
|
+
testable_filename = xml_element.parent.parent.attributes['name']
|
81
|
+
testable = File.basename(testable_filename, '.xctest')
|
82
|
+
@identifier = "#{testable}/#{testsuite}/#{name}"
|
83
|
+
@skipped_test = Xcodeproj::XCScheme::TestAction::TestableReference::SkippedTest.new
|
84
|
+
@skipped_test.identifier = "#{testsuite}/#{name}#{'()' if is_swift}"
|
85
|
+
@passed = xml_element.get_elements('failure').size.zero?
|
86
|
+
end
|
87
|
+
|
88
|
+
def passed?
|
89
|
+
@passed
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module TestCenter
|
2
|
+
module Helper
|
3
|
+
require 'fastlane_core/ui/ui.rb'
|
4
|
+
|
5
|
+
class ReportNameHelper
|
6
|
+
def initialize(output_types = nil, output_files = nil, custom_report_file_name = nil)
|
7
|
+
@output_types = output_types || 'junit'
|
8
|
+
@output_files = output_files || custom_report_file_name
|
9
|
+
@report_count = 0
|
10
|
+
|
11
|
+
if @output_types && @output_files.nil?
|
12
|
+
@output_files = @output_types.split(',').map { |type| "report.#{type}" }.join(',')
|
13
|
+
end
|
14
|
+
unless @output_types.include?('junit')
|
15
|
+
FastlaneCore::UI.important('Scan output types missing \'junit\', adding it')
|
16
|
+
@output_types = @output_types.split(',').push('junit').join(',')
|
17
|
+
if @output_types.split(',').size == @output_files.split(',').size + 1
|
18
|
+
@output_files = @output_files.split(',').push('report.xml').join(',')
|
19
|
+
FastlaneCore::UI.message('As output files has one less than the new number of output types, assumming the filename for the junit was missing and added it')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
types = @output_types.split(',').each(&:chomp)
|
24
|
+
files = @output_files.split(',').each(&:chomp)
|
25
|
+
unless files.size == types.size
|
26
|
+
raise ArgumentError, "Error: count of :output_types, #{types}, does not match the output filename(s) #{files}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def numbered_filename(filename)
|
31
|
+
if @report_count > 0
|
32
|
+
basename = File.basename(filename, '.*')
|
33
|
+
extension = File.extname(filename)
|
34
|
+
filename = "#{basename}-#{@report_count + 1}#{extension}"
|
35
|
+
end
|
36
|
+
filename
|
37
|
+
end
|
38
|
+
|
39
|
+
def scan_options
|
40
|
+
files = @output_files.split(',').each(&:chomp)
|
41
|
+
files.map! do |filename|
|
42
|
+
filename.chomp
|
43
|
+
numbered_filename(filename)
|
44
|
+
end
|
45
|
+
{
|
46
|
+
output_types: @output_types,
|
47
|
+
output_files: files.join(',')
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def junit_last_reportname
|
52
|
+
junit_index = @output_types.split(',').find_index('junit')
|
53
|
+
numbered_filename(@output_files.to_s.split(',')[junit_index])
|
54
|
+
end
|
55
|
+
|
56
|
+
def junit_reportname
|
57
|
+
junit_index = @output_types.split(',').find_index('junit')
|
58
|
+
@output_files.to_s.split(',')[junit_index]
|
59
|
+
end
|
60
|
+
|
61
|
+
def junit_filextension
|
62
|
+
File.extname(junit_reportname)
|
63
|
+
end
|
64
|
+
|
65
|
+
def increment
|
66
|
+
@report_count += 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module TestCenter
|
2
|
+
module Helper
|
3
|
+
require 'fastlane_core/ui/ui.rb'
|
4
|
+
require 'plist'
|
5
|
+
|
6
|
+
class TestCollector
|
7
|
+
def initialize(options)
|
8
|
+
@xctestrun_path = options[:xctestrun] || derived_testrun_path(options[:derived_data_path], options[:scheme])
|
9
|
+
@only_testing = options[:only_testing]
|
10
|
+
@skip_testing = options[:skip_testing]
|
11
|
+
end
|
12
|
+
|
13
|
+
def derived_testrun_path(derived_data_path, scheme)
|
14
|
+
Dir.glob("#{derived_data_path}/Build/Products/#{scheme}*.xctestrun").first
|
15
|
+
end
|
16
|
+
|
17
|
+
def testables
|
18
|
+
unless @testables
|
19
|
+
if @only_testing
|
20
|
+
@testables ||= only_testing_to_testables_tests.keys
|
21
|
+
else
|
22
|
+
@testables ||= Plist.parse_xml(@xctestrun_path).keys
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@testables
|
26
|
+
end
|
27
|
+
|
28
|
+
def only_testing_to_testables_tests
|
29
|
+
tests = Hash.new { |h, k| h[k] = [] }
|
30
|
+
@only_testing.sort.each do |test_identifier|
|
31
|
+
testable = test_identifier.split('/', 2)[0]
|
32
|
+
tests[testable] << test_identifier
|
33
|
+
end
|
34
|
+
tests
|
35
|
+
end
|
36
|
+
|
37
|
+
def testables_tests
|
38
|
+
unless @testables_tests
|
39
|
+
if @only_testing
|
40
|
+
@testables_tests = only_testing_to_testables_tests
|
41
|
+
else
|
42
|
+
config = FastlaneCore::Configuration.create(::Fastlane::Actions::TestsFromXctestrunAction.available_options, xctestrun: @xctestrun_path)
|
43
|
+
@testables_tests = ::Fastlane::Actions::TestsFromXctestrunAction.run(config)
|
44
|
+
if @skip_testing
|
45
|
+
skipped_testable_tests = Hash.new { |h, k| h[k] = [] }
|
46
|
+
@skip_testing.sort.each do |skipped_test_identifier|
|
47
|
+
testable = skipped_test_identifier.split('/', 2)[0]
|
48
|
+
skipped_testable_tests[testable] << skipped_test_identifier
|
49
|
+
end
|
50
|
+
@testables_tests.each_key do |testable|
|
51
|
+
@testables_tests[testable] -= skipped_testable_tests[testable]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@testables_tests
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-retry_tests
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gloria Chow
|
@@ -187,6 +187,13 @@ files:
|
|
187
187
|
- lib/fastlane/plugin/retry_tests/actions/suppress_tests_from_junit.rb
|
188
188
|
- lib/fastlane/plugin/retry_tests/actions/suppressed_tests.rb
|
189
189
|
- lib/fastlane/plugin/retry_tests/actions/tests_from_junit.rb
|
190
|
+
- lib/fastlane/plugin/retry_tests/actions/tests_from_xctestrun.rb
|
191
|
+
- lib/fastlane/plugin/retry_tests/helper/correcting_scan_helper.rb
|
192
|
+
- lib/fastlane/plugin/retry_tests/helper/junit_helper.rb
|
193
|
+
- lib/fastlane/plugin/retry_tests/helper/reportname_helper.rb
|
194
|
+
- lib/fastlane/plugin/retry_tests/helper/test_collector.rb
|
195
|
+
- lib/fastlane/plugin/retry_tests/helper/xcodebuild_string.rb
|
196
|
+
- lib/fastlane/plugin/retry_tests/version.rb
|
190
197
|
homepage: https://github.com/kouzoh/fastlane-plugin-retry_tests
|
191
198
|
licenses:
|
192
199
|
- MIT
|
@@ -210,5 +217,5 @@ rubyforge_project:
|
|
210
217
|
rubygems_version: 2.6.14
|
211
218
|
signing_key:
|
212
219
|
specification_version: 4
|
213
|
-
summary: Makes testing your iOS app easier
|
220
|
+
summary: Makes testing your iOS app easier
|
214
221
|
test_files: []
|