// // LaneFileProtocol.swift // FastlaneSwiftRunner // // Created by Joshua Liebowitz on 8/4/17. // Copyright © 2017 Joshua Liebowitz. All rights reserved. // import Foundation public protocol LaneFileProtocol: class { var fastlaneVersion: String { get } static func runLane(named: String, parameters: [String : String]) -> Bool func recordLaneDescriptions() func beforeAll() func afterAll(currentLane: String) func onError(currentLane: String, errorInfo: String) } public extension LaneFileProtocol { var fastlaneVersion: String { return "" } // default "" because that means any is fine func beforeAll() { } // no op by default func afterAll(currentLane: String) { } // no op by default func onError(currentLane: String, errorInfo: String) {} // no op by default func recordLaneDescriptions() { } // no op by default } @objcMembers public class LaneFile: NSObject, LaneFileProtocol { private(set) static var fastfileInstance: Fastfile? // Called before any lane is executed. private func setupAllTheThings() { LaneFile.fastfileInstance!.beforeAll() } private static func trimLaneFromName(laneName: String) -> String { return String(laneName.prefix(laneName.count - 4)) } private static func trimLaneWithOptionsFromName(laneName: String) -> String { return String(laneName.prefix(laneName.count - 12)) } private static var laneFunctionNames: [String] { var lanes: [String] = [] var methodCount: UInt32 = 0 let methodList = class_copyMethodList(self, &methodCount) for i in 0.. Bool { log(message: "Running lane: \(named)") self.loadFastfile() guard let fastfileInstance: Fastfile = self.fastfileInstance else { let message = "Unable to instantiate class named: \(self.className())" log(message: message) fatalError(message) } let currentLanes = self.lanes let lowerCasedLaneRequested = named.lowercased() guard let laneMethod = currentLanes[lowerCasedLaneRequested] else { let laneNames = self.laneFunctionNames.map { laneFuctionName in if laneFuctionName.hasSuffix("lanewithoptions:") { return trimLaneWithOptionsFromName(laneName: laneFuctionName) } else { return trimLaneFromName(laneName: laneFuctionName) } }.joined(separator: ", ") let message = "[!] Could not find lane '\(named)'. Available lanes: \(laneNames)" log(message: message) let shutdownCommand = ControlCommand(commandType: .cancel(cancelReason: .clientError), message: message) _ = runner.executeCommand(shutdownCommand) return false } // call all methods that need to be called before we start calling lanes fastfileInstance.setupAllTheThings() // We need to catch all possible errors here and display a nice message _ = fastfileInstance.perform(NSSelectorFromString(laneMethod), with: parameters) // only call on success fastfileInstance.afterAll(currentLane: named) log(message: "Done running lane: \(named) 🚀") return true } } // Please don't remove the lines below // They are used to detect outdated files // FastlaneRunnerAPIVersion [0.9.2]