fastlane-plugin-try_scan 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3bf2f28d3558be4e3d2cd068beb9a4968f1957532a554aa902134c0db1e5e05
4
- data.tar.gz: b4f5d09eede219e2425efce5487481947bee2a30075aac8448ba9f014ddbb48e
3
+ metadata.gz: f1cf8ffd4f2e1a0558797b6bdd7094d7b36f42306d28d10bea3172be11c42688
4
+ data.tar.gz: c286e3609e7900a837322e36dc86ed3ead3a17fe0a32a3239a87de8feb8a742a
5
5
  SHA512:
6
- metadata.gz: 575e434210450543a657cdcae55e88573183e552a2e12125d83ac4fc5cbdaa0ef715699268a6b1059a12f23ffb4a6fea47a3093683d95fc61146a6dc359d1b76
7
- data.tar.gz: 4670941d32adf903ff77ebf024555c40295ad64b7e267cb027b40def51d45183f4df0e1521778ac623857bb30a180e42990ac04b3aa30343083b3f9910992080
6
+ metadata.gz: 27fea4e492a529eee6953d601914075b0042549345bfb4fc91e28bf0562fc514c943bbebdb929777c5973d863ec8b09795b9445e46c76cd3da142a14c42d08fa
7
+ data.tar.gz: 12bab09a883ab80263e01a65b07ec9670df952a2800d1296a87688af7bf8736de240ebf35f05cf6f54df822d405cc3cf3c50f40b2c6ca3f908b0db69e1288d32
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Getting Started
6
6
 
7
- This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-try_scan`, add it to your project by running:
7
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `try_scan`, add it to your project by running:
8
8
 
9
9
  ```bash
10
10
  fastlane add_plugin try_scan
@@ -12,27 +12,16 @@ fastlane add_plugin try_scan
12
12
 
13
13
  ## About try_scan
14
14
 
15
- Simple way to retry your scan action
15
+ Simple way to retry your scan action 🚀
16
16
 
17
- **Note to author:** Add a more detailed description about this plugin here. If your plugin contains multiple actions, make sure to mention them here.
17
+ ## Usage
18
18
 
19
- ## Example
20
-
21
- 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`.
22
-
23
- **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
24
-
25
- ## Run tests for this plugin
26
-
27
- To run both the tests, and code style validation, run
28
-
29
- ```
30
- rake
31
- ```
32
-
33
- To automatically fix many of the styling issues, use
34
- ```
35
- rubocop -a
19
+ ```ruby
20
+ try_scan(
21
+ workspace: "Example.xcworkspace",
22
+ devices: ["iPhone 6s", "iPad Air"],
23
+ try_count: 3
24
+ )
36
25
  ```
37
26
 
38
27
  ## Issues and Feedback
@@ -43,10 +32,6 @@ For any other issues and feedback about this plugin, please submit it to this re
43
32
 
44
33
  If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
45
34
 
46
- ## Using _fastlane_ Plugins
47
-
48
- For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
49
-
50
35
  ## About _fastlane_
51
36
 
52
37
  _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).
@@ -1,6 +1,7 @@
1
1
  module Fastlane
2
2
  module Actions
3
3
 
4
+ require 'json'
4
5
  require 'fastlane/actions/scan'
5
6
  require_relative '../helper/scan_helper'
6
7
  require_relative '../helper/try_scan_runner'
@@ -9,61 +10,31 @@ module Fastlane
9
10
 
10
11
  class TryScanAction < Action
11
12
  def self.run(params)
12
- prepare_for_testing(params)
13
- success = TryScanManager::Runner.new(params.values).run
14
-
15
- raise FastlaneCore::UI.test_failure!('Tests have failed') if params[:fail_build] && !success
16
- end
17
-
18
- def self.prepare_for_testing(params)
19
- warn_of_xcode11_result_bundle_incompatability(params)
20
- use_scanfile_to_override_settings(params.values)
21
- turn_off_concurrent_workers(params.values)
22
- prepare_scan_config(params.values)
23
- coerce_destination_to_array(params)
13
+ if Helper.xcode_at_least?('11.0.0')
14
+ prepare_scan_config(params.values)
15
+ prepare_destination(params)
16
+ success = TryScanManager::Runner.new(params.values).run
17
+
18
+ raise FastlaneCore::UI.test_failure!('Tests have failed') if params[:fail_build] && !success
19
+ else
20
+ raise FastlaneCore::UI.user_error!("Minimum supported Xcode: `v11.0.0` (used: `v#{Helper.xcode_version}`)")
21
+ end
24
22
  end
25
23
 
26
- def self.warn_of_xcode11_result_bundle_incompatability(params)
27
- if FastlaneCore::Helper.xcode_at_least?('11.0.0')
28
- if params[:result_bundle]
29
- FastlaneCore::UI.important('As of Xcode 11, test_result bundles created in the output directory are actually symbolic links to an xcresult bundle')
30
- end
31
- elsif params[:output_types]&.include?('xcresult')
32
- FastlaneCore::UI.important("The 'xcresult' :output_type is only supported for Xcode 11 and greater. You are using #{FastlaneCore::Helper.xcode_version}.")
33
- end
24
+ def self.prepare_scan_config(scan_options)
25
+ Scan.config = FastlaneCore::Configuration.create(
26
+ Fastlane::Actions::ScanAction.available_options,
27
+ FastlaneScanHelper.scan_options_from_try_scan_options(scan_options)
28
+ )
34
29
  end
35
30
 
36
- def self.coerce_destination_to_array(params)
31
+ def self.prepare_destination(params)
37
32
  destination = params[:destination] || Scan.config[:destination] || []
38
33
  unless destination.kind_of?(Array)
39
34
  params[:destination] = Scan.config[:destination] = [destination]
40
35
  end
41
36
  end
42
37
 
43
- def self.turn_off_concurrent_workers(scan_options)
44
- if Gem::Version.new(Fastlane::VERSION) >= Gem::Version.new('2.142.0')
45
- scan_options.delete(:concurrent_workers) if scan_options[:concurrent_workers].to_i > 0
46
- end
47
- end
48
-
49
- def self.use_scanfile_to_override_settings(scan_options)
50
- overridden_options = FastlaneScanHelper.options_from_configuration_file(
51
- FastlaneScanHelper.scan_options_from_try_scan_options(scan_options)
52
- )
53
-
54
- unless overridden_options.empty?
55
- FastlaneCore::UI.important("Scanfile found: overriding try_scan options with it's values.")
56
- overridden_options.each { |key, val| scan_options[key] = val }
57
- end
58
- end
59
-
60
- def self.prepare_scan_config(scan_options)
61
- Scan.config ||= FastlaneCore::Configuration.create(
62
- Fastlane::Actions::ScanAction.available_options,
63
- FastlaneScanHelper.scan_options_from_try_scan_options(scan_options)
64
- )
65
- end
66
-
67
38
  #####################################################
68
39
  # Documentation #
69
40
  #####################################################
@@ -76,13 +47,8 @@ module Fastlane
76
47
  ["Alexey Alter-Pesotskiy"]
77
48
  end
78
49
 
79
- def self.scan_options
80
- ScanAction.available_options.reject { |config| %i[output_types].include?(config.key) }
81
- end
82
-
83
50
  def self.available_options
84
- scan_options = ScanAction.available_options.reject { |config| %i[output_types].include?(config.key) }
85
- scan_options + [
51
+ ScanAction.available_options + [
86
52
  FastlaneCore::ConfigItem.new(
87
53
  key: :try_count,
88
54
  env_name: "FL_TRY_SCAN_TRY_COUNT",
@@ -19,31 +19,9 @@ module TryScanManager
19
19
  end
20
20
 
21
21
  def self.scan_options_from_try_scan_options(params)
22
- valid_scan_keys = Fastlane::Actions::ScanAction.available_options.map(&:key)
23
22
  params.select { |key, _| valid_scan_keys.include?(key) }
24
23
  end
25
24
 
26
- def self.options_from_configuration_file(params)
27
- config = FastlaneCore::Configuration.create(
28
- Fastlane::Actions::ScanAction.available_options,
29
- params
30
- )
31
- config_file = config.load_configuration_file(Scan.scanfile_name, nil, true)
32
- overridden_options = config_file ? config_file.options : {}
33
-
34
- FastlaneCore::Project.detect_projects(config)
35
- project = FastlaneCore::Project.new(config)
36
-
37
- imported_path = File.expand_path(Scan.scanfile_name)
38
- Dir.chdir(File.expand_path("..", project.path)) do
39
- if File.expand_path(Scan.scanfile_name) != imported_path
40
- config_file = config.load_configuration_file(Scan.scanfile_name, nil, true)
41
- end
42
- overridden_options.merge!(config_file.options) if config_file
43
- end
44
- overridden_options
45
- end
46
-
47
25
  def self.remove_preexisting_simulator_logs(params)
48
26
  return unless params[:include_simulator_logs]
49
27
 
@@ -88,18 +66,6 @@ module TryScanManager
88
66
  end
89
67
  end
90
68
  end
91
-
92
- def self.update_xctestrun_after_build(scan_options)
93
- xctestrun_files = Dir.glob("#{Scan.config[:derived_data_path]}/Build/Products/*.xctestrun")
94
- FastlaneCore::UI.verbose("After building, found xctestrun files #{xctestrun_files} (choosing 1st)")
95
- scan_options[:xctestrun] = xctestrun_files.first
96
- end
97
-
98
- def self.remove_preexisting_xctestrun_files
99
- xctestrun_files = Dir.glob("#{Scan.config[:derived_data_path]}/Build/Products/*.xctestrun")
100
- FastlaneCore::UI.verbose("Before building, removing pre-existing xctestrun files: #{xctestrun_files}")
101
- FileUtils.rm_rf(xctestrun_files)
102
- end
103
69
  end
104
70
  end
105
- end
71
+ end
@@ -5,30 +5,37 @@ module TryScanManager
5
5
 
6
6
  def initialize(options = {})
7
7
  @options = options
8
- warn_of_try_scan_option
8
+ @options[:try_count] = 1 if @options[:try_count] < 1
9
9
  end
10
10
 
11
11
  def run
12
- update_scan_config
13
12
  print_summary
14
- attempt = 1
13
+ @attempt = 1
15
14
  begin
16
- warn_of_performing_attempts(attempt)
15
+ essential_scan_config_updates
16
+ warn_of_performing_attempts
17
17
  clear_preexisting_data
18
18
  Scan::Runner.new.run
19
+ print_try_scan_result
19
20
  return true
20
- rescue FastlaneCore::Interface::FastlaneBuildFailure, FastlaneCore::Interface::FastlaneTestFailure => _
21
- merge_junit_reports if attempt != 1
22
- return false if attempt > @options[:try_count]
21
+ rescue FastlaneCore::Interface::FastlaneTestFailure => _
22
+ failed_tests = failed_tests_from_xcresult_report
23
+ print_try_scan_result(failed_tests_count: failed_tests.size)
24
+ return false if finish?
23
25
 
24
- attempt += 1
25
- update_scan_options
26
+ @attempt += 1
27
+ update_scan_options(failed_tests)
28
+ retry
29
+ rescue FastlaneCore::Interface::FastlaneBuildFailure => _
30
+ return false if finish?
31
+
32
+ @attempt += 1
26
33
  retry
27
34
  end
28
35
  end
29
36
 
30
- def update_scan_config
31
- Scan.config[:output_types] << 'junit' unless Scan.config[:output_types].include?('junit')
37
+ def finish?
38
+ @attempt >= @options[:try_count]
32
39
  end
33
40
 
34
41
  def print_summary
@@ -47,15 +54,8 @@ module TryScanManager
47
54
  )
48
55
  end
49
56
 
50
- def warn_of_performing_attempts(attempt)
51
- FastlaneCore::UI.important("TryScan shot №#{attempt}\n")
52
- end
53
-
54
- def warn_of_try_scan_option
55
- if @options[:try_count] <= 0
56
- FastlaneCore::UI.important(":try_count can't be less than or equal to zero. Setting a default value equal to `1`")
57
- @options[:try_count] = 1
58
- end
57
+ def warn_of_performing_attempts
58
+ FastlaneCore::UI.important("TryScan: Getting started #{ordinalized_attempt} shot\n")
59
59
  end
60
60
 
61
61
  def clear_preexisting_data
@@ -65,81 +65,77 @@ module TryScanManager
65
65
  FastlaneScanHelper.remove_report_files
66
66
  end
67
67
 
68
- def update_scan_options
69
- scan_options = @options.select { |key, _| FastlaneScanHelper.valid_scan_keys.include?(key) }.merge(plugin_scan_options)
70
- scan_options[:only_testing] = extract_failed_tests
68
+ def print_try_scan_result(failed_tests_count: 0)
69
+ FastlaneCore::UI.important("TryScan: result after #{ordinalized_attempt} shot 👇")
70
+ FastlaneCore::PrintTable.print_values(
71
+ config: {"Number of tests" => tests_count_from_xcresult_report, "Number of failures" => failed_tests_count},
72
+ title: "Test Results"
73
+ )
74
+ end
75
+
76
+ def ordinalized_attempt
77
+ case @attempt
78
+ when 1
79
+ "#{@attempt}st"
80
+ when 2
81
+ "#{@attempt}nd"
82
+ when 3
83
+ "#{@attempt}rd"
84
+ else
85
+ "#{@attempt}th"
86
+ end
87
+ end
88
+
89
+ def update_scan_options(failed_tests)
90
+ scan_options = FastlaneScanHelper.scan_options_from_try_scan_options(@options)
91
+ scan_options[:only_testing] = failed_tests
71
92
  scan_options[:skip_build] = true
72
93
  scan_options[:test_without_building] = true
73
- scan_options[:build_for_testing] = false
74
94
  scan_options.delete(:skip_testing)
75
95
  Scan.cache.clear
76
96
  scan_options.each do |key, val|
77
97
  next if val.nil?
78
98
 
79
- Scan.config.set(key, val) unless val.nil?
99
+ Scan.config.set(key, val)
80
100
  FastlaneCore::UI.verbose("\tSetting #{key.to_s} to #{val}")
81
101
  end
82
102
  end
83
103
 
84
- def plugin_scan_options
85
- xcargs = @options[:xcargs] || ''
86
- if xcargs&.include?('build-for-testing')
87
- FastlaneCore::UI.important(":xcargs, #{xcargs}, contained 'build-for-testing', removing it")
88
- xcargs.slice!('build-for-testing')
89
- end
90
- if xcargs.include?('-quiet')
91
- FastlaneCore::UI.important('Disabling -quiet as failing tests cannot be found with it enabled.')
92
- xcargs.gsub!('-quiet', '')
93
- end
94
- xcargs.gsub!(/-parallel-testing-enabled(=|\s+)(YES|NO)/, '')
95
- @options.select { |k,v| FastlaneScanHelper.valid_scan_keys.include?(k) }.merge({ xcargs: "#{xcargs} -parallel-testing-enabled NO " })
104
+ def essential_scan_config_updates
105
+ Scan.config[:result_bundle] = true
106
+ Scan.config[:build_for_testing] = nil if Scan.config[:build_for_testing]
107
+ Scan.config[:xcargs].slice!('build-for-testing') if Scan.config[:xcargs]&.include?('build-for-testing')
96
108
  end
97
109
 
98
- def extract_failed_tests
99
- report = junit_report
100
- suite_name = report.xpath('testsuites/@name').to_s.split('.')[0]
101
- test_cases = report.xpath('//testcase')
102
- only_testing = []
103
- test_cases.each do |test_case|
104
- next if test_case.xpath('failure').empty?
110
+ def parse_xcresult_report
111
+ report_options = FastlaneScanHelper.report_options
112
+ output_directory = report_options.instance_variable_get(:@output_directory)
113
+ xcresult_report_files = Dir["#{output_directory}/*.xcresult"]
114
+ raise FastlaneCore::UI.test_failure!('There are no xcresult reports to parse') if xcresult_report_files.empty?
105
115
 
106
- test_class = test_case.xpath('@classname').to_s.split('.')[1]
107
- test_name = test_case.xpath('@name')
108
- only_testing << "#{suite_name}/#{test_class}/#{test_name}"
109
- end
110
- only_testing
116
+ FastlaneCore::UI.verbose("Parsing xcresult report by path: '#{xcresult_report_files.first}'")
117
+ JSON.parse(`xcrun xcresulttool get --format json --path #{xcresult_report_files.first}`)
111
118
  end
112
119
 
113
- def junit_report(cached: false)
114
- unless cached
115
- report_options = FastlaneScanHelper.report_options
116
- output_files = report_options.instance_variable_get(:@output_files)
117
- output_directory = report_options.instance_variable_get(:@output_directory)
118
- file_name = output_files.select { |name| name.include?('.xml') }.first
119
- @junit_report_path = "#{output_directory}/#{file_name}"
120
- @cached_junit_report = File.open(@junit_report_path) { |f| Nokogiri::XML(f) }
121
- end
122
- @cached_junit_report
123
- end
124
-
125
- def merge_junit_reports
126
- old_junit_report = junit_report(cached: true)
127
- new_junit_report = junit_report(cached: false)
128
-
129
- new_junit_report.css("testsuites").zip(old_junit_report.css("testsuites")).each do |new_suites, old_suites|
130
- old_suites.attributes["failures"].value = new_suites.attributes["failures"].value
131
- new_suites.css("testsuite").zip(old_suites.css("testsuite")).each do |new_suite, old_suite|
132
- old_suite.attributes["failures"].value = new_suite.attributes["failures"].value
133
- end
134
- end
135
-
136
- new_junit_report.css('testcase').each do |node1|
137
- old_junit_report.css('testcase').each do |node2|
138
- node2.children = node1.children if node1['name'] == node2['name']
120
+ def failed_tests_from_xcresult_report
121
+ only_testing = []
122
+ parse_xcresult_report['issues']['testFailureSummaries']['_values'].each do |failed_test|
123
+ suite_name = failed_test['producingTarget']['_value']
124
+ test_path = failed_test['testCaseName']['_value']
125
+ begin
126
+ test_class = test_path.split('.').first
127
+ test_name = test_path.split('.')[1].split('(').first
128
+ rescue NoMethodError => _
129
+ test_class = test_path.split('[')[1].split(' ').first
130
+ test_name = test_path.split(' ')[1].split(']').first
139
131
  end
132
+ only_testing << "#{suite_name}/#{test_class}/#{test_name}"
140
133
  end
134
+ only_testing
135
+ end
141
136
 
142
- File.open(@junit_report_path, "w+") { |f| f.write(old_junit_report.to_xml) }
137
+ def tests_count_from_xcresult_report
138
+ parse_xcresult_report['metrics']['testsCount']['_value']
143
139
  end
144
140
  end
145
141
  end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TryScan
3
- VERSION = "0.1.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-try_scan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Alter-Pesotskiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-09 00:00:00.000000000 Z
11
+ date: 2020-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: pry
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -122,20 +136,6 @@ dependencies:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: nokogiri
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: fastlane
141
141
  requirement: !ruby/object:Gem::Requirement