simctl 1.6.2 → 1.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +80 -0
- data/.travis.yml +5 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +20 -3
- data/README.md +3 -3
- data/fastlane-plugin-simctl/.gitignore +11 -0
- data/fastlane-plugin-simctl/.rspec +3 -0
- data/fastlane-plugin-simctl/.rubocop.yml +263 -0
- data/fastlane-plugin-simctl/Gemfile +6 -0
- data/fastlane-plugin-simctl/README.md +46 -0
- data/fastlane-plugin-simctl/Rakefile +9 -0
- data/fastlane-plugin-simctl/fastlane-plugin-simctl.gemspec +29 -0
- data/fastlane-plugin-simctl/fastlane/Fastfile +9 -0
- data/fastlane-plugin-simctl/fastlane/Pluginfile +1 -0
- data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl.rb +16 -0
- data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl/actions/simctl_action.rb +51 -0
- data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl/helper/simctl_helper.rb +52 -0
- data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl/version.rb +5 -0
- data/fastlane-plugin-simctl/spec/simctl_action_spec.rb +4 -0
- data/fastlane-plugin-simctl/spec/spec_helper.rb +15 -0
- data/lib/simctl.rb +1 -1
- data/lib/simctl/command/create.rb +3 -2
- data/lib/simctl/command/delete.rb +1 -1
- data/lib/simctl/command/erase.rb +0 -2
- data/lib/simctl/command/io.rb +3 -3
- data/lib/simctl/command/launch.rb +6 -6
- data/lib/simctl/command/list.rb +8 -6
- data/lib/simctl/command/reset.rb +2 -2
- data/lib/simctl/command/spawn.rb +4 -2
- data/lib/simctl/command/terminate.rb +4 -4
- data/lib/simctl/command/warmup.rb +3 -3
- data/lib/simctl/device.rb +14 -14
- data/lib/simctl/device_launchctl.rb +3 -3
- data/lib/simctl/device_path.rb +18 -7
- data/lib/simctl/device_settings.rb +5 -5
- data/lib/simctl/device_type.rb +1 -1
- data/lib/simctl/executor.rb +3 -3
- data/lib/simctl/list.rb +6 -6
- data/lib/simctl/object.rb +1 -1
- data/lib/simctl/runtime.rb +2 -2
- data/lib/simctl/version.rb +1 -1
- data/lib/simctl/xcode/path.rb +10 -4
- data/lib/simctl/xcode/version.rb +3 -3
- data/simctl.gemspec +3 -1
- data/spec/simctl/device_interaction_spec.rb +11 -11
- data/spec/simctl/executor_spec.rb +1 -1
- data/spec/simctl/list_spec.rb +6 -2
- data/spec/simctl/readme_spec.rb +5 -5
- data/spec/simctl/warmup_spec.rb +1 -1
- data/spec/spec_helper.rb +9 -13
- metadata +33 -2
@@ -0,0 +1,46 @@
|
|
1
|
+
# fastlane-plugin-simctl
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
|
5
|
+
This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-simctl`, add it to your project by running:
|
6
|
+
|
7
|
+
```bash
|
8
|
+
fastlane add_plugin simctl
|
9
|
+
```
|
10
|
+
|
11
|
+
## About fastlane-plugin-simctl
|
12
|
+
|
13
|
+
Fastlane plugin to interact with xcrun simctl. Manage your iOS Simulators directly from your Fastfile.
|
14
|
+
|
15
|
+
## Example
|
16
|
+
|
17
|
+
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`.
|
18
|
+
|
19
|
+
## Run tests for this plugin
|
20
|
+
|
21
|
+
To run both the tests, and code style validation, run
|
22
|
+
|
23
|
+
```
|
24
|
+
rake
|
25
|
+
```
|
26
|
+
|
27
|
+
To automatically fix many of the styling issues, use
|
28
|
+
```
|
29
|
+
rubocop -a
|
30
|
+
```
|
31
|
+
|
32
|
+
## Issues and Feedback
|
33
|
+
|
34
|
+
For any other issues and feedback about this plugin, please submit it to this repository.
|
35
|
+
|
36
|
+
## Troubleshooting
|
37
|
+
|
38
|
+
If you have trouble using plugins, check out the [Plugins Troubleshooting](https://docs.fastlane.tools/plugins/plugins-troubleshooting/) guide.
|
39
|
+
|
40
|
+
## Using _fastlane_ Plugins
|
41
|
+
|
42
|
+
For more information about how the `fastlane` plugin system works, check out the [Plugins documentation](https://docs.fastlane.tools/plugins/create-plugin/).
|
43
|
+
|
44
|
+
## About _fastlane_
|
45
|
+
|
46
|
+
_fastlane_ is the easiest way to automate beta deployments and releases for your iOS and Android apps. To learn more, check out [fastlane.tools](https://fastlane.tools).
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'fastlane/plugin/simctl/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'fastlane-plugin-simctl'
|
9
|
+
spec.version = Fastlane::Simctl::VERSION
|
10
|
+
spec.author = 'Renzo Crisostomo'
|
11
|
+
spec.email = 'renzo.crisostomo@me.com'
|
12
|
+
|
13
|
+
spec.summary = 'Fastlane plugin to interact with xcrun simctl'
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = Dir["lib/**/*"] + %w(README.md)
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_dependency 'simctl', '~> 1.6.2'
|
21
|
+
|
22
|
+
spec.add_development_dependency 'pry'
|
23
|
+
spec.add_development_dependency 'bundler'
|
24
|
+
spec.add_development_dependency 'rspec'
|
25
|
+
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rubocop'
|
27
|
+
spec.add_development_dependency 'simplecov'
|
28
|
+
spec.add_development_dependency 'fastlane', '>= 2.53.1'
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# Autogenerated by fastlane
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'fastlane/plugin/simctl/version'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Simctl
|
5
|
+
# Return all .rb files inside the "actions" and "helper" directory
|
6
|
+
def self.all_classes
|
7
|
+
Dir[File.expand_path('**/{actions,helper}/*.rb', File.dirname(__FILE__))]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# By default we want to import all available actions and helpers
|
13
|
+
# A plugin can contain any number of actions and plugins
|
14
|
+
Fastlane::Simctl.all_classes.each do |current|
|
15
|
+
require current
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'simctl'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Actions
|
5
|
+
class SimctlAction < Action
|
6
|
+
def self.run(params)
|
7
|
+
Helper::SimctlHelper.execute_with_simulator_ready(self, params[:block], params[:runtime], params[:type], params[:name])
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.description
|
11
|
+
"Fastlane plugin to interact with xcrun simctl."
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.authors
|
15
|
+
["Renzo Crisostomo"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.details
|
19
|
+
"Fastlane plugin to interact with xcrun simctl. Manage your iOS Simulators directly from your Fastfile."
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.available_options
|
23
|
+
[
|
24
|
+
FastlaneCore::ConfigItem.new(key: :block,
|
25
|
+
description: "A Ruby block given to execute in the context of a Simulator ready",
|
26
|
+
optional: false,
|
27
|
+
type: Proc),
|
28
|
+
FastlaneCore::ConfigItem.new(key: :runtime,
|
29
|
+
description: "iOS Runtime used to create the simulator",
|
30
|
+
optional: true,
|
31
|
+
type: String,
|
32
|
+
default_value: 'latest'),
|
33
|
+
FastlaneCore::ConfigItem.new(key: :type,
|
34
|
+
description: "iOS device type used to create the simulator",
|
35
|
+
optional: true,
|
36
|
+
type: String,
|
37
|
+
default_value: 'iPhone 6'),
|
38
|
+
FastlaneCore::ConfigItem.new(key: :name,
|
39
|
+
description: "String used to set the name to the simulator",
|
40
|
+
optional: true,
|
41
|
+
type: String,
|
42
|
+
default_value: nil)
|
43
|
+
]
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.is_supported?(platform)
|
47
|
+
[:ios].include?(platform)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Helper
|
3
|
+
class SimctlHelper
|
4
|
+
def self.execute_with_simulator_ready(action, block, runtime, type, name)
|
5
|
+
device = create_device(runtime, type, name)
|
6
|
+
device.launch
|
7
|
+
device.wait(90) do |d|
|
8
|
+
Fastlane::UI.message("Waiting for simulator `#{d.name}` to be ready")
|
9
|
+
d.state == :booted && d.ready?
|
10
|
+
end
|
11
|
+
begin
|
12
|
+
block.call(action.other_action, device)
|
13
|
+
rescue StandardError => error
|
14
|
+
throw error
|
15
|
+
ensure
|
16
|
+
delete_device(device)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create_device(runtime, type, name)
|
21
|
+
runtime = if runtime.eql? 'latest'
|
22
|
+
SimCtl::Runtime.latest('ios')
|
23
|
+
else
|
24
|
+
SimCtl.runtime(name: runtime)
|
25
|
+
end
|
26
|
+
device_type = SimCtl.devicetype(name: type)
|
27
|
+
device_name = name
|
28
|
+
device_name ||= type.to_s.instance_eval do |obj|
|
29
|
+
obj += "-#{ENV['JOB_NAME']}" if ENV['JOB_NAME']
|
30
|
+
obj += "@#{ENV['BUILD_NUMBER']}" if ENV['BUILD_NUMBER']
|
31
|
+
obj
|
32
|
+
end
|
33
|
+
Fastlane::UI.message("Starting simulator with runtime: `#{runtime.name}`, device type: `#{device_type.name}`"\
|
34
|
+
" and device name: `#{device_name}`")
|
35
|
+
SimCtl.reset_device(device_name, device_type, runtime)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.delete_device(device)
|
39
|
+
if device.state != :shutdown
|
40
|
+
device.shutdown
|
41
|
+
device.kill
|
42
|
+
device.wait do |d|
|
43
|
+
Fastlane::UI.message("Waiting for simulator `#{d.name}` to be shutdown")
|
44
|
+
d.state == :shutdown
|
45
|
+
end
|
46
|
+
end
|
47
|
+
Fastlane::UI.message("Deleting simulator `#{device.name}`")
|
48
|
+
device.delete
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
|
5
|
+
# SimpleCov.minimum_coverage 95
|
6
|
+
SimpleCov.start
|
7
|
+
|
8
|
+
# This module is only used to check the environment is currently a testing env
|
9
|
+
module SpecHelper
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'fastlane' # to import the Action super class
|
13
|
+
require 'fastlane/plugin/simctl' # import the actual plugin
|
14
|
+
|
15
|
+
Fastlane.load_actions # load other actions (in case your plugin calls other actions or shared values)
|
data/lib/simctl.rb
CHANGED
@@ -14,10 +14,11 @@ module SimCtl
|
|
14
14
|
devicetype = devicetype(name: devicetype) unless devicetype.is_a?(DeviceType)
|
15
15
|
raise "Invalid runtime: #{runtime}" unless runtime.is_a?(Runtime)
|
16
16
|
raise "Invalid devicetype: #{devicetype}" unless devicetype.is_a?(DeviceType)
|
17
|
-
|
17
|
+
command = command_for('create', Shellwords.shellescape(name), devicetype.identifier, runtime.identifier)
|
18
|
+
device = Executor.execute(command) do |identifier|
|
18
19
|
device(udid: identifier)
|
19
20
|
end
|
20
|
-
device.wait {|d| d.state == :shutdown && File.
|
21
|
+
device.wait { |d| d.state == :shutdown && File.exist?(d.path.device_plist) }
|
21
22
|
device
|
22
23
|
end
|
23
24
|
end
|
data/lib/simctl/command/erase.rb
CHANGED
data/lib/simctl/command/io.rb
CHANGED
@@ -11,11 +11,11 @@ module SimCtl
|
|
11
11
|
# * type: Can be png, tiff, bmp, gif, jpeg (default is png)
|
12
12
|
# * display: Can be main or tv for iOS, tv for tvOS and main for watchOS
|
13
13
|
# @return [void]
|
14
|
-
def screenshot(device, file, opts={})
|
14
|
+
def screenshot(device, file, opts = {})
|
15
15
|
unless Xcode::Version.gte? '8.2'
|
16
|
-
raise UnsupportedCommandError
|
16
|
+
raise UnsupportedCommandError, 'Needs at least Xcode 8.2'
|
17
17
|
end
|
18
|
-
optional_args = opts.map {|k,v| "--#{k}=#{Shellwords.shellescape(v)}"}
|
18
|
+
optional_args = opts.map { |k, v| "--#{k}=#{Shellwords.shellescape(v)}" }
|
19
19
|
Executor.execute(command_for('io', device.udid, 'screenshot', *optional_args, Shellwords.shellescape(file)))
|
20
20
|
end
|
21
21
|
end
|
@@ -3,13 +3,13 @@ require 'shellwords'
|
|
3
3
|
module SimCtl
|
4
4
|
class Command
|
5
5
|
module Launch
|
6
|
-
SUPPORTED_SCALE = [1.0, 0.75, 0.5, 0.25]
|
6
|
+
SUPPORTED_SCALE = [1.0, 0.75, 0.5, 0.25].freeze
|
7
7
|
|
8
8
|
# Launches a Simulator instance with the given device
|
9
9
|
#
|
10
10
|
# @param device [SimCtl::Device] the device to launch
|
11
11
|
# @return [void]
|
12
|
-
def launch_device(device, scale=1.0, opts={})
|
12
|
+
def launch_device(device, scale = 1.0, opts = {})
|
13
13
|
raise "unsupported scale '#{scale}' (supported: #{SUPPORTED_SCALE.join(', ')})" unless SUPPORTED_SCALE.include?(scale)
|
14
14
|
# Launching the same device twice does not work.
|
15
15
|
# Simulator.app would just hang. Solution: Kill first.
|
@@ -17,9 +17,9 @@ module SimCtl
|
|
17
17
|
args = {
|
18
18
|
'-ConnectHardwareKeyboard' => 1,
|
19
19
|
'-CurrentDeviceUDID' => device.udid,
|
20
|
-
"-SimulatorWindowLastScale-#{device.devicetype.identifier}" => scale
|
20
|
+
"-SimulatorWindowLastScale-#{device.devicetype.identifier}" => scale
|
21
21
|
}
|
22
|
-
args
|
22
|
+
args['-DeviceSetPath'] = Shellwords.shellescape(SimCtl.device_set_path) unless SimCtl.device_set_path.nil?
|
23
23
|
args = args.merge(opts).zip.flatten.join(' ')
|
24
24
|
command = "open -Fgn #{Xcode::Path.home}/Applications/Simulator.app --args #{args}"
|
25
25
|
system command
|
@@ -32,8 +32,8 @@ module SimCtl
|
|
32
32
|
# @param identifier [String] the app identifier
|
33
33
|
# @param args [Array] optional launch arguments
|
34
34
|
# @return [void]
|
35
|
-
def launch_app(device, identifier, args=[], opts={})
|
36
|
-
launch_args = args.map {|arg| Shellwords.shellescape arg}
|
35
|
+
def launch_app(device, identifier, args = [], opts = {})
|
36
|
+
launch_args = args.map { |arg| Shellwords.shellescape arg }
|
37
37
|
launch_opts = opts[:wait_for_debugger] ? '-w' : ''
|
38
38
|
Executor.execute(command_for('launch', launch_opts, device.udid, identifier, launch_args))
|
39
39
|
end
|
data/lib/simctl/command/list.rb
CHANGED
@@ -15,7 +15,8 @@ module SimCtl
|
|
15
15
|
# @return [SimCtl::DeviceType] the device type matching the given filter
|
16
16
|
# @raise [DeviceTypeNotFound] if the device type could not be found
|
17
17
|
def devicetype(filter)
|
18
|
-
list_devicetypes.where(filter).first
|
18
|
+
device_type = list_devicetypes.where(filter).first
|
19
|
+
device_type || raise(DeviceTypeNotFound, "Could not find a device type matching #{filter.inspect}")
|
19
20
|
end
|
20
21
|
|
21
22
|
# List all devices
|
@@ -23,7 +24,8 @@ module SimCtl
|
|
23
24
|
# @return [SimCtl::List] a list of SimCtl::Device objects
|
24
25
|
def list_devices
|
25
26
|
Executor.execute(command_for('list', '-j', 'devices')) do |json|
|
26
|
-
|
27
|
+
devices = json['devices'].map { |os, devs| devs.map { |device| Device.new(device.merge(os: os)) } }
|
28
|
+
SimCtl::List.new(devices.flatten)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -32,7 +34,7 @@ module SimCtl
|
|
32
34
|
# @return [SimCtl::List] a list of SimCtl::DeviceType objects
|
33
35
|
def list_devicetypes
|
34
36
|
Executor.execute(command_for('list', '-j', 'devicetypes')) do |json|
|
35
|
-
SimCtl::List.new(json['devicetypes'].map {|devicetype| DeviceType.new(devicetype)})
|
37
|
+
SimCtl::List.new(json['devicetypes'].map { |devicetype| DeviceType.new(devicetype) })
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -41,7 +43,7 @@ module SimCtl
|
|
41
43
|
# @return [SimCtl::List] a list of SimCtl::Runtime objects
|
42
44
|
def list_runtimes
|
43
45
|
Executor.execute(command_for('list', '-j', 'runtimes')) do |json|
|
44
|
-
SimCtl::List.new(json['runtimes'].map {|runtime| Runtime.new(runtime)})
|
46
|
+
SimCtl::List.new(json['runtimes'].map { |runtime| Runtime.new(runtime) })
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
@@ -51,9 +53,9 @@ module SimCtl
|
|
51
53
|
# @return [SimCtl::Runtime] the runtime matching the given filter
|
52
54
|
# @raise [RuntimeNotFound] if the runtime could not be found
|
53
55
|
def runtime(filter)
|
54
|
-
list_runtimes.where(filter).first
|
56
|
+
runtime = list_runtimes.where(filter).first
|
57
|
+
runtime || raise(RuntimeNotFound, "Could not find a runtime matching #{filter.inspect}")
|
55
58
|
end
|
56
|
-
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
data/lib/simctl/command/reset.rb
CHANGED
@@ -13,14 +13,14 @@ module SimCtl
|
|
13
13
|
list_devices.where(name: name, os: runtime.name).each do |device|
|
14
14
|
device.kill
|
15
15
|
device.shutdown if device.state != :shutdown
|
16
|
-
device.wait {|d| d.state == :shutdown}
|
16
|
+
device.wait { |d| d.state == :shutdown }
|
17
17
|
device.delete
|
18
18
|
end
|
19
19
|
rescue Exception => exception
|
20
20
|
yield exception if block_given?
|
21
21
|
end
|
22
22
|
device = create_device name, device_type, runtime
|
23
|
-
device.wait {|d| d.state == :shutdown}
|
23
|
+
device.wait { |d| d.state == :shutdown }
|
24
24
|
device
|
25
25
|
end
|
26
26
|
end
|
data/lib/simctl/command/spawn.rb
CHANGED
@@ -9,8 +9,10 @@ module SimCtl
|
|
9
9
|
# @param path [String] path to executable
|
10
10
|
# @param args [Array] arguments for the executable
|
11
11
|
# @return [String] standard output the spawned process generated
|
12
|
-
def spawn(device, path, args=[],
|
13
|
-
|
12
|
+
def spawn(device, path, args = [], _opts = {})
|
13
|
+
escaped_path = Shellwords.shellescape(path)
|
14
|
+
command = command_for('spawn', device.udid, escaped_path, *args.map { |a| Shellwords.shellwords(a) })
|
15
|
+
Executor.execute(command) do |output|
|
14
16
|
output
|
15
17
|
end
|
16
18
|
end
|
@@ -9,13 +9,13 @@ module SimCtl
|
|
9
9
|
# @param identifier [String] the app identifier
|
10
10
|
# @param args [Array] optional terminate arguments
|
11
11
|
# @return [void]
|
12
|
-
def terminate_app(device, identifier, args=[])
|
12
|
+
def terminate_app(device, identifier, args = [])
|
13
13
|
unless Xcode::Version.gte? '8.2'
|
14
|
-
raise UnsupportedCommandError
|
14
|
+
raise UnsupportedCommandError, 'Needs at least Xcode 8.2'
|
15
15
|
end
|
16
|
-
terminate_args = args.map {|arg| Shellwords.shellescape arg}
|
16
|
+
terminate_args = args.map { |arg| Shellwords.shellescape arg }
|
17
17
|
Executor.execute(command_for('terminate', terminate_args, device.udid, identifier))
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|