fastlane 2.150.3 → 2.151.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +86 -86
  3. data/deliver/lib/deliver/options.rb +7 -1
  4. data/deliver/lib/deliver/submit_for_review.rb +7 -7
  5. data/deliver/lib/deliver/upload_metadata.rb +2 -2
  6. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +3 -0
  7. data/fastlane/lib/fastlane/actions/notarize.rb +13 -3
  8. data/fastlane/lib/fastlane/actions/pod_push.rb +10 -1
  9. data/fastlane/lib/fastlane/actions/resign.rb +1 -1
  10. data/fastlane/lib/fastlane/actions/setup_ci.rb +5 -0
  11. data/fastlane/lib/fastlane/actions/setup_circle_ci.rb +1 -1
  12. data/fastlane/lib/fastlane/actions/setup_travis.rb +1 -1
  13. data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +10 -2
  14. data/fastlane/lib/fastlane/documentation/docs_generator.rb +1 -1
  15. data/fastlane/lib/fastlane/helper/s3_client_helper.rb +28 -11
  16. data/fastlane/lib/fastlane/server/socket_server.rb +7 -1
  17. data/fastlane/lib/fastlane/swift_fastlane_function.rb +1 -1
  18. data/fastlane/lib/fastlane/version.rb +1 -1
  19. data/fastlane/swift/Actions.swift +1 -1
  20. data/fastlane/swift/ArgumentProcessor.swift +24 -24
  21. data/fastlane/swift/ControlCommand.swift +3 -3
  22. data/fastlane/swift/Deliverfile.swift +4 -8
  23. data/fastlane/swift/DeliverfileProtocol.swift +181 -182
  24. data/fastlane/swift/Fastlane.swift +2813 -2802
  25. data/fastlane/swift/Gymfile.swift +4 -8
  26. data/fastlane/swift/GymfileProtocol.swift +133 -134
  27. data/fastlane/swift/LaneFileProtocol.swift +17 -17
  28. data/fastlane/swift/Matchfile.swift +4 -8
  29. data/fastlane/swift/MatchfileProtocol.swift +115 -112
  30. data/fastlane/swift/Plugins.swift +1 -1
  31. data/fastlane/swift/Precheckfile.swift +4 -8
  32. data/fastlane/swift/PrecheckfileProtocol.swift +22 -23
  33. data/fastlane/swift/RubyCommand.swift +34 -37
  34. data/fastlane/swift/RubyCommandable.swift +3 -1
  35. data/fastlane/swift/Runner.swift +76 -69
  36. data/fastlane/swift/Scanfile.swift +4 -8
  37. data/fastlane/swift/ScanfileProtocol.swift +190 -191
  38. data/fastlane/swift/Screengrabfile.swift +4 -8
  39. data/fastlane/swift/ScreengrabfileProtocol.swift +67 -68
  40. data/fastlane/swift/Snapshotfile.swift +4 -8
  41. data/fastlane/swift/SnapshotfileProtocol.swift +127 -128
  42. data/fastlane/swift/SocketClient.swift +84 -90
  43. data/fastlane/swift/SocketResponse.swift +14 -14
  44. data/fastlane/swift/formatting/Brewfile +1 -0
  45. data/fastlane/swift/formatting/Brewfile.lock.json +39 -0
  46. data/fastlane/swift/formatting/Rakefile +18 -0
  47. data/fastlane/swift/main.swift +5 -6
  48. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +15 -7
  49. data/fastlane_core/lib/fastlane_core/ui/fastlane_runner.rb +1 -1
  50. data/match/lib/assets/READMETemplate.md +5 -2
  51. data/match/lib/match/options.rb +4 -0
  52. data/match/lib/match/runner.rb +1 -0
  53. data/match/lib/match/storage/git_storage.rb +1 -1
  54. data/match/lib/match/storage/s3_storage.rb +25 -7
  55. data/sigh/lib/assets/resign.sh +18 -0
  56. data/spaceship/lib/spaceship/client.rb +1 -2
  57. data/spaceship/lib/spaceship/connect_api/client.rb +0 -1
  58. data/spaceship/lib/spaceship/connect_api/models/app_store_version.rb +1 -1
  59. metadata +31 -38
  60. data/deliver/lib/deliver/.upload_metadata.rb.swp +0 -0
  61. data/spaceship/lib/spaceship/babosa_fix.rb +0 -30
@@ -12,4 +12,4 @@ import Foundation
12
12
 
13
13
  // Please don't remove the lines below
14
14
  // They are used to detect outdated files
15
- // FastlaneRunnerAPIVersion [0.9.56]
15
+ // FastlaneRunnerAPIVersion [0.9.56]
@@ -9,13 +9,9 @@
9
9
  //
10
10
 
11
11
  class Precheckfile: PrecheckfileProtocol {
12
- // If you want to enable `precheck`, run `fastlane precheck init`
13
- // After, this file will be replaced with a custom implementation that contains values you supplied
14
- // during the `init` process, and you won't see this message
12
+ // If you want to enable `precheck`, run `fastlane precheck init`
13
+ // After, this file will be replaced with a custom implementation that contains values you supplied
14
+ // during the `init` process, and you won't see this message
15
15
  }
16
16
 
17
-
18
-
19
-
20
-
21
- // Generated with fastlane 2.150.3
17
+ // Generated with fastlane 2.151.0
@@ -1,37 +1,36 @@
1
1
  protocol PrecheckfileProtocol: class {
2
+ /// The bundle identifier of your app
3
+ var appIdentifier: String { get }
2
4
 
3
- /// The bundle identifier of your app
4
- var appIdentifier: String { get }
5
+ /// Your Apple ID Username
6
+ var username: String { get }
5
7
 
6
- /// Your Apple ID Username
7
- var username: String { get }
8
+ /// The ID of your App Store Connect team if you're in multiple teams
9
+ var teamId: String? { get }
8
10
 
9
- /// The ID of your App Store Connect team if you're in multiple teams
10
- var teamId: String? { get }
11
+ /// The name of your App Store Connect team if you're in multiple teams
12
+ var teamName: String? { get }
11
13
 
12
- /// The name of your App Store Connect team if you're in multiple teams
13
- var teamName: String? { get }
14
+ /// The default rule level unless otherwise configured
15
+ var defaultRuleLevel: String { get }
14
16
 
15
- /// The default rule level unless otherwise configured
16
- var defaultRuleLevel: String { get }
17
+ /// Should check in-app purchases?
18
+ var includeInAppPurchases: Bool { get }
17
19
 
18
- /// Should check in-app purchases?
19
- var includeInAppPurchases: Bool { get }
20
-
21
- /// using text indicating that your IAP is free
22
- var freeStuffInIap: String? { get }
20
+ /// using text indicating that your IAP is free
21
+ var freeStuffInIap: String? { get }
23
22
  }
24
23
 
25
24
  extension PrecheckfileProtocol {
26
- var appIdentifier: String { return "" }
27
- var username: String { return "" }
28
- var teamId: String? { return nil }
29
- var teamName: String? { return nil }
30
- var defaultRuleLevel: String { return "error" }
31
- var includeInAppPurchases: Bool { return true }
32
- var freeStuffInIap: String? { return nil }
25
+ var appIdentifier: String { return "" }
26
+ var username: String { return "" }
27
+ var teamId: String? { return nil }
28
+ var teamName: String? { return nil }
29
+ var defaultRuleLevel: String { return "error" }
30
+ var includeInAppPurchases: Bool { return true }
31
+ var freeStuffInIap: String? { return nil }
33
32
  }
34
33
 
35
34
  // Please don't remove the lines below
36
35
  // They are used to detect outdated files
37
- // FastlaneRunnerAPIVersion [0.9.11]
36
+ // FastlaneRunnerAPIVersion [0.9.18]
@@ -40,40 +40,38 @@ struct RubyCommand: RubyCommandable {
40
40
  }
41
41
 
42
42
  var hasValue: Bool {
43
- return nil != self.value
43
+ return value != nil
44
44
  }
45
45
 
46
46
  var json: String {
47
- get {
48
- if let someValue = value {
49
- let typeJson: String
50
- if let type = type {
51
- typeJson = ", \"value_type\" : \"\(type.typeString)\""
52
- } else {
53
- typeJson = ""
54
- }
55
-
56
- if type == .stringClosure {
57
- return "{\"name\" : \"\(name)\", \"value\" : \"ignored_for_closure\"\(typeJson)}"
58
- } else if let array = someValue as? [String] {
59
- return "{\"name\" : \"\(name)\", \"value\" : \"\(array.joined(separator: ","))\"\(typeJson)}"
60
- } else if let hash = someValue as? [String : Any] {
61
- let jsonData = try! JSONSerialization.data(withJSONObject: hash, options: [])
62
- let jsonString = String(data: jsonData, encoding: .utf8)!
63
- return "{\"name\" : \"\(name)\", \"value\" : \(jsonString)\(typeJson)}"
64
- } else {
65
- let dictionary = [
66
- "name": name,
67
- "value": someValue
68
- ]
69
- let jsonData = try! JSONSerialization.data(withJSONObject: dictionary, options: [])
70
- let jsonString = String(data: jsonData, encoding: .utf8)!
71
- return jsonString
72
- }
47
+ if let someValue = value {
48
+ let typeJson: String
49
+ if let type = type {
50
+ typeJson = ", \"value_type\" : \"\(type.typeString)\""
73
51
  } else {
74
- // Just exclude this arg if it doesn't have a value
75
- return ""
52
+ typeJson = ""
76
53
  }
54
+
55
+ if type == .stringClosure {
56
+ return "{\"name\" : \"\(name)\", \"value\" : \"ignored_for_closure\"\(typeJson)}"
57
+ } else if let array = someValue as? [String] {
58
+ return "{\"name\" : \"\(name)\", \"value\" : \"\(array.joined(separator: ","))\"\(typeJson)}"
59
+ } else if let hash = someValue as? [String: Any] {
60
+ let jsonData = try! JSONSerialization.data(withJSONObject: hash, options: [])
61
+ let jsonString = String(data: jsonData, encoding: .utf8)!
62
+ return "{\"name\" : \"\(name)\", \"value\" : \(jsonString)\(typeJson)}"
63
+ } else {
64
+ let dictionary = [
65
+ "name": name,
66
+ "value": someValue,
67
+ ]
68
+ let jsonData = try! JSONSerialization.data(withJSONObject: dictionary, options: [])
69
+ let jsonString = String(data: jsonData, encoding: .utf8)!
70
+ return jsonString
71
+ }
72
+ } else {
73
+ // Just exclude this arg if it doesn't have a value
74
+ return ""
77
75
  }
78
76
  }
79
77
  }
@@ -83,9 +81,9 @@ struct RubyCommand: RubyCommandable {
83
81
  let className: String?
84
82
  let args: [Argument]
85
83
  let id: String = UUID().uuidString
86
-
84
+
87
85
  var closure: ((String) -> Void)? {
88
- let callbacks = self.args.filter { ($0.type != nil) && $0.type == .stringClosure }
86
+ let callbacks = args.filter { ($0.type != nil) && $0.type == .stringClosure }
89
87
  guard let callback = callbacks.first else {
90
88
  return nil
91
89
  }
@@ -99,11 +97,10 @@ struct RubyCommand: RubyCommandable {
99
97
  }
100
98
  return callbackClosure
101
99
  }
102
-
103
-
100
+
104
101
  func callbackClosure(_ callbackArg: String) -> ((String) -> Void)? {
105
102
  // WARNING: This will perform the first callback it receives
106
- let callbacks = self.args.filter { ($0.type != nil) && $0.type == .stringClosure }
103
+ let callbacks = args.filter { ($0.type != nil) && $0.type == .stringClosure }
107
104
  guard let callback = callbacks.first else {
108
105
  verbose(message: "received call to performCallback with \(callbackArg), but no callback available to perform")
109
106
  return nil
@@ -124,17 +121,17 @@ struct RubyCommand: RubyCommandable {
124
121
  func performCallback(callbackArg: String, socket: SocketClient, completion: @escaping () -> Void) {
125
122
  verbose(message: "Performing callback with: \(callbackArg)")
126
123
  socket.leave()
127
- self.callbackClosure(callbackArg)?(callbackArg)
124
+ callbackClosure(callbackArg)?(callbackArg)
128
125
  completion()
129
126
  }
130
127
 
131
128
  var commandJson: String {
132
- let argsArrayJson = self.args
129
+ let argsArrayJson = args
133
130
  .map { $0.json }
134
131
  .filter { $0 != "" }
135
132
 
136
133
  let argsJson: String?
137
- if argsArrayJson.count > 0 {
134
+ if !argsArrayJson.isEmpty {
138
135
  argsJson = "\"args\" : [\(argsArrayJson.joined(separator: ","))]"
139
136
  } else {
140
137
  argsJson = nil
@@ -36,7 +36,9 @@ protocol RubyCommandable {
36
36
 
37
37
  extension RubyCommandable {
38
38
  var json: String {
39
- return "{\"commandType\" : \"\(self.type.token)\", \"command\" : \(self.commandJson)}"
39
+ return """
40
+ { "commandType": "\(type.token)", "command": \(commandJson) }
41
+ """
40
42
  }
41
43
  }
42
44
 
@@ -15,48 +15,49 @@
15
15
  import Foundation
16
16
 
17
17
  let logger: Logger = {
18
- return Logger()
18
+ Logger()
19
19
  }()
20
20
 
21
21
  let runner: Runner = {
22
- return Runner()
22
+ Runner()
23
23
  }()
24
24
 
25
- func desc(_ laneDescription: String) {
25
+ func desc(_: String) {
26
26
  // no-op, this is handled in fastlane/lane_list.rb
27
27
  }
28
28
 
29
29
  class Runner {
30
- fileprivate var thread: Thread!
31
- fileprivate var socketClient: SocketClient!
32
- fileprivate let dispatchGroup: DispatchGroup = DispatchGroup()
33
- fileprivate var returnValue: String? // lol, so safe
34
- fileprivate var currentlyExecutingCommand: RubyCommandable? = nil
35
- fileprivate var shouldLeaveDispatchGroupDuringDisconnect = false
36
- fileprivate var executeNext: [String: Bool] = [:]
37
-
30
+ private var thread: Thread!
31
+ private var socketClient: SocketClient!
32
+ private let dispatchGroup: DispatchGroup = DispatchGroup()
33
+ private var returnValue: String? // lol, so safe
34
+ private var currentlyExecutingCommand: RubyCommandable?
35
+ private var shouldLeaveDispatchGroupDuringDisconnect = false
36
+ private var executeNext: [String: Bool] = [:]
37
+
38
38
  func executeCommand(_ command: RubyCommandable) -> String {
39
- self.dispatchGroup.enter()
40
- self.currentlyExecutingCommand = command
41
- self.socketClient.send(rubyCommand: command)
42
-
39
+ dispatchGroup.enter()
40
+ currentlyExecutingCommand = command
41
+ socketClient.send(rubyCommand: command)
42
+
43
43
  let secondsToWait = DispatchTimeInterval.seconds(SocketClient.defaultCommandTimeoutSeconds)
44
+ // swiftlint:disable next
44
45
  let timeoutResult = waitWithPolling(self.executeNext[command.id], toEventually: { $0 == true }, timeout: SocketClient.defaultCommandTimeoutSeconds)
45
46
  executeNext.removeValue(forKey: command.id)
46
47
  let failureMessage = "command didn't execute in: \(SocketClient.defaultCommandTimeoutSeconds) seconds"
47
- let success = self.testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
48
+ let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
48
49
  guard success else {
49
50
  log(message: "command timeout")
50
- fatalError()
51
+ preconditionFailure()
51
52
  }
52
-
53
- if let _returnValue = self.returnValue {
53
+
54
+ if let _returnValue = returnValue {
54
55
  return _returnValue
55
56
  } else {
56
57
  return ""
57
58
  }
58
59
  }
59
-
60
+
60
61
  private func waitWithPolling<T>(_ expression: @autoclosure @escaping () throws -> T, toEventually predicate: @escaping (T) -> Bool, timeout: Int, pollingInterval: DispatchTimeInterval = .milliseconds(4)) -> DispatchTimeoutResult {
61
62
  func memoizedClosure<T>(_ closure: @escaping () throws -> T) -> (Bool) throws -> T {
62
63
  var cache: T?
@@ -67,11 +68,11 @@ class Runner {
67
68
  guard let cache = cache else {
68
69
  preconditionFailure()
69
70
  }
70
-
71
+
71
72
  return cache
72
73
  }
73
74
  }
74
-
75
+
75
76
  let runLoop = RunLoop.current
76
77
  let timeoutDate = Date(timeInterval: TimeInterval(timeout), since: Date())
77
78
  var fulfilled: Bool = false
@@ -102,44 +103,48 @@ class Runner {
102
103
  extension Runner {
103
104
  func startSocketThread(port: UInt32) {
104
105
  let secondsToWait = DispatchTimeInterval.seconds(SocketClient.connectTimeoutSeconds)
105
-
106
- self.dispatchGroup.enter()
107
-
108
- self.socketClient = SocketClient(port: port, commandTimeoutSeconds:timeout, socketDelegate: self)
109
- self.thread = Thread(target: self, selector: #selector(startSocketComs), object: nil)
110
- self.thread!.name = "socket thread"
111
- self.thread!.start()
112
-
106
+
107
+ dispatchGroup.enter()
108
+
109
+ socketClient = SocketClient(port: port, commandTimeoutSeconds: timeout, socketDelegate: self)
110
+ thread = Thread(target: self, selector: #selector(startSocketComs), object: nil)
111
+ guard let thread = thread else {
112
+ preconditionFailure("Thread did not instantiate correctly")
113
+ }
114
+
115
+ thread.name = "socket thread"
116
+ thread.start()
117
+
113
118
  let connectTimeout = DispatchTime.now() + secondsToWait
114
- let timeoutResult = self.dispatchGroup.wait(timeout: connectTimeout)
115
-
119
+ let timeoutResult = dispatchGroup.wait(timeout: connectTimeout)
120
+
116
121
  let failureMessage = "couldn't start socket thread in: \(SocketClient.connectTimeoutSeconds) seconds"
117
122
  let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
118
123
  guard success else {
119
124
  log(message: "socket thread timeout")
120
- fatalError()
125
+ preconditionFailure()
121
126
  }
122
127
  }
123
-
128
+
124
129
  func disconnectFromFastlaneProcess() {
125
- self.shouldLeaveDispatchGroupDuringDisconnect = true
126
- self.dispatchGroup.enter()
130
+ shouldLeaveDispatchGroupDuringDisconnect = true
131
+ dispatchGroup.enter()
127
132
  socketClient.sendComplete()
128
-
133
+
129
134
  let connectTimeout = DispatchTime.now() + 2
130
- _ = self.dispatchGroup.wait(timeout: connectTimeout)
135
+ _ = dispatchGroup.wait(timeout: connectTimeout)
131
136
  }
132
-
137
+
133
138
  @objc func startSocketComs() {
134
139
  guard let socketClient = self.socketClient else {
135
140
  return
136
141
  }
137
-
142
+
138
143
  socketClient.connectAndOpenStreams()
139
- self.dispatchGroup.leave()
144
+ dispatchGroup.leave()
140
145
  }
141
-
142
- fileprivate func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait: DispatchTimeInterval) -> Bool {
146
+
147
+ fileprivate func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait _: DispatchTimeInterval) -> Bool {
143
148
  switch timeoutResult {
144
149
  case .success:
145
150
  return true
@@ -150,51 +155,53 @@ extension Runner {
150
155
  }
151
156
  }
152
157
 
153
- extension Runner : SocketClientDelegateProtocol {
158
+ extension Runner: SocketClientDelegateProtocol {
154
159
  func commandExecuted(serverResponse: SocketClientResponse, completion: (SocketClient) -> Void) {
155
160
  switch serverResponse {
156
- case .success(let returnedObject, let closureArgumentValue):
161
+ case let .success(returnedObject, closureArgumentValue):
157
162
  verbose(message: "command executed")
158
- self.returnValue = returnedObject
159
- if let command = self.currentlyExecutingCommand as? RubyCommand {
163
+ returnValue = returnedObject
164
+ if let command = currentlyExecutingCommand as? RubyCommand {
160
165
  if let closureArgumentValue = closureArgumentValue, !closureArgumentValue.isEmpty {
161
166
  command.performCallback(callbackArg: closureArgumentValue, socket: socketClient) {
162
167
  self.executeNext[command.id] = true
163
168
  }
164
169
  } else {
165
- self.executeNext[command.id] = true
170
+ executeNext[command.id] = true
166
171
  }
167
172
  }
168
173
  dispatchGroup.leave()
169
174
  completion(socketClient)
170
175
  case .clientInitiatedCancelAcknowledged:
171
176
  verbose(message: "server acknowledged a cancel request")
172
- self.dispatchGroup.leave()
173
- if let command = self.currentlyExecutingCommand as? RubyCommand {
174
- self.executeNext[command.id] = true
177
+ dispatchGroup.leave()
178
+ if let command = currentlyExecutingCommand as? RubyCommand {
179
+ executeNext[command.id] = true
175
180
  }
176
181
  completion(socketClient)
177
182
  case .alreadyClosedSockets, .connectionFailure, .malformedRequest, .malformedResponse, .serverError:
178
183
  log(message: "error encountered while executing command:\n\(serverResponse)")
179
- self.dispatchGroup.leave()
180
- if let command = self.currentlyExecutingCommand as? RubyCommand {
181
- self.executeNext[command.id] = true
184
+ dispatchGroup.leave()
185
+ if let command = currentlyExecutingCommand as? RubyCommand {
186
+ executeNext[command.id] = true
182
187
  }
183
188
  completion(socketClient)
184
- case .commandTimeout(let timeout):
189
+ case let .commandTimeout(timeout):
185
190
  log(message: "Runner timed out after \(timeout) second(s)")
186
191
  }
187
192
  }
188
-
193
+
189
194
  func connectionsOpened() {
190
195
  DispatchQueue.main.async {
191
196
  verbose(message: "connected!")
192
197
  }
193
198
  }
194
-
199
+
195
200
  func connectionsClosed() {
196
201
  DispatchQueue.main.async {
197
- self.thread?.cancel()
202
+ if let thread = self.thread {
203
+ thread.cancel()
204
+ }
198
205
  self.thread = nil
199
206
  self.socketClient.closeSession()
200
207
  self.socketClient = nil
@@ -220,17 +227,18 @@ class Logger {
220
227
  self = .normal
221
228
  }
222
229
  }
230
+
223
231
  case normal
224
232
  case verbose
225
233
  }
226
-
234
+
227
235
  public static var logMode: LogMode = .normal
228
-
236
+
229
237
  func log(message: String) {
230
238
  let timestamp = NSDate().timeIntervalSince1970
231
239
  print("[\(timestamp)]: \(message)")
232
240
  }
233
-
241
+
234
242
  func verbose(message: String) {
235
243
  if Logger.logMode == .verbose {
236
244
  let timestamp = NSDate().timeIntervalSince1970
@@ -251,14 +259,14 @@ private extension DispatchTimeInterval {
251
259
  var timeInterval: TimeInterval {
252
260
  var result: TimeInterval = 0
253
261
  switch self {
254
- case .seconds(let value):
262
+ case let .seconds(value):
255
263
  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
264
+ case let .milliseconds(value):
265
+ result = TimeInterval(value) * 0.001
266
+ case let .microseconds(value):
267
+ result = TimeInterval(value) * 0.000_001
268
+ case let .nanoseconds(value):
269
+ result = TimeInterval(value) * 0.000_000_001
262
270
  case .never:
263
271
  fatalError()
264
272
  }
@@ -269,4 +277,3 @@ private extension DispatchTimeInterval {
269
277
  // Please don't remove the lines below
270
278
  // They are used to detect outdated files
271
279
  // FastlaneRunnerAPIVersion [0.9.2]
272
-