fastlane-plugin-try_scan 0.1.0 → 0.4.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 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