simctl 1.6.2 → 1.6.3

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +80 -0
  4. data/.travis.yml +5 -4
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile.lock +20 -3
  7. data/README.md +3 -3
  8. data/fastlane-plugin-simctl/.gitignore +11 -0
  9. data/fastlane-plugin-simctl/.rspec +3 -0
  10. data/fastlane-plugin-simctl/.rubocop.yml +263 -0
  11. data/fastlane-plugin-simctl/Gemfile +6 -0
  12. data/fastlane-plugin-simctl/README.md +46 -0
  13. data/fastlane-plugin-simctl/Rakefile +9 -0
  14. data/fastlane-plugin-simctl/fastlane-plugin-simctl.gemspec +29 -0
  15. data/fastlane-plugin-simctl/fastlane/Fastfile +9 -0
  16. data/fastlane-plugin-simctl/fastlane/Pluginfile +1 -0
  17. data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl.rb +16 -0
  18. data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl/actions/simctl_action.rb +51 -0
  19. data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl/helper/simctl_helper.rb +52 -0
  20. data/fastlane-plugin-simctl/lib/fastlane/plugin/simctl/version.rb +5 -0
  21. data/fastlane-plugin-simctl/spec/simctl_action_spec.rb +4 -0
  22. data/fastlane-plugin-simctl/spec/spec_helper.rb +15 -0
  23. data/lib/simctl.rb +1 -1
  24. data/lib/simctl/command/create.rb +3 -2
  25. data/lib/simctl/command/delete.rb +1 -1
  26. data/lib/simctl/command/erase.rb +0 -2
  27. data/lib/simctl/command/io.rb +3 -3
  28. data/lib/simctl/command/launch.rb +6 -6
  29. data/lib/simctl/command/list.rb +8 -6
  30. data/lib/simctl/command/reset.rb +2 -2
  31. data/lib/simctl/command/spawn.rb +4 -2
  32. data/lib/simctl/command/terminate.rb +4 -4
  33. data/lib/simctl/command/warmup.rb +3 -3
  34. data/lib/simctl/device.rb +14 -14
  35. data/lib/simctl/device_launchctl.rb +3 -3
  36. data/lib/simctl/device_path.rb +18 -7
  37. data/lib/simctl/device_settings.rb +5 -5
  38. data/lib/simctl/device_type.rb +1 -1
  39. data/lib/simctl/executor.rb +3 -3
  40. data/lib/simctl/list.rb +6 -6
  41. data/lib/simctl/object.rb +1 -1
  42. data/lib/simctl/runtime.rb +2 -2
  43. data/lib/simctl/version.rb +1 -1
  44. data/lib/simctl/xcode/path.rb +10 -4
  45. data/lib/simctl/xcode/version.rb +3 -3
  46. data/simctl.gemspec +3 -1
  47. data/spec/simctl/device_interaction_spec.rb +11 -11
  48. data/spec/simctl/executor_spec.rb +1 -1
  49. data/spec/simctl/list_spec.rb +6 -2
  50. data/spec/simctl/readme_spec.rb +5 -5
  51. data/spec/simctl/warmup_spec.rb +1 -1
  52. data/spec/spec_helper.rb +9 -13
  53. metadata +33 -2
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
6
+ eval_gemfile(plugins_path) if File.exist?(plugins_path)
@@ -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,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new
5
+
6
+ require 'rubocop/rake_task'
7
+ RuboCop::RakeTask.new(:rubocop)
8
+
9
+ task default: [:spec, :rubocop]
@@ -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,9 @@
1
+ lane :test do
2
+ simctl(block: lambda { |other_action, device|
3
+ other_action.scan(workspace: "#{Dir.pwd}/AwesomeApp.xcworkspace",
4
+ scheme: 'AwesomeApp',
5
+ device: device.name,
6
+ derived_data_path: derived_data_path)
7
+ })
8
+ trainer(output_directory: ".")
9
+ 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,5 @@
1
+ module Fastlane
2
+ module Simctl
3
+ VERSION = "0.2.0"
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ describe Fastlane::Actions::SimctlAction do
2
+ describe '#run' do
3
+ end
4
+ 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)
@@ -30,7 +30,7 @@ module SimCtl
30
30
 
31
31
  private
32
32
 
33
- def respond_to_missing?(method_name, include_private=false)
33
+ def respond_to_missing?(method_name, include_private = false)
34
34
  command.respond_to?(method_name, include_private)
35
35
  end
36
36
 
@@ -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
- device = Executor.execute(command_for('create', Shellwords.shellescape(name), devicetype.identifier, runtime.identifier)) do |identifier|
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.exists?(d.path.device_plist)}
21
+ device.wait { |d| d.state == :shutdown && File.exist?(d.path.device_plist) }
21
22
  device
22
23
  end
23
24
  end
@@ -16,7 +16,7 @@ module SimCtl
16
16
  list_devices.each do |device|
17
17
  device.kill
18
18
  device.shutdown if device.state != :shutdown
19
- device.wait {|d| d.state == :shutdown}
19
+ device.wait { |d| d.state == :shutdown }
20
20
  device.delete
21
21
  end
22
22
  end
@@ -11,5 +11,3 @@ module SimCtl
11
11
  end
12
12
  end
13
13
  end
14
-
15
-
@@ -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.new('Needs at least Xcode 8.2')
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.merge!({ '-DeviceSetPath' => Shellwords.shellescape(SimCtl.device_set_path) }) unless SimCtl.device_set_path.nil?
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
@@ -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 or raise DeviceTypeNotFound.new("Could not find a device type matching #{filter.inspect}")
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
- SimCtl::List.new(json['devices'].map {|os, devices| devices.map {|device| Device.new(device.merge(os: os))}}.flatten)
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 or raise RuntimeNotFound.new("Could not find a runtime matching #{filter.inspect}")
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
@@ -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
@@ -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=[], opts={})
13
- Executor.execute(command_for('spawn', device.udid, Shellwords.shellescape(path), *args.map{|a| Shellwords.shellwords(a)})) do |output|
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.new('Needs at least Xcode 8.2')
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