fastlane-plugin-create_simulator_devices 0.0.12 → 0.0.14
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 +4 -4
- data/lib/fastlane/plugin/create_simulator_devices/actions/create_simulator_devices_action.rb +37 -4
- data/lib/fastlane/plugin/create_simulator_devices/actions/gather_simctl_diagnose_action.rb +153 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/apple_build_version.rb +11 -3
- data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/device_naming_style.rb +14 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models.rb +1 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/runner.rb +92 -10
- data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/runtime_helper.rb +10 -3
- data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/shell_helper.rb +12 -3
- data/lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/module.rb +10 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/runner.rb +84 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/scripts/collect_simctl_diagnose_data.expect +9 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/scripts/collect_simctl_diagnose_data.sh +40 -0
- data/lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/shared_values.rb +11 -0
- data/lib/fastlane/plugin/create_simulator_devices/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d67f3fc97805357d10286a81d1d7fcbf18ede6af69da32b176c6fcd73ab72a2f
|
4
|
+
data.tar.gz: baf9ecd15c0dc7fbc66c413f61d48f44bf37a6ff32963fb4647cdcf9b586bdeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8de8e706a371d863ee1646ca85c899ee96c42ce7f94a2c6bb97fabbc579b03af429ddc439356ea7a6d429507e0ccc4c21fda66007ffef6a16fd6925e99ef033f
|
7
|
+
data.tar.gz: ddd40fb588c98656bae804668cc5ee899af6c09fc660a629edc6a6c443f431832375a0e3930dcb27ebc89153d325780386961dc8e4fececb877fb16b2488648a
|
data/lib/fastlane/plugin/create_simulator_devices/actions/create_simulator_devices_action.rb
CHANGED
@@ -4,6 +4,7 @@ require 'fastlane'
|
|
4
4
|
require 'spaceship'
|
5
5
|
require_relative '../helpers/create_simulator_devices/runner'
|
6
6
|
require_relative '../helpers/create_simulator_devices/models'
|
7
|
+
require_relative '../helpers/create_simulator_devices/models/device_naming_style'
|
7
8
|
|
8
9
|
module Fastlane
|
9
10
|
module Actions
|
@@ -22,12 +23,16 @@ module Fastlane
|
|
22
23
|
UI.user_error!('No devices specified') if required_devices.nil? || required_devices.empty?
|
23
24
|
|
24
25
|
shell_helper = CreateSimulatorDevices::ShellHelper.new(print_command: params[:print_command], print_command_output: params[:print_command_output], action_context: self)
|
25
|
-
runtime_helper = CreateSimulatorDevices::RuntimeHelper.new(cache_dir: params[:cache_dir], shell_helper
|
26
|
+
runtime_helper = CreateSimulatorDevices::RuntimeHelper.new(cache_dir: params[:cache_dir], shell_helper: shell_helper, verbose: verbose)
|
26
27
|
|
27
28
|
runner = CreateSimulatorDevices::Runner.new(
|
28
29
|
runtime_helper: runtime_helper,
|
29
30
|
shell_helper: shell_helper,
|
30
|
-
verbose: verbose
|
31
|
+
verbose: verbose,
|
32
|
+
can_rename_devices: params[:rename_devices],
|
33
|
+
can_delete_duplicate_devices: params[:delete_duplicate_devices],
|
34
|
+
device_naming_style: params[:device_naming_style].to_sym,
|
35
|
+
remove_cached_runtimes: params[:remove_cached_runtimes]
|
31
36
|
)
|
32
37
|
|
33
38
|
runner.run(required_devices)
|
@@ -52,7 +57,7 @@ module Fastlane
|
|
52
57
|
)"
|
53
58
|
end
|
54
59
|
|
55
|
-
def self.available_options
|
60
|
+
def self.available_options # rubocop:disable Metrics/MethodLength
|
56
61
|
[
|
57
62
|
::FastlaneCore::ConfigItem.new(key: :devices,
|
58
63
|
env_name: 'SCAN_DEVICES',
|
@@ -80,7 +85,35 @@ module Fastlane
|
|
80
85
|
description: 'Print xcrun simctl commands output',
|
81
86
|
type: Boolean,
|
82
87
|
optional: true,
|
83
|
-
default_value: false)
|
88
|
+
default_value: false),
|
89
|
+
::FastlaneCore::ConfigItem.new(key: :rename_devices,
|
90
|
+
env_name: 'CREATE_SIMULATOR_DEVICES_RENAME_DEVICES',
|
91
|
+
description: 'Rename devices if needed',
|
92
|
+
type: Boolean,
|
93
|
+
optional: true,
|
94
|
+
default_value: false),
|
95
|
+
::FastlaneCore::ConfigItem.new(key: :delete_duplicate_devices,
|
96
|
+
env_name: 'CREATE_SIMULATOR_DEVICES_DELETE_DUPLICATE_DEVICES',
|
97
|
+
description: 'Delete duplicate devices',
|
98
|
+
type: Boolean,
|
99
|
+
optional: true,
|
100
|
+
default_value: false),
|
101
|
+
::FastlaneCore::ConfigItem.new(key: :device_naming_style,
|
102
|
+
env_name: 'CREATE_SIMULATOR_DEVICES_DEVICE_NAMING_STYLE',
|
103
|
+
description: 'Device naming style',
|
104
|
+
type: String,
|
105
|
+
optional: true,
|
106
|
+
default_value: CreateSimulatorDevices::DeviceNamingStyle::SCAN.to_s,
|
107
|
+
verify_block: proc do |value|
|
108
|
+
allowed_values = CreateSimulatorDevices::DeviceNamingStyle::ALL
|
109
|
+
UI.user_error!("Invalid device naming style: #{value}. Allowed values: #{allowed_values.map(&:to_s).join(', ')}") unless allowed_values.include?(value.to_sym)
|
110
|
+
end),
|
111
|
+
::FastlaneCore::ConfigItem.new(key: :remove_cached_runtimes,
|
112
|
+
env_name: 'CREATE_SIMULATOR_DEVICES_REMOVE_CACHED_RUNTIMES',
|
113
|
+
description: 'Remove cached runtimes after successful installation',
|
114
|
+
type: Boolean,
|
115
|
+
optional: true,
|
116
|
+
default_value: true)
|
84
117
|
]
|
85
118
|
end
|
86
119
|
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fastlane'
|
4
|
+
require 'spaceship'
|
5
|
+
require_relative '../helpers/create_simulator_devices/shell_helper'
|
6
|
+
require_relative '../helpers/create_simulator_devices/runner'
|
7
|
+
require_relative '../helpers/create_simulator_devices/models/device_naming_style'
|
8
|
+
require_relative '../helpers/gather_simctl_diagnose/runner'
|
9
|
+
|
10
|
+
module Fastlane
|
11
|
+
module Actions
|
12
|
+
GatherSimctlDiagnose = ::Fastlane::GatherSimctlDiagnose
|
13
|
+
CreateSimulatorDevices = ::Fastlane::CreateSimulatorDevices
|
14
|
+
|
15
|
+
# Gather simctl diagnose data.
|
16
|
+
class GatherSimctlDiagnoseAction < Fastlane::Action
|
17
|
+
UI = ::Fastlane::UI unless defined?(UI)
|
18
|
+
|
19
|
+
attr_accessor :shell_helper
|
20
|
+
|
21
|
+
def self.run(params)
|
22
|
+
verbose = params[:verbose]
|
23
|
+
params[:devices] = params[:devices].split(',').map(&:strip) if params[:devices].is_a?(String)
|
24
|
+
required_devices = params[:devices]
|
25
|
+
UI.user_error!('No devices specified') if required_devices.nil? || required_devices.empty?
|
26
|
+
|
27
|
+
shell_helper = CreateSimulatorDevices::ShellHelper.new(print_command: params[:print_command], print_command_output: params[:print_command_output], action_context: self)
|
28
|
+
runtime_helper = CreateSimulatorDevices::RuntimeHelper.new(cache_dir: nil, shell_helper: shell_helper, verbose: verbose)
|
29
|
+
|
30
|
+
create_simulator_devices_runner = ::Fastlane::CreateSimulatorDevices::Runner.new(
|
31
|
+
runtime_helper: runtime_helper,
|
32
|
+
shell_helper: shell_helper,
|
33
|
+
verbose: verbose,
|
34
|
+
can_rename_devices: false,
|
35
|
+
can_delete_duplicate_devices: false,
|
36
|
+
device_naming_style: params[:device_naming_style].to_sym,
|
37
|
+
remove_cached_runtimes: false
|
38
|
+
)
|
39
|
+
|
40
|
+
runner = GatherSimctlDiagnose::Runner.new(
|
41
|
+
runtime_helper: runtime_helper,
|
42
|
+
shell_helper: shell_helper,
|
43
|
+
verbose: verbose,
|
44
|
+
device_naming_style: params[:device_naming_style].to_sym,
|
45
|
+
create_simulator_devices_runner: create_simulator_devices_runner,
|
46
|
+
output_dir: params[:output_dir],
|
47
|
+
timeout: params[:timeout],
|
48
|
+
include_all_device_logs: params[:include_all_device_logs],
|
49
|
+
include_booted_device_data_directory: params[:include_booted_device_data_directory]
|
50
|
+
)
|
51
|
+
|
52
|
+
runner.run(required_devices)
|
53
|
+
end
|
54
|
+
|
55
|
+
#####################################################
|
56
|
+
# @!group Documentation
|
57
|
+
#####################################################
|
58
|
+
|
59
|
+
def self.description
|
60
|
+
'Gathers simctl diagnose data'
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.details
|
64
|
+
"This action gathers simctl diagnose data.
|
65
|
+
|
66
|
+
Usage sample:
|
67
|
+
|
68
|
+
gather_simctl_diagnose(
|
69
|
+
devices: ['iPhone 15 (17.0)', 'iPhone 16', 'iPhone 14 (16.3)']
|
70
|
+
output_dir: 'diagnose'
|
71
|
+
)"
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.available_options # rubocop:disable Metrics/MethodLength
|
75
|
+
[
|
76
|
+
::FastlaneCore::ConfigItem.new(key: :devices,
|
77
|
+
env_name: 'SCAN_DEVICES',
|
78
|
+
description: 'A list of simulator devices to install (e.g. "iPhone 16")',
|
79
|
+
is_string: false,
|
80
|
+
default_value: 'iPhone 16'),
|
81
|
+
::FastlaneCore::ConfigItem.new(key: :verbose,
|
82
|
+
env_name: 'VERBOSE',
|
83
|
+
description: 'Verbose output',
|
84
|
+
type: Boolean,
|
85
|
+
optional: true,
|
86
|
+
default_value: ::FastlaneCore::Globals.verbose?,
|
87
|
+
default_value_dynamic: true),
|
88
|
+
::FastlaneCore::ConfigItem.new(key: :output_dir,
|
89
|
+
env_name: 'GATHER_SIMCTL_DIAGNOSE_OUTPUT_DIR',
|
90
|
+
description: 'Output directory',
|
91
|
+
type: String,
|
92
|
+
optional: false),
|
93
|
+
::FastlaneCore::ConfigItem.new(key: :print_command,
|
94
|
+
description: 'Print xcrun simctl commands',
|
95
|
+
type: Boolean,
|
96
|
+
optional: true,
|
97
|
+
default_value: false),
|
98
|
+
::FastlaneCore::ConfigItem.new(key: :print_command_output,
|
99
|
+
description: 'Print xcrun simctl commands output',
|
100
|
+
type: Boolean,
|
101
|
+
optional: true,
|
102
|
+
default_value: false),
|
103
|
+
::FastlaneCore::ConfigItem.new(key: :device_naming_style,
|
104
|
+
env_name: 'CREATE_SIMULATOR_DEVICES_DEVICE_NAMING_STYLE',
|
105
|
+
description: 'Device naming style',
|
106
|
+
type: String,
|
107
|
+
optional: true,
|
108
|
+
default_value: CreateSimulatorDevices::DeviceNamingStyle::SCAN.to_s,
|
109
|
+
verify_block: proc do |value|
|
110
|
+
allowed_values = CreateSimulatorDevices::DeviceNamingStyle::ALL
|
111
|
+
UI.user_error!("Invalid device naming style: #{value}. Allowed values: #{allowed_values.map(&:to_s).join(', ')}") unless allowed_values.include?(value.to_sym)
|
112
|
+
end),
|
113
|
+
::FastlaneCore::ConfigItem.new(key: :timeout,
|
114
|
+
env_name: 'GATHER_SIMCTL_DIAGNOSE_TIMEOUT',
|
115
|
+
description: 'Timeout',
|
116
|
+
type: Integer,
|
117
|
+
optional: true,
|
118
|
+
default_value: 300),
|
119
|
+
::FastlaneCore::ConfigItem.new(key: :include_all_device_logs,
|
120
|
+
env_name: 'GATHER_SIMCTL_DIAGNOSE_INCLUDE_ALL_DEVICE_LOGS',
|
121
|
+
description: 'Include all device logs',
|
122
|
+
type: Boolean,
|
123
|
+
optional: true,
|
124
|
+
default_value: false),
|
125
|
+
::FastlaneCore::ConfigItem.new(key: :include_booted_device_data_directory,
|
126
|
+
env_name: 'GATHER_SIMCTL_DIAGNOSE_INCLUDE_BOOTED_DEVICE_DATA_DIRECTORY',
|
127
|
+
description: 'Include booted device data directory. Warning: May include private information, app data containers, and increases the size of the archive! Default is NOT to collect the data container',
|
128
|
+
type: Boolean,
|
129
|
+
optional: true,
|
130
|
+
default_value: false)
|
131
|
+
]
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.output
|
135
|
+
[
|
136
|
+
['GATHER_SIMCTL_DIAGNOSE_OUTPUT_FILE', 'Output archive file with simctl diagnose data']
|
137
|
+
]
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.return_value
|
141
|
+
'Returns a path to the output archive file with simctl diagnose data'
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.authors
|
145
|
+
['nekrich']
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.is_supported?(_platform) # rubocop:disable Naming/PredicatePrefix
|
149
|
+
true
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -58,11 +58,19 @@ module Fastlane
|
|
58
58
|
return self == other unless lhs_is_beta && rhs_is_beta && @build_version.length == rhs_build_version.to_s.length
|
59
59
|
|
60
60
|
# Take only leading chars up to the first letter included e.g. 22C146 -> 22C
|
61
|
-
|
61
|
+
major == rhs_build_version.major && minor == rhs_build_version.minor && patch == rhs_build_version.patch
|
62
62
|
end
|
63
63
|
|
64
|
-
def
|
65
|
-
|
64
|
+
def major
|
65
|
+
@build_version.match(/^([0-9]+)([A-Z][0-9]{2,3})([0-9]+)/)[1]
|
66
|
+
end
|
67
|
+
|
68
|
+
def minor
|
69
|
+
@build_version.match(/^([0-9]+)([A-Z][0-9]{2,3})([0-9]+)/)[2]
|
70
|
+
end
|
71
|
+
|
72
|
+
def patch
|
73
|
+
@build_version.match(/^([0-9]+)([A-Z][0-9]{2,3})([0-9]+)/)[3]
|
66
74
|
end
|
67
75
|
|
68
76
|
def <(other)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module CreateSimulatorDevices
|
5
|
+
class DeviceNamingStyle
|
6
|
+
SCAN = :scan
|
7
|
+
RUN_TESTS = :run_tests
|
8
|
+
SNAPSHOT = :snapshot
|
9
|
+
CAPTURE_IOS_SCREENSHOTS = :capture_ios_screenshots
|
10
|
+
|
11
|
+
ALL = [SCAN, RUN_TESTS, SNAPSHOT, CAPTURE_IOS_SCREENSHOTS].freeze
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative 'models/xcodebuild/sdk'
|
|
8
8
|
require_relative 'models/required_device'
|
9
9
|
require_relative 'models/required_runtime'
|
10
10
|
require_relative 'models/apple_build_version'
|
11
|
+
require_relative 'models/device_naming_style'
|
11
12
|
require 'fastlane'
|
12
13
|
|
13
14
|
module Fastlane
|
data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/runner.rb
CHANGED
@@ -3,20 +3,25 @@
|
|
3
3
|
require_relative 'runtime_helper'
|
4
4
|
require 'fastlane'
|
5
5
|
require_relative 'shared_values'
|
6
|
+
require_relative 'models/device_naming_style'
|
6
7
|
|
7
8
|
module Fastlane
|
8
9
|
# Create simulator devices.
|
9
10
|
module CreateSimulatorDevices
|
10
11
|
# Does all the work to create simulator devices.
|
11
|
-
class Runner
|
12
|
+
class Runner # rubocop:disable Metrics/ClassLength
|
12
13
|
UI = ::Fastlane::UI unless defined?(UI)
|
13
14
|
|
14
|
-
attr_accessor :shell_helper, :verbose, :runtime_helper
|
15
|
+
attr_accessor :shell_helper, :verbose, :runtime_helper, :can_rename_devices, :can_delete_duplicate_devices, :device_naming_style, :remove_cached_runtimes
|
15
16
|
|
16
|
-
def initialize(runtime_helper:, shell_helper:, verbose:)
|
17
|
+
def initialize(runtime_helper:, shell_helper:, verbose:, can_rename_devices:, can_delete_duplicate_devices:, device_naming_style:, remove_cached_runtimes:) # rubocop:disable Metrics/ParameterLists
|
17
18
|
self.shell_helper = shell_helper
|
18
19
|
self.verbose = verbose
|
19
20
|
self.runtime_helper = runtime_helper
|
21
|
+
self.can_rename_devices = can_rename_devices
|
22
|
+
self.can_delete_duplicate_devices = can_delete_duplicate_devices
|
23
|
+
self.device_naming_style = device_naming_style
|
24
|
+
self.remove_cached_runtimes = remove_cached_runtimes
|
20
25
|
end
|
21
26
|
|
22
27
|
def run(devices)
|
@@ -50,11 +55,11 @@ module Fastlane
|
|
50
55
|
|
51
56
|
log_matched_devices(matched_devices: matched_devices)
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
matched_devices_names = matched_devices.map(&:description)
|
58
|
+
matched_devices_names = matched_devices.map { |matched_device| returning_device_name_for_required_device(matched_device) }
|
56
59
|
UI.message("Available simulator devices: #{matched_devices_names.join(', ')}")
|
57
60
|
|
61
|
+
Actions.lane_context[Actions::SharedValues::AVAILABLE_SIMULATOR_DEVICES] = matched_devices_names
|
62
|
+
|
58
63
|
matched_devices_names
|
59
64
|
end
|
60
65
|
|
@@ -85,14 +90,91 @@ module Fastlane
|
|
85
90
|
|
86
91
|
simctl_devices = shell_helper.simctl_devices_for_runtimes[required_device.simctl_runtime.identifier.to_sym]
|
87
92
|
|
88
|
-
return
|
93
|
+
return nil if simctl_devices.nil?
|
89
94
|
|
90
95
|
# Find the device with the same name as the required device.
|
91
96
|
devices_with_same_type = simctl_devices
|
92
97
|
.select { |simctl_device| simctl_device.device_type_identifier == required_device.device_type.identifier }
|
93
98
|
|
94
|
-
|
95
|
-
|
99
|
+
preferred_device_name = device_name_for_required_device(required_device)
|
100
|
+
|
101
|
+
# Prefer device with the same name that includes the runtime version.
|
102
|
+
matching_device = devices_with_same_type.detect { |simctl_device| simctl_device.name == preferred_device_name }
|
103
|
+
|
104
|
+
if can_rename_devices
|
105
|
+
# Otherwise, if rename is enabled, use the first device with the same type.
|
106
|
+
matching_device ||= devices_with_same_type.first
|
107
|
+
rename_device_if_needed(matching_device, preferred_device_name)
|
108
|
+
end
|
109
|
+
|
110
|
+
delete_duplicate_devices(devices_with_same_type, matching_device) if can_delete_duplicate_devices
|
111
|
+
|
112
|
+
matching_device
|
113
|
+
end
|
114
|
+
|
115
|
+
def rename_device_if_needed(matching_device, preferred_device_name)
|
116
|
+
return if matching_device.nil? || matching_device.name == preferred_device_name
|
117
|
+
|
118
|
+
UI.message("Renaming device #{matching_device.name} (udid: #{matching_device.udid}) to #{preferred_device_name}")
|
119
|
+
shell_helper.rename_device(udid: matching_device.udid, name: preferred_device_name)
|
120
|
+
matching_device.name = preferred_device_name
|
121
|
+
end
|
122
|
+
|
123
|
+
def delete_duplicate_devices(matching_devices, matching_device)
|
124
|
+
return if matching_device.nil?
|
125
|
+
|
126
|
+
matching_devices
|
127
|
+
.reject { |simctl_device| simctl_device.udid == matching_device.udid }
|
128
|
+
.each do |simctl_device|
|
129
|
+
UI.message("Deleting duplicate device #{simctl_device.name} (udid: #{simctl_device.udid})")
|
130
|
+
shell_helper.delete_device(udid: simctl_device.udid)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Returns the device name for the required device.
|
135
|
+
#
|
136
|
+
# This name is used in the simctl device name.
|
137
|
+
def device_name_for_required_device(required_device)
|
138
|
+
case device_naming_style
|
139
|
+
when DeviceNamingStyle::SCAN, DeviceNamingStyle::RUN_TESTS
|
140
|
+
# scan modifies the device name by removing the runtime version when searching for a passed device name.
|
141
|
+
# E.g.:
|
142
|
+
# * given "iPhone 15 (17.0)" match will search for simulator named "iPhone 15" with the SDK version 17.0.
|
143
|
+
# * given "iPhone 15" match will search for simulator named "iPhone 15" with the default SDK version.
|
144
|
+
# So we need to name the device by the device type name for scan to find the correct device.
|
145
|
+
required_device.device_type.name
|
146
|
+
when DeviceNamingStyle::SNAPSHOT, DeviceNamingStyle::CAPTURE_IOS_SCREENSHOTS
|
147
|
+
# snapshot nither does not modify the device name when searching for a passed device name nor extracts the runtime version from the device name.
|
148
|
+
# E.g.:
|
149
|
+
# * given "iPhone 15 (17.0)" match will search for device named exactly "iPhone 15 (17.0)".
|
150
|
+
# * given "iPhone 15" match will search for device named exactly "iPhone 15".
|
151
|
+
# So we need to return the full device name for the required device for snapshot to find the correct device.
|
152
|
+
runtime_build = required_device.simctl_runtime.build_version
|
153
|
+
build_suffix = runtime_build.beta? ? "-#{runtime_build}" : ''
|
154
|
+
"#{required_device.device_type.name} (#{required_device.simctl_runtime.version}#{build_suffix})"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns the device name for the required device.
|
159
|
+
#
|
160
|
+
# This name is used when passing the device name to the scan or snapshot.
|
161
|
+
def returning_device_name_for_required_device(required_device)
|
162
|
+
case device_naming_style
|
163
|
+
when DeviceNamingStyle::SCAN, DeviceNamingStyle::RUN_TESTS
|
164
|
+
# scan respects the runtime version in the devices list, so we need to return the full device name for the required device, otherwise the default SDK version will be used.
|
165
|
+
# E.g.:
|
166
|
+
# * given "iPhone 15 (17.0)" match will search for simulator named "iPhone 15" with the SDK version 17.0.
|
167
|
+
# * given "iPhone 15" match will search for simulator named "iPhone 15" with the default SDK version.
|
168
|
+
# So we need to return the device name and the required runtime version for scan to find the correct device.
|
169
|
+
"#{required_device.simctl_device.name} (#{required_device.required_runtime.product_version})"
|
170
|
+
when DeviceNamingStyle::SNAPSHOT, DeviceNamingStyle::CAPTURE_IOS_SCREENSHOTS
|
171
|
+
# snapshot does not modify the device name when searching for a passed device name nor extracts the runtime version from the device name.
|
172
|
+
# E.g.:
|
173
|
+
# * given "iPhone 15 (17.0)" match will search for device named exactly "iPhone 15 (17.0)".
|
174
|
+
# * given "iPhone 15" match will search for device named exactly "iPhone 15" .
|
175
|
+
# So we need to return the full device name for the required device for snapshot to find the correct device.
|
176
|
+
required_device.simctl_device.name
|
177
|
+
end
|
96
178
|
end
|
97
179
|
|
98
180
|
def create_missing_devices(required_devices)
|
@@ -109,7 +191,7 @@ module Fastlane
|
|
109
191
|
UI.message('Creating missing devices')
|
110
192
|
missing_devices.each do |missing_device|
|
111
193
|
shell_helper.create_device(
|
112
|
-
missing_device
|
194
|
+
device_name_for_required_device(missing_device),
|
113
195
|
missing_device.device_type.identifier,
|
114
196
|
missing_device.simctl_runtime.identifier
|
115
197
|
)
|
data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/runtime_helper.rb
CHANGED
@@ -50,7 +50,7 @@ module Fastlane
|
|
50
50
|
end
|
51
51
|
|
52
52
|
missing_runtimes.each do |missing_runtime|
|
53
|
-
download_and_install_missing_runtime(missing_runtime)
|
53
|
+
download_and_install_missing_runtime(missing_runtime, remove_cached_runtimes: remove_cached_runtimes)
|
54
54
|
end
|
55
55
|
|
56
56
|
# Update simctl_runtimes after installing the runtimes.
|
@@ -128,7 +128,7 @@ module Fastlane
|
|
128
128
|
simctl_runtime
|
129
129
|
end
|
130
130
|
|
131
|
-
def download_and_install_missing_runtime(missing_runtime)
|
131
|
+
def download_and_install_missing_runtime(missing_runtime, remove_cached_runtimes:)
|
132
132
|
UI.message("Attempting to install #{missing_runtime.runtime_name} runtime.")
|
133
133
|
|
134
134
|
downloaded_runtime_file = cached_runtime_file(missing_runtime)
|
@@ -139,6 +139,8 @@ module Fastlane
|
|
139
139
|
end
|
140
140
|
|
141
141
|
shell_helper.import_runtime(downloaded_runtime_file, missing_runtime.runtime_name)
|
142
|
+
|
143
|
+
FileUtils.rm_rf(downloaded_runtime_file) if remove_cached_runtimes
|
142
144
|
end
|
143
145
|
|
144
146
|
def runtime_build_version_for_filename(filename)
|
@@ -161,7 +163,12 @@ module Fastlane
|
|
161
163
|
# shipped with Xcode betas and use the same product version.
|
162
164
|
# E.g. Xcode 26.0 Beta 3 has iOS 26.0 (23A5287e) SDK, but
|
163
165
|
# xcodebuild downloads iphonesimulator_26.0_23A5287g.dmg as latest.
|
164
|
-
|
166
|
+
product_build_version = missing_runtime.product_build_version
|
167
|
+
if product_build_version
|
168
|
+
runtime_dmg_search_pattern += product_build_version.major.to_s
|
169
|
+
runtime_dmg_search_pattern += product_build_version.minor.to_s
|
170
|
+
runtime_dmg_search_pattern += product_build_version.patch.to_s
|
171
|
+
end
|
165
172
|
runtime_dmg_search_pattern += '*.dmg'
|
166
173
|
|
167
174
|
if verbose
|
data/lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/shell_helper.rb
CHANGED
@@ -66,7 +66,7 @@ module Fastlane
|
|
66
66
|
@simctl_device_types
|
67
67
|
end
|
68
68
|
|
69
|
-
def delete_device(udid)
|
69
|
+
def delete_device(udid:)
|
70
70
|
UI.message("Deleting device #{udid}...")
|
71
71
|
sh(command: "xcrun simctl delete #{udid.shellescape}")
|
72
72
|
end
|
@@ -130,6 +130,11 @@ module Fastlane
|
|
130
130
|
sh(command: "xcrun simctl create #{name.shellescape} #{device_type_identifier.shellescape} #{runtime_identifier.shellescape}")
|
131
131
|
end
|
132
132
|
|
133
|
+
def rename_device(udid:, name:)
|
134
|
+
UI.message("Renaming device with udid #{udid} to #{name}")
|
135
|
+
sh(command: "xcrun simctl rename #{udid.shellescape} #{name.shellescape}")
|
136
|
+
end
|
137
|
+
|
133
138
|
def delete_runtime(runtime_identifier)
|
134
139
|
UI.message("Deleting runtime #{runtime_identifier}...")
|
135
140
|
sh(command: "xcrun simctl runtime delete #{runtime_identifier.shellescape}")
|
@@ -150,8 +155,12 @@ module Fastlane
|
|
150
155
|
missing_runtime.os_name.shellescape
|
151
156
|
]
|
152
157
|
|
153
|
-
|
154
|
-
|
158
|
+
is_beta = missing_runtime.product_build_version.nil? ? false : missing_runtime.product_build_version.beta?
|
159
|
+
|
160
|
+
unless is_beta
|
161
|
+
command << '-buildVersion'
|
162
|
+
command << missing_runtime.product_version.to_s.shellescape
|
163
|
+
end
|
155
164
|
|
156
165
|
sh(command: command.join(' '), print_command: true, print_command_output: true)
|
157
166
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'module'
|
4
|
+
require 'fastlane'
|
5
|
+
require_relative 'shared_values'
|
6
|
+
require_relative '../create_simulator_devices/models/device_naming_style'
|
7
|
+
|
8
|
+
module Fastlane
|
9
|
+
# Gather simctl diagnose data.
|
10
|
+
module GatherSimctlDiagnose
|
11
|
+
# Does all the work to create simulator devices.
|
12
|
+
class Runner
|
13
|
+
UI = ::Fastlane::UI unless defined?(UI)
|
14
|
+
|
15
|
+
attr_accessor :shell_helper, :verbose, :runtime_helper, :device_naming_style, :create_simulator_devices_runner, :output_dir, :timeout, :include_all_device_logs, :include_booted_device_data_directory, :print_command, :print_command_output
|
16
|
+
|
17
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
18
|
+
runtime_helper:,
|
19
|
+
shell_helper:,
|
20
|
+
verbose:,
|
21
|
+
device_naming_style:,
|
22
|
+
create_simulator_devices_runner:,
|
23
|
+
output_dir:,
|
24
|
+
timeout:,
|
25
|
+
include_all_device_logs:,
|
26
|
+
include_booted_device_data_directory:
|
27
|
+
)
|
28
|
+
self.shell_helper = shell_helper
|
29
|
+
self.verbose = verbose
|
30
|
+
self.runtime_helper = runtime_helper
|
31
|
+
self.device_naming_style = device_naming_style
|
32
|
+
self.create_simulator_devices_runner = create_simulator_devices_runner
|
33
|
+
self.output_dir = output_dir
|
34
|
+
self.timeout = timeout
|
35
|
+
self.include_all_device_logs = include_all_device_logs
|
36
|
+
self.include_booted_device_data_directory = include_booted_device_data_directory
|
37
|
+
end
|
38
|
+
|
39
|
+
def run(devices) # rubocop:disable Metrics/AbcSize
|
40
|
+
UI.message("Simulator devices to gather diagnose data: #{devices.join(', ')}")
|
41
|
+
|
42
|
+
# Create distict required devices from a given list of device strings.
|
43
|
+
required_devices = devices
|
44
|
+
.filter_map { |device| create_simulator_devices_runner.required_device_for_device(device) }
|
45
|
+
.uniq { |required_device| [required_device.device_type.name, required_device.required_runtime.product_version] }
|
46
|
+
|
47
|
+
if verbose
|
48
|
+
UI.message('Unique required devices:')
|
49
|
+
UI.message(" #{required_devices.map(&:description).join("\n ")}")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return distinct matched devices strings
|
53
|
+
matched_devices = create_simulator_devices_runner.find_runtime_and_device_for_required_devices(required_devices)
|
54
|
+
.reject { |required_device| required_device.simctl_device.nil? }
|
55
|
+
|
56
|
+
matched_devices_udids = matched_devices.map { |matched_device| matched_device.simctl_device.udid }
|
57
|
+
UI.message("Available simulator devices: #{matched_devices_udids.join(', ')}")
|
58
|
+
|
59
|
+
temp_output_dir = "#{File.expand_path(output_dir)}/simctl_diagnose_#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
60
|
+
|
61
|
+
diagnose_args = matched_devices_udids.map { |udid| "--udid=#{udid}" }
|
62
|
+
diagnose_args << '-b' # Do NOT show the resulting archive in a Finder window upon completion.
|
63
|
+
diagnose_args << '--all-logs' if include_all_device_logs
|
64
|
+
diagnose_args << '--data-container' if include_booted_device_data_directory
|
65
|
+
diagnose_args << "--timeout=#{timeout}"
|
66
|
+
|
67
|
+
cmd_args = diagnose_args.map(&:shellescape).join(' ')
|
68
|
+
|
69
|
+
collect_diagnose_data_script_path = File.expand_path("#{__dir__}/scripts/collect_simctl_diagnose_data.sh")
|
70
|
+
|
71
|
+
shell_helper.sh(
|
72
|
+
command: "SIMCTL_DIAGNOSE_OUTPUT_FOLDER=#{temp_output_dir.shellescape} #{collect_diagnose_data_script_path.shellescape} #{cmd_args}",
|
73
|
+
print_command: verbose,
|
74
|
+
print_command_output: verbose
|
75
|
+
)
|
76
|
+
|
77
|
+
archive_name = "#{temp_output_dir}.tar.gz"
|
78
|
+
Actions.lane_context[Actions::SharedValues::GATHER_SIMCTL_DIAGNOSE_OUTPUT_FILE] = archive_name
|
79
|
+
|
80
|
+
archive_name
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env expect
|
2
|
+
|
3
|
+
# Runs xcrun simctl diagnose with given parameters.
|
4
|
+
# xcrun simctl diagnose needs user to press ENTER which is not possible to do in non-interactive shell.
|
5
|
+
|
6
|
+
spawn xcrun simctl diagnose {*}$argv
|
7
|
+
expect -exact "Press ENTER to continue\r\n"
|
8
|
+
send -- "\r"
|
9
|
+
expect eof
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# Runs xcrun simctl diagnose with given parameters.
|
4
|
+
# Manages the output folder and the archive.
|
5
|
+
#
|
6
|
+
# When --data-container is passed simctl diagnose doesn't create archive,
|
7
|
+
# and w/o archive the artifacts step on CI hangs.
|
8
|
+
#
|
9
|
+
# For this case we handle the archive creation manually.
|
10
|
+
|
11
|
+
set -Eeo pipefail
|
12
|
+
|
13
|
+
export SIMCTL_DIAGNOSE_OUTPUT_FOLDER="${SIMCTL_DIAGNOSE_OUTPUT_FOLDER:-"logs/simctl_diagnose"}"
|
14
|
+
|
15
|
+
FOLDER_NAME="$(basename "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}")"
|
16
|
+
OUTPUT_FOLDER_PATH="$(dirname "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}")"
|
17
|
+
|
18
|
+
echo "Cleaning up previous simctl logs at ${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}"
|
19
|
+
rm -rf "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}" || true
|
20
|
+
rm -rf "${OUTPUT_FOLDER_PATH}/${FOLDER_NAME}."* || true
|
21
|
+
mkdir -p "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}"
|
22
|
+
|
23
|
+
echo "Collecting simctl logs to ${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}..."
|
24
|
+
"$(dirname "${0}")/$(basename "${0}" .sh).expect" "${@}" --output="${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}"
|
25
|
+
|
26
|
+
if [ -d "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}" ]; then
|
27
|
+
echo "Compressing simctl logs to ${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}.tar.gz..."
|
28
|
+
cd "${OUTPUT_FOLDER_PATH}"
|
29
|
+
tar -czf "${FOLDER_NAME}.tar.gz" "${FOLDER_NAME}"
|
30
|
+
echo "Removing folder ${FOLDER_NAME}"
|
31
|
+
# Remove folder becuse it contains symlinks and zip doesn't remove them and tar doesn't remove it at all.
|
32
|
+
rm -rf "${FOLDER_NAME}" || true
|
33
|
+
echo "Archive size: $(du -h "${FOLDER_NAME}.tar.gz" | cut -f1)"
|
34
|
+
elif [ -f "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}.zip" ]; then
|
35
|
+
echo "Archive size: $(du -h "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}.zip" | cut -f1)"
|
36
|
+
elif [ -f "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}.tar.gz" ]; then
|
37
|
+
echo "Archive size: $(du -h "${SIMCTL_DIAGNOSE_OUTPUT_FOLDER}.tar.gz" | cut -f1)"
|
38
|
+
fi
|
39
|
+
|
40
|
+
echo "Simctl logs collected successfully at $OUTPUT_FOLDER_PATH"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-create_simulator_devices
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vitalii Budnik
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: developers@setapp.com
|
@@ -20,8 +20,10 @@ files:
|
|
20
20
|
- README.md
|
21
21
|
- lib/fastlane/plugin/create_simulator_devices.rb
|
22
22
|
- lib/fastlane/plugin/create_simulator_devices/actions/create_simulator_devices_action.rb
|
23
|
+
- lib/fastlane/plugin/create_simulator_devices/actions/gather_simctl_diagnose_action.rb
|
23
24
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models.rb
|
24
25
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/apple_build_version.rb
|
26
|
+
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/device_naming_style.rb
|
25
27
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/required_device.rb
|
26
28
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/required_runtime.rb
|
27
29
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/models/simctl/device.rb
|
@@ -33,6 +35,11 @@ files:
|
|
33
35
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/runtime_helper.rb
|
34
36
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/shared_values.rb
|
35
37
|
- lib/fastlane/plugin/create_simulator_devices/helpers/create_simulator_devices/shell_helper.rb
|
38
|
+
- lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/module.rb
|
39
|
+
- lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/runner.rb
|
40
|
+
- lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/scripts/collect_simctl_diagnose_data.expect
|
41
|
+
- lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/scripts/collect_simctl_diagnose_data.sh
|
42
|
+
- lib/fastlane/plugin/create_simulator_devices/helpers/gather_simctl_diagnose/shared_values.rb
|
36
43
|
- lib/fastlane/plugin/create_simulator_devices/version.rb
|
37
44
|
homepage:
|
38
45
|
licenses:
|