fastlane 2.149.1 → 2.150.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/deliver/lib/deliver.rb +0 -1
  3. data/deliver/lib/deliver/app_screenshot.rb +26 -25
  4. data/deliver/lib/deliver/options.rb +6 -11
  5. data/deliver/lib/deliver/runner.rb +7 -4
  6. data/deliver/lib/deliver/setup.rb +5 -30
  7. data/deliver/lib/deliver/submit_for_review.rb +124 -87
  8. data/deliver/lib/deliver/upload_metadata.rb +284 -143
  9. data/deliver/lib/deliver/upload_price_tier.rb +15 -8
  10. data/deliver/lib/deliver/upload_screenshots.rb +86 -37
  11. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +1 -1
  12. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +3 -11
  13. data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +3 -2
  14. data/fastlane/lib/fastlane/actions/download_dsyms.rb +7 -1
  15. data/fastlane/lib/fastlane/actions/google_play_track_release_names.rb +74 -0
  16. data/fastlane/lib/fastlane/actions/slack.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/spm.rb +7 -0
  18. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +1 -32
  19. data/fastlane/lib/fastlane/lane.rb +3 -3
  20. data/fastlane/lib/fastlane/swift_fastlane_function.rb +8 -4
  21. data/fastlane/lib/fastlane/version.rb +1 -1
  22. data/fastlane/swift/ControlCommand.swift +1 -0
  23. data/fastlane/swift/Fastlane.swift +48 -12
  24. data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/xcshareddata/xcschemes/FastlaneRunner.xcscheme +3 -9
  25. data/fastlane/swift/LaneFileProtocol.swift +2 -5
  26. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  27. data/fastlane/swift/RubyCommand.swift +29 -6
  28. data/fastlane/swift/RubyCommandable.swift +1 -0
  29. data/fastlane/swift/Runner.swift +85 -13
  30. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  31. data/fastlane/swift/SnapshotfileProtocol.swift +3 -3
  32. data/fastlane/swift/SocketClient.swift +76 -45
  33. data/fastlane/swift/SocketClientDelegateProtocol.swift +1 -1
  34. data/fastlane/swift/SocketResponse.swift +1 -0
  35. data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +1 -3
  36. data/fastlane_core/lib/fastlane_core/pkg_file_analyser.rb +7 -0
  37. data/frameit/lib/frameit/device_types.rb +100 -100
  38. data/produce/lib/produce/itunes_connect.rb +20 -20
  39. data/produce/lib/produce/options.rb +3 -3
  40. data/sigh/lib/assets/resign.sh +7 -7
  41. data/snapshot/lib/assets/SnapshotHelper.swift +5 -5
  42. data/snapshot/lib/assets/SnapshotHelperXcode8.swift +3 -3
  43. data/snapshot/lib/snapshot/options.rb +0 -1
  44. data/snapshot/lib/snapshot/reports_generator.rb +8 -1
  45. data/spaceship/lib/spaceship/.DS_Store +0 -0
  46. data/spaceship/lib/spaceship/connect_api.rb +21 -2
  47. data/spaceship/lib/spaceship/connect_api/client.rb +47 -11
  48. data/spaceship/lib/spaceship/connect_api/model.rb +1 -1
  49. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +109 -0
  50. data/spaceship/lib/spaceship/connect_api/models/app.rb +113 -3
  51. data/spaceship/lib/spaceship/connect_api/models/app_category.rb +94 -0
  52. data/spaceship/lib/spaceship/connect_api/models/app_info.rb +74 -0
  53. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +38 -0
  54. data/spaceship/lib/spaceship/connect_api/models/app_price.rb +22 -0
  55. data/spaceship/lib/spaceship/connect_api/models/app_price_tier.rb +12 -0
  56. data/spaceship/lib/spaceship/connect_api/models/app_review_attachment.rb +81 -0
  57. data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +117 -0
  58. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +101 -0
  59. data/spaceship/lib/spaceship/connect_api/models/app_store_review_detail.rb +51 -0
  60. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +182 -0
  61. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +70 -0
  62. data/spaceship/lib/spaceship/connect_api/models/app_store_version_phased_release.rb +36 -0
  63. data/spaceship/lib/spaceship/connect_api/models/app_store_version_submission.rb +26 -0
  64. data/spaceship/lib/spaceship/connect_api/models/build.rb +4 -0
  65. data/spaceship/lib/spaceship/connect_api/models/idfa_declaration.rb +40 -0
  66. data/spaceship/lib/spaceship/connect_api/models/reset_ratings_request.rb +26 -0
  67. data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +10 -3
  68. data/spaceship/lib/spaceship/connect_api/tunes/client.rb +33 -0
  69. data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +703 -0
  70. data/spaceship/lib/spaceship/spaceauth_runner.rb +2 -2
  71. data/supply/lib/supply/client.rb +19 -0
  72. data/supply/lib/supply/reader.rb +16 -0
  73. metadata +27 -24
  74. data/deliver/lib/deliver/upload_assets.rb +0 -27
  75. data/scan/lib/scan/.test_command_generator.rb.swp +0 -0
  76. data/snapshot/lib/snapshot/.test_command_generator_base.rb.swp +0 -0
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
- VERSION = '2.149.1'.freeze
2
+ VERSION = '2.150.0.rc1'.freeze
3
3
  DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
4
4
  MINIMUM_XCODE_RELEASE = "7.0".freeze
5
5
  RUBOCOP_REQUIREMENT = '0.49.1'.freeze
@@ -49,6 +49,7 @@ struct ControlCommand: RubyCommandable {
49
49
  }
50
50
 
51
51
  let message: String?
52
+ let id: String = UUID().uuidString
52
53
  let shutdownCommandType: ShutdownCommandType
53
54
  var commandJson: String {
54
55
  var jsonDictionary: [String: Any] = [ControlCommand.commandKey : self.shutdownCommandType.token]
@@ -1491,7 +1491,7 @@ func captureIosScreenshots(workspace: String? = nil,
1491
1491
  appIdentifier: String? = nil,
1492
1492
  addPhotos: [String]? = nil,
1493
1493
  addVideos: [String]? = nil,
1494
- htmlTemplate: String = "/Users/josh/Projects/fastlane/fastlane/snapshot/lib/snapshot/page.html.erb",
1494
+ htmlTemplate: String? = nil,
1495
1495
  buildlogPath: String = "~/Library/Logs/snapshot",
1496
1496
  clean: Bool = false,
1497
1497
  testWithoutBuilding: Bool? = nil,
@@ -1625,7 +1625,7 @@ func captureScreenshots(workspace: String? = nil,
1625
1625
  appIdentifier: String? = nil,
1626
1626
  addPhotos: [String]? = nil,
1627
1627
  addVideos: [String]? = nil,
1628
- htmlTemplate: String = "/Users/josh/Projects/fastlane/fastlane/snapshot/lib/snapshot/page.html.erb",
1628
+ htmlTemplate: String? = nil,
1629
1629
  buildlogPath: String = "~/Library/Logs/snapshot",
1630
1630
  clean: Bool = false,
1631
1631
  testWithoutBuilding: Bool? = nil,
@@ -2039,7 +2039,7 @@ func cocoapods(repoUpdate: Bool = false,
2039
2039
  ansi: Bool = true,
2040
2040
  useBundleExec: Bool = true,
2041
2041
  podfile: String? = nil,
2042
- errorCallback: Any? = nil,
2042
+ errorCallback: ((String) -> Void)? = nil,
2043
2043
  tryRepoUpdateOnError: Bool = false,
2044
2044
  deployment: Bool = false,
2045
2045
  clean: Bool = true,
@@ -2051,7 +2051,7 @@ func cocoapods(repoUpdate: Bool = false,
2051
2051
  RubyCommand.Argument(name: "ansi", value: ansi),
2052
2052
  RubyCommand.Argument(name: "use_bundle_exec", value: useBundleExec),
2053
2053
  RubyCommand.Argument(name: "podfile", value: podfile),
2054
- RubyCommand.Argument(name: "error_callback", value: errorCallback),
2054
+ RubyCommand.Argument(name: "error_callback", value: errorCallback, type: .stringClosure),
2055
2055
  RubyCommand.Argument(name: "try_repo_update_on_error", value: tryRepoUpdateOnError),
2056
2056
  RubyCommand.Argument(name: "deployment", value: deployment),
2057
2057
  RubyCommand.Argument(name: "clean", value: clean),
@@ -3054,7 +3054,7 @@ func frameScreenshots(white: Bool? = nil,
3054
3054
  useLegacyIphonexr: Bool = false,
3055
3055
  useLegacyIphonexs: Bool = false,
3056
3056
  useLegacyIphonexsmax: Bool = false,
3057
- forceOrientationBlock: String? = nil,
3057
+ forceOrientationBlock: ((String) -> Void)? = nil,
3058
3058
  debugMode: Bool = false,
3059
3059
  resume: Bool = false,
3060
3060
  usePlatform: String = "IOS",
@@ -3071,7 +3071,7 @@ func frameScreenshots(white: Bool? = nil,
3071
3071
  RubyCommand.Argument(name: "use_legacy_iphonexr", value: useLegacyIphonexr),
3072
3072
  RubyCommand.Argument(name: "use_legacy_iphonexs", value: useLegacyIphonexs),
3073
3073
  RubyCommand.Argument(name: "use_legacy_iphonexsmax", value: useLegacyIphonexsmax),
3074
- RubyCommand.Argument(name: "force_orientation_block", value: forceOrientationBlock),
3074
+ RubyCommand.Argument(name: "force_orientation_block", value: forceOrientationBlock, type: .stringClosure),
3075
3075
  RubyCommand.Argument(name: "debug_mode", value: debugMode),
3076
3076
  RubyCommand.Argument(name: "resume", value: resume),
3077
3077
  RubyCommand.Argument(name: "use_platform", value: usePlatform),
@@ -3116,7 +3116,7 @@ func frameit(white: Bool? = nil,
3116
3116
  useLegacyIphonexr: Bool = false,
3117
3117
  useLegacyIphonexs: Bool = false,
3118
3118
  useLegacyIphonexsmax: Bool = false,
3119
- forceOrientationBlock: String? = nil,
3119
+ forceOrientationBlock: ((String) -> Void)? = nil,
3120
3120
  debugMode: Bool = false,
3121
3121
  resume: Bool = false,
3122
3122
  usePlatform: String = "IOS",
@@ -3133,7 +3133,7 @@ func frameit(white: Bool? = nil,
3133
3133
  RubyCommand.Argument(name: "use_legacy_iphonexr", value: useLegacyIphonexr),
3134
3134
  RubyCommand.Argument(name: "use_legacy_iphonexs", value: useLegacyIphonexs),
3135
3135
  RubyCommand.Argument(name: "use_legacy_iphonexsmax", value: useLegacyIphonexsmax),
3136
- RubyCommand.Argument(name: "force_orientation_block", value: forceOrientationBlock),
3136
+ RubyCommand.Argument(name: "force_orientation_block", value: forceOrientationBlock, type: .stringClosure),
3137
3137
  RubyCommand.Argument(name: "debug_mode", value: debugMode),
3138
3138
  RubyCommand.Argument(name: "resume", value: resume),
3139
3139
  RubyCommand.Argument(name: "use_platform", value: usePlatform),
@@ -3639,6 +3639,42 @@ func githubApi(serverUrl: String = "https://api.github.com",
3639
3639
  _ = runner.executeCommand(command)
3640
3640
  }
3641
3641
 
3642
+ /**
3643
+ Retrieves release names for a Google Play track
3644
+
3645
+ - parameters:
3646
+ - packageName: The package name of the application to use
3647
+ - track: The track of the application to use. The default available tracks are: production, beta, alpha, internal
3648
+ - key: **DEPRECATED!** Use `--json_key` instead - The p12 File used to authenticate with Google
3649
+ - issuer: **DEPRECATED!** Use `--json_key` instead - The issuer of the p12 file (email address of the service account)
3650
+ - jsonKey: The path to a file containing service account JSON, used to authenticate with Google
3651
+ - jsonKeyData: The raw service account JSON data used to authenticate with Google
3652
+ - rootUrl: Root URL for the Google Play API. The provided URL will be used for API calls in place of https://www.googleapis.com/
3653
+ - timeout: Timeout for read, open, and send (in seconds)
3654
+
3655
+ - returns: Array of strings representing the release names for the given Google Play track
3656
+
3657
+ More information: [https://docs.fastlane.tools/actions/supply/](https://docs.fastlane.tools/actions/supply/)
3658
+ */
3659
+ func googlePlayTrackReleaseNames(packageName: String,
3660
+ track: String = "production",
3661
+ key: String? = nil,
3662
+ issuer: String? = nil,
3663
+ jsonKey: String? = nil,
3664
+ jsonKeyData: String? = nil,
3665
+ rootUrl: String? = nil,
3666
+ timeout: Int = 300) {
3667
+ let command = RubyCommand(commandID: "", methodName: "google_play_track_release_names", className: nil, args: [RubyCommand.Argument(name: "package_name", value: packageName),
3668
+ RubyCommand.Argument(name: "track", value: track),
3669
+ RubyCommand.Argument(name: "key", value: key),
3670
+ RubyCommand.Argument(name: "issuer", value: issuer),
3671
+ RubyCommand.Argument(name: "json_key", value: jsonKey),
3672
+ RubyCommand.Argument(name: "json_key_data", value: jsonKeyData),
3673
+ RubyCommand.Argument(name: "root_url", value: rootUrl),
3674
+ RubyCommand.Argument(name: "timeout", value: timeout)])
3675
+ _ = runner.executeCommand(command)
3676
+ }
3677
+
3642
3678
  /**
3643
3679
  Retrieves version codes for a Google Play track
3644
3680
 
@@ -6520,10 +6556,10 @@ func setupTravis(force: Bool = false) {
6520
6556
  */
6521
6557
  @discardableResult func sh(command: String,
6522
6558
  log: Bool = true,
6523
- errorCallback: Any? = nil) -> String {
6559
+ errorCallback: ((String) -> Void)? = nil) -> String {
6524
6560
  let command = RubyCommand(commandID: "", methodName: "sh", className: nil, args: [RubyCommand.Argument(name: "command", value: command),
6525
6561
  RubyCommand.Argument(name: "log", value: log),
6526
- RubyCommand.Argument(name: "error_callback", value: errorCallback)])
6562
+ RubyCommand.Argument(name: "error_callback", value: errorCallback, type: .stringClosure)])
6527
6563
  return runner.executeCommand(command)
6528
6564
  }
6529
6565
 
@@ -6868,7 +6904,7 @@ func snapshot(workspace: Any? = snapshotfile.workspace,
6868
6904
  appIdentifier: Any? = snapshotfile.appIdentifier,
6869
6905
  addPhotos: [String]? = snapshotfile.addPhotos,
6870
6906
  addVideos: [String]? = snapshotfile.addVideos,
6871
- htmlTemplate: Any = snapshotfile.htmlTemplate,
6907
+ htmlTemplate: Any? = snapshotfile.htmlTemplate,
6872
6908
  buildlogPath: Any = snapshotfile.buildlogPath,
6873
6909
  clean: Bool = snapshotfile.clean,
6874
6910
  testWithoutBuilding: Bool? = snapshotfile.testWithoutBuilding,
@@ -8924,4 +8960,4 @@ let snapshotfile: Snapshotfile = Snapshotfile()
8924
8960
 
8925
8961
  // Please don't remove the lines below
8926
8962
  // They are used to detect outdated files
8927
- // FastlaneRunnerAPIVersion [0.9.77]
8963
+ // FastlaneRunnerAPIVersion [0.9.71]
@@ -26,10 +26,7 @@
26
26
  buildConfiguration = "Debug"
27
27
  selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28
28
  selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29
- language = ""
30
29
  shouldUseLaunchSchemeArgsEnv = "YES">
31
- <Testables>
32
- </Testables>
33
30
  <MacroExpansion>
34
31
  <BuildableReference
35
32
  BuildableIdentifier = "primary"
@@ -39,14 +36,13 @@
39
36
  ReferencedContainer = "container:FastlaneSwiftRunner.xcodeproj">
40
37
  </BuildableReference>
41
38
  </MacroExpansion>
42
- <AdditionalOptions>
43
- </AdditionalOptions>
39
+ <Testables>
40
+ </Testables>
44
41
  </TestAction>
45
42
  <LaunchAction
46
43
  buildConfiguration = "Debug"
47
44
  selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
48
45
  selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
49
- language = ""
50
46
  launchStyle = "0"
51
47
  useCustomWorkingDirectory = "NO"
52
48
  ignoresPersistentStateOnLaunch = "NO"
@@ -65,7 +61,7 @@
65
61
  </BuildableProductRunnable>
66
62
  <CommandLineArguments>
67
63
  <CommandLineArgument
68
- argument = "lane test"
64
+ argument = "lane testLane"
69
65
  isEnabled = "YES">
70
66
  </CommandLineArgument>
71
67
  <CommandLineArgument
@@ -73,8 +69,6 @@
73
69
  isEnabled = "YES">
74
70
  </CommandLineArgument>
75
71
  </CommandLineArguments>
76
- <AdditionalOptions>
77
- </AdditionalOptions>
78
72
  </LaunchAction>
79
73
  <ProfileAction
80
74
  buildConfiguration = "Release"
@@ -19,7 +19,6 @@ public protocol LaneFileProtocol: class {
19
19
  static func runLane(named: String, parameters: [String : String]) -> Bool
20
20
 
21
21
  func recordLaneDescriptions()
22
- func beforeAll(currentLane: String, parameters: [String : String])
23
22
  func beforeAll()
24
23
  func afterAll(currentLane: String)
25
24
  func onError(currentLane: String, errorInfo: String)
@@ -27,7 +26,6 @@ public protocol LaneFileProtocol: class {
27
26
 
28
27
  public extension LaneFileProtocol {
29
28
  var fastlaneVersion: String { return "" } // default "" because that means any is fine
30
- func beforeAll(currentLane: String, parameters: [String : String]) { } // no op by default
31
29
  func beforeAll() { } // no op by default
32
30
  func afterAll(currentLane: String) { } // no op by default
33
31
  func onError(currentLane: String, errorInfo: String) {} // no op by default
@@ -39,8 +37,7 @@ public class LaneFile: NSObject, LaneFileProtocol {
39
37
  private(set) static var fastfileInstance: Fastfile?
40
38
 
41
39
  // Called before any lane is executed.
42
- private func setupAllTheThings(lane: String, parameters: [String : String]) {
43
- LaneFile.fastfileInstance!.beforeAll(currentLane: lane, parameters: parameters)
40
+ private func setupAllTheThings() {
44
41
  LaneFile.fastfileInstance!.beforeAll()
45
42
  }
46
43
 
@@ -126,7 +123,7 @@ public class LaneFile: NSObject, LaneFileProtocol {
126
123
  }
127
124
 
128
125
  // call all methods that need to be called before we start calling lanes
129
- fastfileInstance.setupAllTheThings(lane: named, parameters: parameters)
126
+ fastfileInstance.setupAllTheThings()
130
127
 
131
128
  // We need to catch all possible errors here and display a nice message
132
129
  _ = fastfileInstance.perform(NSSelectorFromString(laneMethod), with: parameters)
@@ -154,4 +154,4 @@ extension MatchfileProtocol {
154
154
 
155
155
  // Please don't remove the lines below
156
156
  // They are used to detect outdated files
157
- // FastlaneRunnerAPIVersion [0.9.17]
157
+ // FastlaneRunnerAPIVersion [0.9.12]
@@ -82,27 +82,50 @@ struct RubyCommand: RubyCommandable {
82
82
  let methodName: String
83
83
  let className: String?
84
84
  let args: [Argument]
85
+ let id: String = UUID().uuidString
86
+
87
+ var closure: ((String) -> Void)? {
88
+ let callbacks = self.args.filter { ($0.type != nil) && $0.type == .stringClosure }
89
+ guard let callback = callbacks.first else {
90
+ return nil
91
+ }
92
+
93
+ guard let callbackArgValue = callback.value else {
94
+ return nil
95
+ }
85
96
 
86
- func performCallback(callbackArg: String) {
97
+ guard let callbackClosure = callbackArgValue as? ((String) -> Void) else {
98
+ return nil
99
+ }
100
+ return callbackClosure
101
+ }
102
+
103
+
104
+ func callbackClosure(_ callbackArg: String) -> ((String) -> Void)? {
87
105
  // WARNING: This will perform the first callback it receives
88
106
  let callbacks = self.args.filter { ($0.type != nil) && $0.type == .stringClosure }
89
107
  guard let callback = callbacks.first else {
90
108
  verbose(message: "received call to performCallback with \(callbackArg), but no callback available to perform")
91
- return
109
+ return nil
92
110
  }
93
111
 
94
112
  guard let callbackArgValue = callback.value else {
95
113
  verbose(message: "received call to performCallback with \(callbackArg), but callback is nil")
96
- return
114
+ return nil
97
115
  }
98
116
 
99
117
  guard let callbackClosure = callbackArgValue as? ((String) -> Void) else {
100
118
  verbose(message: "received call to performCallback with \(callbackArg), but callback type is unknown \(callbackArgValue.self)")
101
- return
119
+ return nil
102
120
  }
121
+ return callbackClosure
122
+ }
103
123
 
104
- print("Performing callback with: \(callbackArg)")
105
- callbackClosure(callbackArg)
124
+ func performCallback(callbackArg: String, socket: SocketClient, completion: @escaping () -> Void) {
125
+ verbose(message: "Performing callback with: \(callbackArg)")
126
+ socket.leave()
127
+ self.callbackClosure(callbackArg)?(callbackArg)
128
+ completion()
106
129
  }
107
130
 
108
131
  var commandJson: String {
@@ -31,6 +31,7 @@ enum CommandType {
31
31
  protocol RubyCommandable {
32
32
  var type: CommandType { get }
33
33
  var commandJson: String { get }
34
+ var id: String { get }
34
35
  }
35
36
 
36
37
  extension RubyCommandable {
@@ -33,28 +33,69 @@ class Runner {
33
33
  fileprivate var returnValue: String? // lol, so safe
34
34
  fileprivate var currentlyExecutingCommand: RubyCommandable? = nil
35
35
  fileprivate var shouldLeaveDispatchGroupDuringDisconnect = false
36
+ fileprivate var executeNext: [String: Bool] = [:]
36
37
 
37
38
  func executeCommand(_ command: RubyCommandable) -> String {
38
39
  self.dispatchGroup.enter()
39
- currentlyExecutingCommand = command
40
- socketClient.send(rubyCommand: command)
40
+ self.currentlyExecutingCommand = command
41
+ self.socketClient.send(rubyCommand: command)
41
42
 
42
43
  let secondsToWait = DispatchTimeInterval.seconds(SocketClient.defaultCommandTimeoutSeconds)
43
- let connectTimeout = DispatchTime.now() + secondsToWait
44
- let timeoutResult = self.dispatchGroup.wait(timeout: connectTimeout)
44
+ let timeoutResult = waitWithPolling(self.executeNext[command.id], toEventually: { $0 == true }, timeout: SocketClient.defaultCommandTimeoutSeconds)
45
+ executeNext.removeValue(forKey: command.id)
45
46
  let failureMessage = "command didn't execute in: \(SocketClient.defaultCommandTimeoutSeconds) seconds"
46
- let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
47
+ let success = self.testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
47
48
  guard success else {
48
49
  log(message: "command timeout")
49
50
  fatalError()
50
51
  }
51
52
 
52
- if let returnValue = self.returnValue {
53
- return returnValue
53
+ if let _returnValue = self.returnValue {
54
+ return _returnValue
54
55
  } else {
55
56
  return ""
56
57
  }
57
58
  }
59
+
60
+ private func waitWithPolling<T>(_ expression: @autoclosure @escaping () throws -> T, toEventually predicate: @escaping (T) -> Bool, timeout: Int, pollingInterval: DispatchTimeInterval = .milliseconds(4)) -> DispatchTimeoutResult {
61
+ func memoizedClosure<T>(_ closure: @escaping () throws -> T) -> (Bool) throws -> T {
62
+ var cache: T?
63
+ return { withoutCaching in
64
+ if withoutCaching || cache == nil {
65
+ cache = try closure()
66
+ }
67
+ guard let cache = cache else {
68
+ preconditionFailure()
69
+ }
70
+
71
+ return cache
72
+ }
73
+ }
74
+
75
+ let runLoop = RunLoop.current
76
+ let timeoutDate = Date(timeInterval: TimeInterval(timeout), since: Date())
77
+ var fulfilled: Bool = false
78
+ let _expression = memoizedClosure(expression)
79
+ repeat {
80
+ do {
81
+ let exp = try _expression(true)
82
+ fulfilled = predicate(exp)
83
+ } catch {
84
+ fatalError("Error raised \(error.localizedDescription)")
85
+ }
86
+ if !fulfilled {
87
+ runLoop.run(until: Date(timeIntervalSinceNow: pollingInterval.timeInterval))
88
+ } else {
89
+ break
90
+ }
91
+ } while Date().compare(timeoutDate) == .orderedAscending
92
+
93
+ if fulfilled {
94
+ return .success
95
+ } else {
96
+ return .timedOut
97
+ }
98
+ }
58
99
  }
59
100
 
60
101
  // Handle threading stuff
@@ -110,25 +151,36 @@ extension Runner {
110
151
  }
111
152
 
112
153
  extension Runner : SocketClientDelegateProtocol {
113
- func commandExecuted(serverResponse: SocketClientResponse) {
154
+ func commandExecuted(serverResponse: SocketClientResponse, completion: (SocketClient) -> Void) {
114
155
  switch serverResponse {
115
156
  case .success(let returnedObject, let closureArgumentValue):
116
157
  verbose(message: "command executed")
117
158
  self.returnValue = returnedObject
118
159
  if let command = self.currentlyExecutingCommand as? RubyCommand {
119
- if let closureArgumentValue = closureArgumentValue {
120
- command.performCallback(callbackArg: closureArgumentValue)
160
+ if let closureArgumentValue = closureArgumentValue, !closureArgumentValue.isEmpty {
161
+ command.performCallback(callbackArg: closureArgumentValue, socket: socketClient) {
162
+ self.executeNext[command.id] = true
163
+ }
164
+ } else {
165
+ self.executeNext[command.id] = true
121
166
  }
122
167
  }
123
- self.dispatchGroup.leave()
168
+ dispatchGroup.leave()
169
+ completion(socketClient)
124
170
  case .clientInitiatedCancelAcknowledged:
125
171
  verbose(message: "server acknowledged a cancel request")
126
172
  self.dispatchGroup.leave()
127
-
173
+ if let command = self.currentlyExecutingCommand as? RubyCommand {
174
+ self.executeNext[command.id] = true
175
+ }
176
+ completion(socketClient)
128
177
  case .alreadyClosedSockets, .connectionFailure, .malformedRequest, .malformedResponse, .serverError:
129
178
  log(message: "error encountered while executing command:\n\(serverResponse)")
130
179
  self.dispatchGroup.leave()
131
-
180
+ if let command = self.currentlyExecutingCommand as? RubyCommand {
181
+ self.executeNext[command.id] = true
182
+ }
183
+ completion(socketClient)
132
184
  case .commandTimeout(let timeout):
133
185
  log(message: "Runner timed out after \(timeout) second(s)")
134
186
  }
@@ -144,6 +196,7 @@ extension Runner : SocketClientDelegateProtocol {
144
196
  DispatchQueue.main.async {
145
197
  self.thread?.cancel()
146
198
  self.thread = nil
199
+ self.socketClient.closeSession()
147
200
  self.socketClient = nil
148
201
  verbose(message: "connection closed!")
149
202
  if self.shouldLeaveDispatchGroupDuringDisconnect {
@@ -194,6 +247,25 @@ func verbose(message: String) {
194
247
  logger.verbose(message: message)
195
248
  }
196
249
 
250
+ private extension DispatchTimeInterval {
251
+ var timeInterval: TimeInterval {
252
+ var result: TimeInterval = 0
253
+ switch self {
254
+ case .seconds(let value):
255
+ result = TimeInterval(value)
256
+ case .milliseconds(let value):
257
+ result = TimeInterval(value)*0.001
258
+ case .microseconds(let value):
259
+ result = TimeInterval(value)*0.000001
260
+ case .nanoseconds(let value):
261
+ result = TimeInterval(value)*0.000000001
262
+ case .never:
263
+ fatalError()
264
+ }
265
+ return result
266
+ }
267
+ }
268
+
197
269
  // Please don't remove the lines below
198
270
  // They are used to detect outdated files
199
271
  // FastlaneRunnerAPIVersion [0.9.2]