Initial fastlane Setup (#1089)

This commit is contained in:
Ethan Pippin 2024-06-09 22:08:43 -06:00 committed by GitHub
parent 3128a78548
commit f05ef94c77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
48 changed files with 17846 additions and 1 deletions

21
.github/workflows/draft_release.yml vendored Normal file
View File

@ -0,0 +1,21 @@
on:
repository_dispatch:
types: [draft_release]
jobs:
test_build:
runs-on: macos-14
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
- name: Create Release
run: fastlane draftReleaseLane \
repository:${{ github.event.client_payload.repository }} \
apiToken:${{ github.event.client_payload.apiToken }} \
tag:${{ github.event.client_payload.tag }} \
name64:${{ github.event.client_payload.name64 }}

19
.github/workflows/tag.yml vendored Normal file
View File

@ -0,0 +1,19 @@
on:
repository_dispatch:
types: [tag]
jobs:
test_build:
runs-on: macos-14
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
- name: Add Tag
run: fastlane tagLane \
tag:${{ github.event.client_payload.tag }} \
commit:${{ github.event.client_payload.commit }}

View File

@ -44,6 +44,6 @@
redundantClosure, \
redundantType
--exclude Shared/Strings/Strings.swift
--exclude Shared/Strings/Strings.swift, fastlane/
--header "\nSwiftfin is subject to the terms of the Mozilla Public\nLicense, v2.0. If a copy of the MPL was not distributed with this\nfile, you can obtain one at https://mozilla.org/MPL/2.0/.\n\nCopyright (c) {year} Jellyfin & Jellyfin Contributors\n"

3
Gemfile Normal file
View File

@ -0,0 +1,3 @@
source "https://rubygems.org"
gem "fastlane"

7
fastlane/Appfile.swift Normal file
View File

@ -0,0 +1,7 @@
var appIdentifier: String { return "[[APP_IDENTIFIER]]" } // The bundle identifier of your app
var appleID: String { return "[[APPLE_ID]]" } // Your Apple Developer Portal username
// For more information about the Appfile, see:
// https://docs.fastlane.tools/advanced/#appfile

76
fastlane/Fastfile.swift Normal file
View File

@ -0,0 +1,76 @@
// This file contains the fastlane.tools configuration
// You can find the documentation at https://docs.fastlane.tools
//
// For a list of all available actions, check out
//
// https://docs.fastlane.tools/actions
//
import Foundation
class Fastfile: LaneFile {
// MARK: tag
func tagLane(withOptions options: [String: String]?) {
guard let options,
let tag = options["tag"] else {
puts(message: "ERROR: missing options")
exit(1)
}
guard !gitTagExists(tag: tag) else {
puts(message: "ERROR: tag \(tag) already exists")
exit(1)
}
addGitTag(
tag: .userDefined(tag),
commit: .userDefined(options["commit"])
)
pushGitTags(
force: true
)
}
// MARK: draft release
func draftReleaseLane(withOptions options: [String: String]?) {
guard let options,
let repository = options["repository"],
let apiToken = options["apiToken"],
let tag = options["tag"],
let name64 = options["name64"] else {
puts(message: "ERROR: missing options")
exit(1)
}
guard let name = decodeBase64(encoded: name64) else {
puts(message: "ERROR: name not valid base 64")
exit(1)
}
setGithubRelease(
repositoryName: repository,
apiToken: .userDefined(apiToken),
tagName: tag,
name: .userDefined(name),
isDraft: true,
isGenerateReleaseNotes: true
)
}
// MARK: Utilities
private func decodeBase64(encoded: String) -> String? {
guard let data = Data(base64Encoded: encoded),
let decoded = String(data: data, encoding: .utf8) else {
return nil
}
return decoded
}
}

View File

@ -0,0 +1,16 @@
// Actions.swift
// Copyright (c) 2024 FastlaneTools
// This autogenerated file will be overwritten or replaced when running "fastlane generate_swift"
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.56]

View File

@ -0,0 +1,15 @@
// Appfile.swift
// Copyright (c) 2024 FastlaneTools
var appIdentifier: String { return "" } // The bundle identifier of your app
var appleID: String { return "" } // Your Apple Developer Portal username
var teamID: String { return "" } // Developer Portal Team ID
var itcTeam: String? { return nil } // App Store Connect Team ID (may be nil if no team)
// you can even provide different app identifiers, Apple IDs and team names per lane:
// More information: https://docs.fastlane.tools/advanced/#appfile
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.1]

View File

@ -0,0 +1,89 @@
// ArgumentProcessor.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
struct ArgumentProcessor {
let args: [RunnerArgument]
let currentLane: String
let commandTimeout: Int
let port: UInt32
init(args: [String]) {
// Dump the first arg which is the program name
let fastlaneArgs = stride(from: 1, to: args.count - 1, by: 2).map {
RunnerArgument(name: args[$0], value: args[$0 + 1])
}
self.args = fastlaneArgs
let fastlaneArgsMinusLanes = fastlaneArgs.filter { arg in
arg.name.lowercased() != "lane"
}
let potentialLogMode = fastlaneArgsMinusLanes.filter { arg in
arg.name.lowercased() == "logmode"
}
port = UInt32(fastlaneArgsMinusLanes.first(where: { $0.name == "swiftServerPort" })?.value ?? "") ?? 2000
// Configure logMode since we might need to use it before we finish parsing
if let logModeArg = potentialLogMode.first {
let logModeString = logModeArg.value
Logger.logMode = Logger.LogMode(logMode: logModeString)
}
let lanes = self.args.filter { arg in
arg.name.lowercased() == "lane"
}
verbose(message: lanes.description)
guard lanes.count == 1 else {
let message = "You must have exactly one lane specified as an arg, here's what I got: \(lanes)"
log(message: message)
fatalError(message)
}
let lane = lanes.first!
currentLane = lane.value
// User might have configured a timeout for the socket connection
let potentialTimeout = fastlaneArgsMinusLanes.filter { arg in
arg.name.lowercased() == "timeoutseconds"
}
if let logModeArg = potentialLogMode.first {
let logModeString = logModeArg.value
Logger.logMode = Logger.LogMode(logMode: logModeString)
}
if let timeoutArg = potentialTimeout.first {
let timeoutString = timeoutArg.value
commandTimeout = (timeoutString as NSString).integerValue
} else {
commandTimeout = SocketClient.defaultCommandTimeoutSeconds
}
}
func laneParameters() -> [String: String] {
let laneParametersArgs = args.filter { arg in
let lowercasedName = arg.name.lowercased()
return lowercasedName != "timeoutseconds" && lowercasedName != "lane" && lowercasedName != "logmode"
}
var laneParameters = [String: String]()
for arg in laneParametersArgs {
laneParameters[arg.name] = arg.value
}
return laneParameters
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

150
fastlane/swift/Atomic.swift Normal file
View File

@ -0,0 +1,150 @@
// Atomic.swift
// Copyright (c) 2024 FastlaneTools
import Foundation
protocol DictionaryProtocol: class {
associatedtype Key: Hashable
associatedtype Value
subscript(_: Key) -> Value? { get set }
@discardableResult
func removeValue(forKey key: Key) -> Value?
func get(_ key: Key) -> Value?
func set(_ key: Key, value: Value?)
}
extension DictionaryProtocol {
subscript(_ key: Key) -> Value? {
get {
get(key)
}
set {
set(key, value: newValue)
}
}
}
protocol LockProtocol: DictionaryProtocol {
associatedtype Lock
var _lock: Lock { get set }
func lock()
func unlock()
}
protocol AnyLock {}
extension UnsafeMutablePointer: AnyLock {
@available(macOS, deprecated: 10.12)
static func make() -> Self where Pointee == OSSpinLock {
let spin = UnsafeMutablePointer<OSSpinLock>.allocate(capacity: 1)
spin.initialize(to: OS_SPINLOCK_INIT)
return spin
}
@available(macOS, introduced: 10.12)
static func make() -> Self where Pointee == os_unfair_lock {
let unfairLock = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
unfairLock.initialize(to: os_unfair_lock())
return unfairLock
}
@available(macOS, deprecated: 10.12)
static func lock(_ lock: Self) where Pointee == OSSpinLock {
OSSpinLockLock(lock)
}
@available(macOS, deprecated: 10.12)
static func unlock(_ lock: Self) where Pointee == OSSpinLock {
OSSpinLockUnlock(lock)
}
@available(macOS, introduced: 10.12)
static func lock(_ lock: Self) where Pointee == os_unfair_lock {
os_unfair_lock_lock(lock)
}
@available(macOS, introduced: 10.12)
static func unlock(_ lock: Self) where Pointee == os_unfair_lock {
os_unfair_lock_unlock(lock)
}
}
// MARK: - Classes
class AtomicDictionary<Key: Hashable, Value>: LockProtocol {
typealias Lock = AnyLock
var _lock: Lock
private var storage: [Key: Value] = [:]
init(_ lock: Lock) {
_lock = lock
}
@discardableResult
func removeValue(forKey key: Key) -> Value? {
lock()
defer { unlock() }
return storage.removeValue(forKey: key)
}
func get(_ key: Key) -> Value? {
lock()
defer { unlock() }
return storage[key]
}
func set(_ key: Key, value: Value?) {
lock()
defer { unlock() }
storage[key] = value
}
func lock() {
fatalError()
}
func unlock() {
fatalError()
}
}
@available(macOS, introduced: 10.12)
final class UnfairAtomicDictionary<Key: Hashable, Value>: AtomicDictionary<Key, Value> {
typealias Lock = UnsafeMutablePointer<os_unfair_lock>
init() {
super.init(Lock.make())
}
override func lock() {
Lock.lock(_lock as! Lock)
}
override func unlock() {
Lock.unlock(_lock as! Lock)
}
}
@available(macOS, deprecated: 10.12)
final class OSSPinAtomicDictionary<Key: Hashable, Value>: AtomicDictionary<Key, Value> {
typealias Lock = UnsafeMutablePointer<OSSpinLock>
init() {
super.init(Lock.make())
}
override func lock() {
Lock.lock(_lock as! Lock)
}
override func unlock() {
Lock.unlock(_lock as! Lock)
}
}

View File

@ -0,0 +1,74 @@
// ControlCommand.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
struct ControlCommand: RubyCommandable {
static let commandKey = "command"
var type: CommandType { return .control }
enum ShutdownCommandType {
static let userMessageKey: String = "userMessage"
enum CancelReason {
static let reasonKey: String = "reason"
case clientError
case serverError
var reasonText: String {
switch self {
case .clientError:
return "clientError"
case .serverError:
return "serverError"
}
}
}
case done
case cancel(cancelReason: CancelReason)
var token: String {
switch self {
case .done:
return "done"
case .cancel:
return "cancelFastlaneRun"
}
}
}
let message: String?
let id: String = UUID().uuidString
let shutdownCommandType: ShutdownCommandType
var commandJson: String {
var jsonDictionary: [String: Any] = [ControlCommand.commandKey: shutdownCommandType.token]
if let message = message {
jsonDictionary[ShutdownCommandType.userMessageKey] = message
}
if case let .cancel(reason) = shutdownCommandType {
jsonDictionary[ShutdownCommandType.CancelReason.reasonKey] = reason.reasonText
}
let jsonData = try! JSONSerialization.data(withJSONObject: jsonDictionary, options: [])
let jsonString = String(data: jsonData, encoding: .utf8)!
return jsonString
}
init(commandType: ShutdownCommandType, message: String? = nil) {
shutdownCommandType = commandType
self.message = message
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,20 @@
// Deliverfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `deliver`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Deliverfile: DeliverfileProtocol {
// If you want to enable `deliver`, run `fastlane deliver init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,275 @@
// DeliverfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol DeliverfileProtocol: AnyObject {
/// Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
var apiKeyPath: String? { get }
/// Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
var apiKey: [String: Any]? { get }
/// Your Apple ID Username
var username: String? { get }
/// The bundle identifier of your app
var appIdentifier: String? { get }
/// The version that should be edited or created
var appVersion: String? { get }
/// Path to your ipa file
var ipa: String? { get }
/// Path to your pkg file
var pkg: String? { get }
/// If set the given build number (already uploaded to iTC) will be used instead of the current built one
var buildNumber: String? { get }
/// The platform to use (optional)
var platform: String { get }
/// Modify live metadata, this option disables ipa upload and screenshot upload
var editLive: Bool { get }
/// Force usage of live version rather than edit version
var useLiveVersion: Bool { get }
/// Path to the folder containing the metadata files
var metadataPath: String? { get }
/// Path to the folder containing the screenshots
var screenshotsPath: String? { get }
/// Skip uploading an ipa or pkg to App Store Connect
var skipBinaryUpload: Bool { get }
/// Don't upload the screenshots
var skipScreenshots: Bool { get }
/// Don't upload the metadata (e.g. title, description). This will still upload screenshots
var skipMetadata: Bool { get }
/// Dont create or update the app version that is being prepared for submission
var skipAppVersionUpdate: Bool { get }
/// Skip verification of HTML preview file
var force: Bool { get }
/// Clear all previously uploaded screenshots before uploading the new ones
var overwriteScreenshots: Bool { get }
/// Timeout in seconds to wait before considering screenshot processing as failed, used to handle cases where uploads to the App Store are stuck in processing
var screenshotProcessingTimeout: Int { get }
/// Sync screenshots with local ones. This is currently beta option so set true to 'FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS' environment variable as well
var syncScreenshots: Bool { get }
/// Submit the new version for Review after uploading everything
var submitForReview: Bool { get }
/// Verifies archive with App Store Connect without uploading
var verifyOnly: Bool { get }
/// Rejects the previously submitted build if it's in a state where it's possible
var rejectIfPossible: Bool { get }
/// After submitting a new version, App Store Connect takes some time to recognize the new version and we must wait until it's available before attempting to upload metadata for it. There is a mechanism that will check if it's available and retry with an exponential backoff if it's not available yet. This option specifies how many times we should retry before giving up. Setting this to a value below 5 is not recommended and will likely cause failures. Increase this parameter when Apple servers seem to be degraded or slow
var versionCheckWaitRetryLimit: Int { get }
/// Should the app be automatically released once it's approved? (Cannot be used together with `auto_release_date`)
var automaticRelease: Bool? { get }
/// Date in milliseconds for automatically releasing on pending approval (Cannot be used together with `automatic_release`)
var autoReleaseDate: Int? { get }
/// Enable the phased release feature of iTC
var phasedRelease: Bool { get }
/// Reset the summary rating when you release a new version of the application
var resetRatings: Bool { get }
/// The price tier of this application
var priceTier: Int? { get }
/// Path to the app rating's config
var appRatingConfigPath: String? { get }
/// Extra information for the submission (e.g. compliance specifications, IDFA settings)
var submissionInformation: [String: Any]? { get }
/// The ID of your App Store Connect team if you're in multiple teams
var teamId: String? { get }
/// The name of your App Store Connect team if you're in multiple teams
var teamName: String? { get }
/// The short ID of your Developer Portal team, if you're in multiple teams. Different from your iTC team ID!
var devPortalTeamId: String? { get }
/// The name of your Developer Portal team if you're in multiple teams
var devPortalTeamName: String? { get }
/// The provider short name to be used with the iTMSTransporter to identify your team. This value will override the automatically detected provider short name. To get provider short name run `pathToXcode.app/Contents/Applications/Application\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u 'USERNAME' -p 'PASSWORD' -account_type itunes_connect -v off`. The short names of providers should be listed in the second column
var itcProvider: String? { get }
/// Run precheck before submitting to app review
var runPrecheckBeforeSubmit: Bool { get }
/// The default precheck rule level unless otherwise configured
var precheckDefaultRuleLevel: String { get }
/// **DEPRECATED!** Removed after the migration to the new App Store Connect API in June 2020 - An array of localized metadata items to upload individually by language so that errors can be identified. E.g. ['name', 'keywords', 'description']. Note: slow
var individualMetadataItems: [String]? { get }
/// **DEPRECATED!** Removed after the migration to the new App Store Connect API in June 2020 - Metadata: The path to the app icon
var appIcon: String? { get }
/// **DEPRECATED!** Removed after the migration to the new App Store Connect API in June 2020 - Metadata: The path to the Apple Watch app icon
var appleWatchAppIcon: String? { get }
/// Metadata: The copyright notice
var copyright: String? { get }
/// Metadata: The english name of the primary category (e.g. `Business`, `Books`)
var primaryCategory: String? { get }
/// Metadata: The english name of the secondary category (e.g. `Business`, `Books`)
var secondaryCategory: String? { get }
/// Metadata: The english name of the primary first sub category (e.g. `Educational`, `Puzzle`)
var primaryFirstSubCategory: String? { get }
/// Metadata: The english name of the primary second sub category (e.g. `Educational`, `Puzzle`)
var primarySecondSubCategory: String? { get }
/// Metadata: The english name of the secondary first sub category (e.g. `Educational`, `Puzzle`)
var secondaryFirstSubCategory: String? { get }
/// Metadata: The english name of the secondary second sub category (e.g. `Educational`, `Puzzle`)
var secondarySecondSubCategory: String? { get }
/// **DEPRECATED!** This is no longer used by App Store Connect - Metadata: A hash containing the trade representative contact information
var tradeRepresentativeContactInformation: [String: Any]? { get }
/// Metadata: A hash containing the review information
var appReviewInformation: [String: Any]? { get }
/// Metadata: Path to the app review attachment file
var appReviewAttachmentFile: String? { get }
/// Metadata: The localised app description
var description: [String: Any]? { get }
/// Metadata: The localised app name
var name: [String: Any]? { get }
/// Metadata: The localised app subtitle
var subtitle: [String: Any]? { get }
/// Metadata: An array of localised keywords
var keywords: [String: Any]? { get }
/// Metadata: An array of localised promotional texts
var promotionalText: [String: Any]? { get }
/// Metadata: Localised release notes for this version
var releaseNotes: [String: Any]? { get }
/// Metadata: Localised privacy url
var privacyUrl: [String: Any]? { get }
/// Metadata: Localised Apple TV privacy policy text
var appleTvPrivacyPolicy: [String: Any]? { get }
/// Metadata: Localised support url
var supportUrl: [String: Any]? { get }
/// Metadata: Localised marketing url
var marketingUrl: [String: Any]? { get }
/// Metadata: List of languages to activate
var languages: [String]? { get }
/// Ignore errors when invalid languages are found in metadata and screenshot directories
var ignoreLanguageDirectoryValidation: Bool { get }
/// Should precheck check in-app purchases?
var precheckIncludeInAppPurchases: Bool { get }
/// The (spaceship) app ID of the app you want to use/modify
var app: Int? { get }
}
public extension DeliverfileProtocol {
var apiKeyPath: String? { return nil }
var apiKey: [String: Any]? { return nil }
var username: String? { return nil }
var appIdentifier: String? { return nil }
var appVersion: String? { return nil }
var ipa: String? { return nil }
var pkg: String? { return nil }
var buildNumber: String? { return nil }
var platform: String { return "ios" }
var editLive: Bool { return false }
var useLiveVersion: Bool { return false }
var metadataPath: String? { return nil }
var screenshotsPath: String? { return nil }
var skipBinaryUpload: Bool { return false }
var skipScreenshots: Bool { return false }
var skipMetadata: Bool { return false }
var skipAppVersionUpdate: Bool { return false }
var force: Bool { return false }
var overwriteScreenshots: Bool { return false }
var screenshotProcessingTimeout: Int { return 3600 }
var syncScreenshots: Bool { return false }
var submitForReview: Bool { return false }
var verifyOnly: Bool { return false }
var rejectIfPossible: Bool { return false }
var versionCheckWaitRetryLimit: Int { return 7 }
var automaticRelease: Bool? { return nil }
var autoReleaseDate: Int? { return nil }
var phasedRelease: Bool { return false }
var resetRatings: Bool { return false }
var priceTier: Int? { return nil }
var appRatingConfigPath: String? { return nil }
var submissionInformation: [String: Any]? { return nil }
var teamId: String? { return nil }
var teamName: String? { return nil }
var devPortalTeamId: String? { return nil }
var devPortalTeamName: String? { return nil }
var itcProvider: String? { return nil }
var runPrecheckBeforeSubmit: Bool { return true }
var precheckDefaultRuleLevel: String { return "warn" }
var individualMetadataItems: [String]? { return nil }
var appIcon: String? { return nil }
var appleWatchAppIcon: String? { return nil }
var copyright: String? { return nil }
var primaryCategory: String? { return nil }
var secondaryCategory: String? { return nil }
var primaryFirstSubCategory: String? { return nil }
var primarySecondSubCategory: String? { return nil }
var secondaryFirstSubCategory: String? { return nil }
var secondarySecondSubCategory: String? { return nil }
var tradeRepresentativeContactInformation: [String: Any]? { return nil }
var appReviewInformation: [String: Any]? { return nil }
var appReviewAttachmentFile: String? { return nil }
var description: [String: Any]? { return nil }
var name: [String: Any]? { return nil }
var subtitle: [String: Any]? { return nil }
var keywords: [String: Any]? { return nil }
var promotionalText: [String: Any]? { return nil }
var releaseNotes: [String: Any]? { return nil }
var privacyUrl: [String: Any]? { return nil }
var appleTvPrivacyPolicy: [String: Any]? { return nil }
var supportUrl: [String: Any]? { return nil }
var marketingUrl: [String: Any]? { return nil }
var languages: [String]? { return nil }
var ignoreLanguageDirectoryValidation: Bool { return false }
var precheckIncludeInAppPurchases: Bool { return true }
var app: Int? { return nil }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.124]

View File

@ -0,0 +1,16 @@
// This class is automatically included in FastlaneRunner during build
// If you have a custom Fastfile.swift, this file will be replaced by it
// Don't modify this file unless you are familiar with how fastlane's swift code generation works
// *** This file will be overwritten or replaced during build time ***
import Foundation
open class Fastfile: LaneFile {
override public init() {
super.init()
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.1]

13800
fastlane/swift/Fastlane.swift Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,448 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0311E387230AC1B20060BB5C /* Plugins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0311E386230AC1B20060BB5C /* Plugins.swift */; };
0311E38B230AC9490060BB5C /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0311E38A230AC9490060BB5C /* Actions.swift */; };
1257253924B7992C00E04FA3 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1257253824B7992B00E04FA3 /* main.swift */; };
1267C3F42773A43E004DE48A /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1267C3F32773A43E004DE48A /* Atomic.swift */; };
12D2EB8D2620D83C00844013 /* OptionalConfigValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12D2EB8C2620D83B00844013 /* OptionalConfigValue.swift */; };
B302067B1F5E3E9000DE6EBD /* SnapshotfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */; };
B302067C1F5E3E9000DE6EBD /* GymfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */; };
B302067D1F5E3E9000DE6EBD /* MatchfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206761F5E3E9000DE6EBD /* MatchfileProtocol.swift */; };
B302067E1F5E3E9000DE6EBD /* PrecheckfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206771F5E3E9000DE6EBD /* PrecheckfileProtocol.swift */; };
B302067F1F5E3E9000DE6EBD /* ScanfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206781F5E3E9000DE6EBD /* ScanfileProtocol.swift */; };
B30206801F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30206791F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift */; };
B30206811F5E3E9000DE6EBD /* DeliverfileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B302067A1F5E3E9000DE6EBD /* DeliverfileProtocol.swift */; };
B3BA65A61F5A269100B34850 /* Fastlane.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA659D1F5A269100B34850 /* Fastlane.swift */; };
B3BA65A71F5A269100B34850 /* LaneFileProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA659E1F5A269100B34850 /* LaneFileProtocol.swift */; };
B3BA65A91F5A269100B34850 /* RubyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A01F5A269100B34850 /* RubyCommand.swift */; };
B3BA65AA1F5A269100B34850 /* Runner.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A11F5A269100B34850 /* Runner.swift */; };
B3BA65AB1F5A269100B34850 /* SocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A21F5A269100B34850 /* SocketClient.swift */; };
B3BA65AC1F5A269100B34850 /* SocketClientDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */; };
B3BA65AD1F5A269100B34850 /* SocketResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65A41F5A269100B34850 /* SocketResponse.swift */; };
B3BA65AF1F5A2D5C00B34850 /* RunnerArgument.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BA65AE1F5A2D5C00B34850 /* RunnerArgument.swift */; };
C0459CAC27261897002CDFB9 /* FastlaneRunner in CopyFiles */ = {isa = PBXBuildFile; fileRef = D556D6A91F6A08F5003108E3 /* FastlaneRunner */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D55B28C31F6C588300DC42C5 /* Deliverfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BC1F6C588300DC42C5 /* Deliverfile.swift */; };
D55B28C41F6C588300DC42C5 /* Gymfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BD1F6C588300DC42C5 /* Gymfile.swift */; };
D55B28C51F6C588300DC42C5 /* Matchfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BE1F6C588300DC42C5 /* Matchfile.swift */; };
D55B28C61F6C588300DC42C5 /* Precheckfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28BF1F6C588300DC42C5 /* Precheckfile.swift */; };
D55B28C71F6C588300DC42C5 /* Scanfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C01F6C588300DC42C5 /* Scanfile.swift */; };
D55B28C81F6C588300DC42C5 /* Screengrabfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C11F6C588300DC42C5 /* Screengrabfile.swift */; };
D55B28C91F6C588300DC42C5 /* Snapshotfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */; };
D5A7C48F1F7C4DAF00A91DE6 /* Appfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */; };
D5A7C4901F7C4DAF00A91DE6 /* Fastfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */; };
D5B8A5B31FFDC49E00536B24 /* ControlCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */; };
D5BAFD121F7DAAFC0030B324 /* ArgumentProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */; };
D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
C0459CAB27261886002CDFB9 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "$SRCROOT/../..";
dstSubfolderSpec = 0;
files = (
C0459CAC27261897002CDFB9 /* FastlaneRunner in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0311E386230AC1B20060BB5C /* Plugins.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Plugins.swift; path = ../Plugins.swift; sourceTree = "<group>"; };
0311E38A230AC9490060BB5C /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Actions.swift; path = ../Actions.swift; sourceTree = "<group>"; };
1257253824B7992B00E04FA3 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../main.swift; sourceTree = "<group>"; };
1267C3F32773A43E004DE48A /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Atomic.swift; path = ../Atomic.swift; sourceTree = "<group>"; };
12D2EB8C2620D83B00844013 /* OptionalConfigValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OptionalConfigValue.swift; path = ../OptionalConfigValue.swift; sourceTree = "<group>"; };
B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotfileProtocol.swift; path = ../SnapshotfileProtocol.swift; sourceTree = "<group>"; };
B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GymfileProtocol.swift; path = ../GymfileProtocol.swift; sourceTree = "<group>"; };
B30206761F5E3E9000DE6EBD /* MatchfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MatchfileProtocol.swift; path = ../MatchfileProtocol.swift; sourceTree = "<group>"; };
B30206771F5E3E9000DE6EBD /* PrecheckfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrecheckfileProtocol.swift; path = ../PrecheckfileProtocol.swift; sourceTree = "<group>"; };
B30206781F5E3E9000DE6EBD /* ScanfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ScanfileProtocol.swift; path = ../ScanfileProtocol.swift; sourceTree = "<group>"; };
B30206791F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ScreengrabfileProtocol.swift; path = ../ScreengrabfileProtocol.swift; sourceTree = "<group>"; };
B302067A1F5E3E9000DE6EBD /* DeliverfileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeliverfileProtocol.swift; path = ../DeliverfileProtocol.swift; sourceTree = "<group>"; };
B3144C072005533400470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
B3144C08200553C800470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
B3144C09200553D400470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
B3144C0A200553DC00470AFE /* README.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
B3BA659D1F5A269100B34850 /* Fastlane.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Fastlane.swift; path = ../Fastlane.swift; sourceTree = "<group>"; };
B3BA659E1F5A269100B34850 /* LaneFileProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LaneFileProtocol.swift; path = ../LaneFileProtocol.swift; sourceTree = "<group>"; };
B3BA65A01F5A269100B34850 /* RubyCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RubyCommand.swift; path = ../RubyCommand.swift; sourceTree = "<group>"; };
B3BA65A11F5A269100B34850 /* Runner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Runner.swift; path = ../Runner.swift; sourceTree = "<group>"; };
B3BA65A21F5A269100B34850 /* SocketClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClient.swift; path = ../SocketClient.swift; sourceTree = "<group>"; };
B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketClientDelegateProtocol.swift; path = ../SocketClientDelegateProtocol.swift; sourceTree = "<group>"; };
B3BA65A41F5A269100B34850 /* SocketResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocketResponse.swift; path = ../SocketResponse.swift; sourceTree = "<group>"; };
B3BA65AE1F5A2D5C00B34850 /* RunnerArgument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RunnerArgument.swift; path = ../RunnerArgument.swift; sourceTree = "<group>"; };
D556D6A91F6A08F5003108E3 /* FastlaneRunner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = FastlaneRunner; sourceTree = BUILT_PRODUCTS_DIR; };
D55B28BC1F6C588300DC42C5 /* Deliverfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Deliverfile.swift; path = ../Deliverfile.swift; sourceTree = "<group>"; };
D55B28BD1F6C588300DC42C5 /* Gymfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gymfile.swift; path = ../Gymfile.swift; sourceTree = "<group>"; };
D55B28BE1F6C588300DC42C5 /* Matchfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Matchfile.swift; path = ../Matchfile.swift; sourceTree = "<group>"; };
D55B28BF1F6C588300DC42C5 /* Precheckfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Precheckfile.swift; path = ../Precheckfile.swift; sourceTree = "<group>"; };
D55B28C01F6C588300DC42C5 /* Scanfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Scanfile.swift; path = ../Scanfile.swift; sourceTree = "<group>"; };
D55B28C11F6C588300DC42C5 /* Screengrabfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Screengrabfile.swift; path = ../Screengrabfile.swift; sourceTree = "<group>"; };
D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Snapshotfile.swift; path = ../Snapshotfile.swift; sourceTree = "<group>"; };
D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Appfile.swift; path = ../../Appfile.swift; sourceTree = "<group>"; };
D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Fastfile.swift; path = ../../Fastfile.swift; sourceTree = "<group>"; };
D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControlCommand.swift; path = ../ControlCommand.swift; sourceTree = "<group>"; };
D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ArgumentProcessor.swift; path = ../ArgumentProcessor.swift; sourceTree = "<group>"; };
D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RubyCommandable.swift; path = ../RubyCommandable.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
B33BAF541F51F8D90001A751 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
B33BAF4E1F51F8D90001A751 = {
isa = PBXGroup;
children = (
B3BA65B01F5A324A00B34850 /* Fastlane Runner */,
D556D6A91F6A08F5003108E3 /* FastlaneRunner */,
);
sourceTree = "<group>";
};
B3BA65B01F5A324A00B34850 /* Fastlane Runner */ = {
isa = PBXGroup;
children = (
B3BA65B21F5A327B00B34850 /* Autogenerated API */,
B3BA65B31F5A329800B34850 /* Fastfile Components */,
B3BA65B11F5A325E00B34850 /* Networking */,
D512BA011F7C7F40000D2137 /* Runner Code */,
D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */,
D55B28BC1F6C588300DC42C5 /* Deliverfile.swift */,
D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */,
D55B28BD1F6C588300DC42C5 /* Gymfile.swift */,
D55B28BE1F6C588300DC42C5 /* Matchfile.swift */,
D55B28BF1F6C588300DC42C5 /* Precheckfile.swift */,
D55B28C01F6C588300DC42C5 /* Scanfile.swift */,
D55B28C11F6C588300DC42C5 /* Screengrabfile.swift */,
D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */,
);
name = "Fastlane Runner";
sourceTree = "<group>";
};
B3BA65B11F5A325E00B34850 /* Networking */ = {
isa = PBXGroup;
children = (
1267C3F32773A43E004DE48A /* Atomic.swift */,
B3144C072005533400470AFE /* README.txt */,
D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */,
B3BA65A01F5A269100B34850 /* RubyCommand.swift */,
D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */,
B3BA65A11F5A269100B34850 /* Runner.swift */,
B3BA65A21F5A269100B34850 /* SocketClient.swift */,
B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */,
B3BA65A41F5A269100B34850 /* SocketResponse.swift */,
);
name = Networking;
sourceTree = "<group>";
};
B3BA65B21F5A327B00B34850 /* Autogenerated API */ = {
isa = PBXGroup;
children = (
B3144C09200553D400470AFE /* README.txt */,
0311E38A230AC9490060BB5C /* Actions.swift */,
B3BA659D1F5A269100B34850 /* Fastlane.swift */,
B302067A1F5E3E9000DE6EBD /* DeliverfileProtocol.swift */,
B30206751F5E3E9000DE6EBD /* GymfileProtocol.swift */,
B30206761F5E3E9000DE6EBD /* MatchfileProtocol.swift */,
0311E386230AC1B20060BB5C /* Plugins.swift */,
B30206771F5E3E9000DE6EBD /* PrecheckfileProtocol.swift */,
B30206781F5E3E9000DE6EBD /* ScanfileProtocol.swift */,
B30206791F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift */,
B30206741F5E3E9000DE6EBD /* SnapshotfileProtocol.swift */,
);
name = "Autogenerated API";
sourceTree = "<group>";
};
B3BA65B31F5A329800B34850 /* Fastfile Components */ = {
isa = PBXGroup;
children = (
B3144C08200553C800470AFE /* README.txt */,
B3BA659E1F5A269100B34850 /* LaneFileProtocol.swift */,
12D2EB8C2620D83B00844013 /* OptionalConfigValue.swift */,
);
name = "Fastfile Components";
sourceTree = "<group>";
};
D512BA011F7C7F40000D2137 /* Runner Code */ = {
isa = PBXGroup;
children = (
1257253824B7992B00E04FA3 /* main.swift */,
B3144C0A200553DC00470AFE /* README.txt */,
D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */,
B3BA65AE1F5A2D5C00B34850 /* RunnerArgument.swift */,
);
name = "Runner Code";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
B33BAF561F51F8D90001A751 /* FastlaneRunner */ = {
isa = PBXNativeTarget;
buildConfigurationList = B33BAF5E1F51F8D90001A751 /* Build configuration list for PBXNativeTarget "FastlaneRunner" */;
buildPhases = (
B33BAF531F51F8D90001A751 /* Sources */,
B33BAF541F51F8D90001A751 /* Frameworks */,
C0459CAB27261886002CDFB9 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = FastlaneRunner;
productName = FastlaneSwiftRunner;
productReference = D556D6A91F6A08F5003108E3 /* FastlaneRunner */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
B33BAF4F1F51F8D90001A751 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "Joshua Liebowitz";
TargetAttributes = {
B33BAF561F51F8D90001A751 = {
CreatedOnToolsVersion = 8.3.3;
LastSwiftMigration = 0900;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = B33BAF521F51F8D90001A751 /* Build configuration list for PBXProject "FastlaneSwiftRunner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = B33BAF4E1F51F8D90001A751;
productRefGroup = B33BAF4E1F51F8D90001A751;
projectDirPath = "";
projectRoot = "";
targets = (
B33BAF561F51F8D90001A751 /* FastlaneRunner */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
B33BAF531F51F8D90001A751 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B3BA65A91F5A269100B34850 /* RubyCommand.swift in Sources */,
D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */,
D55B28C41F6C588300DC42C5 /* Gymfile.swift in Sources */,
B302067D1F5E3E9000DE6EBD /* MatchfileProtocol.swift in Sources */,
1267C3F42773A43E004DE48A /* Atomic.swift in Sources */,
B3BA65AC1F5A269100B34850 /* SocketClientDelegateProtocol.swift in Sources */,
B3BA65A71F5A269100B34850 /* LaneFileProtocol.swift in Sources */,
D55B28C61F6C588300DC42C5 /* Precheckfile.swift in Sources */,
B302067F1F5E3E9000DE6EBD /* ScanfileProtocol.swift in Sources */,
D55B28C51F6C588300DC42C5 /* Matchfile.swift in Sources */,
B30206801F5E3E9000DE6EBD /* ScreengrabfileProtocol.swift in Sources */,
D5BAFD121F7DAAFC0030B324 /* ArgumentProcessor.swift in Sources */,
B302067C1F5E3E9000DE6EBD /* GymfileProtocol.swift in Sources */,
B302067B1F5E3E9000DE6EBD /* SnapshotfileProtocol.swift in Sources */,
D55B28C31F6C588300DC42C5 /* Deliverfile.swift in Sources */,
D5A7C4901F7C4DAF00A91DE6 /* Fastfile.swift in Sources */,
0311E38B230AC9490060BB5C /* Actions.swift in Sources */,
D5A7C48F1F7C4DAF00A91DE6 /* Appfile.swift in Sources */,
B3BA65AB1F5A269100B34850 /* SocketClient.swift in Sources */,
B30206811F5E3E9000DE6EBD /* DeliverfileProtocol.swift in Sources */,
B3BA65AA1F5A269100B34850 /* Runner.swift in Sources */,
B3BA65AF1F5A2D5C00B34850 /* RunnerArgument.swift in Sources */,
D5B8A5B31FFDC49E00536B24 /* ControlCommand.swift in Sources */,
1257253924B7992C00E04FA3 /* main.swift in Sources */,
B302067E1F5E3E9000DE6EBD /* PrecheckfileProtocol.swift in Sources */,
B3BA65AD1F5A269100B34850 /* SocketResponse.swift in Sources */,
D55B28C71F6C588300DC42C5 /* Scanfile.swift in Sources */,
0311E387230AC1B20060BB5C /* Plugins.swift in Sources */,
D55B28C91F6C588300DC42C5 /* Snapshotfile.swift in Sources */,
B3BA65A61F5A269100B34850 /* Fastlane.swift in Sources */,
D55B28C81F6C588300DC42C5 /* Screengrabfile.swift in Sources */,
12D2EB8D2620D83C00844013 /* OptionalConfigValue.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
B33BAF5C1F51F8D90001A751 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
};
name = Debug;
};
B33BAF5D1F51F8D90001A751 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
};
name = Release;
};
B33BAF5F1F51F8D90001A751 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
};
name = Debug;
};
B33BAF601F51F8D90001A751 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
B33BAF521F51F8D90001A751 /* Build configuration list for PBXProject "FastlaneSwiftRunner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
B33BAF5C1F51F8D90001A751 /* Debug */,
B33BAF5D1F51F8D90001A751 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
B33BAF5E1F51F8D90001A751 /* Build configuration list for PBXNativeTarget "FastlaneRunner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
B33BAF5F1F51F8D90001A751 /* Debug */,
B33BAF601F51F8D90001A751 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = B33BAF4F1F51F8D90001A751 /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:FastlaneSwiftRunner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B33BAF561F51F8D90001A751"
BuildableName = "FastlaneRunner"
BlueprintName = "FastlaneRunner"
ReferencedContainer = "container:FastlaneSwiftRunner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B33BAF561F51F8D90001A751"
BuildableName = "FastlaneRunner"
BlueprintName = "FastlaneRunner"
ReferencedContainer = "container:FastlaneSwiftRunner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B33BAF561F51F8D90001A751"
BuildableName = "FastlaneRunner"
BlueprintName = "FastlaneRunner"
ReferencedContainer = "container:FastlaneSwiftRunner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "lane testLane"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "logMode verbose"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "B33BAF561F51F8D90001A751"
BuildableName = "FastlaneRunner"
BlueprintName = "FastlaneRunner"
ReferencedContainer = "container:FastlaneSwiftRunner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,10 @@
Don't modify the structure of this group including but not limited to:
- renaming this group
- adding sub groups
- removing sub groups
- adding new files
- removing files
If you modify anything in this folder, future fastlane upgrades may not be able to be applied automatically.
If you need to add new groups, please add them at the root of the "Fastlane Runner" group.

View File

@ -0,0 +1,20 @@
// Gymfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `gym`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Gymfile: GymfileProtocol {
// If you want to enable `gym`, run `fastlane gym init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,211 @@
// GymfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol GymfileProtocol: AnyObject {
/// Path to the workspace file
var workspace: String? { get }
/// Path to the project file
var project: String? { get }
/// The project's scheme. Make sure it's marked as `Shared`
var scheme: String? { get }
/// Should the project be cleaned before building it?
var clean: Bool { get }
/// The directory in which the ipa file should be stored in
var outputDirectory: String { get }
/// The name of the resulting ipa file
var outputName: String? { get }
/// The configuration to use when building the app. Defaults to 'Release'
var configuration: String? { get }
/// Hide all information that's not necessary while building
var silent: Bool { get }
/// The name of the code signing identity to use. It has to match the name exactly. e.g. 'iPhone Distribution: SunApps GmbH'
var codesigningIdentity: String? { get }
/// Should we skip packaging the ipa?
var skipPackageIpa: Bool { get }
/// Should we skip packaging the pkg?
var skipPackagePkg: Bool { get }
/// Should the ipa file include symbols?
var includeSymbols: Bool? { get }
/// Should the ipa file include bitcode?
var includeBitcode: Bool? { get }
/// Method used to export the archive. Valid values are: app-store, validation, ad-hoc, package, enterprise, development, developer-id and mac-application
var exportMethod: String? { get }
/// Path to an export options plist or a hash with export options. Use 'xcodebuild -help' to print the full set of available options
var exportOptions: [String: Any]? { get }
/// Pass additional arguments to xcodebuild for the package phase. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
var exportXcargs: String? { get }
/// Export ipa from previously built xcarchive. Uses archive_path as source
var skipBuildArchive: Bool? { get }
/// After building, don't archive, effectively not including -archivePath param
var skipArchive: Bool? { get }
/// Build without codesigning
var skipCodesigning: Bool? { get }
/// Platform to build when using a Catalyst enabled app. Valid values are: ios, macos
var catalystPlatform: String? { get }
/// Full name of 3rd Party Mac Developer Installer or Developer ID Installer certificate. Example: `3rd Party Mac Developer Installer: Your Company (ABC1234XWYZ)`
var installerCertName: String? { get }
/// The directory in which the archive should be stored in
var buildPath: String? { get }
/// The path to the created archive
var archivePath: String? { get }
/// The directory where built products and other derived data will go
var derivedDataPath: String? { get }
/// Should an Xcode result bundle be generated in the output directory
var resultBundle: Bool { get }
/// Path to the result bundle directory to create. Ignored if `result_bundle` if false
var resultBundlePath: String? { get }
/// The directory where to store the build log
var buildlogPath: String { get }
/// The SDK that should be used for building the application
var sdk: String? { get }
/// The toolchain that should be used for building the application (e.g. com.apple.dt.toolchain.Swift_2_3, org.swift.30p620160816a)
var toolchain: String? { get }
/// Use a custom destination for building the app
var destination: String? { get }
/// Optional: Sometimes you need to specify a team id when exporting the ipa file
var exportTeamId: String? { get }
/// Pass additional arguments to xcodebuild for the build phase. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
var xcargs: String? { get }
/// Use an extra XCCONFIG file to build your app
var xcconfig: String? { get }
/// Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path
var suppressXcodeOutput: Bool? { get }
/// xcodebuild formatter to use (ex: 'xcbeautify', 'xcbeautify --quieter', 'xcpretty', 'xcpretty -test'). Use empty string (ex: '') to disable any formatter (More information: https://docs.fastlane.tools/best-practices/xcodebuild-formatters/)
var xcodebuildFormatter: String { get }
/// Create a build timing summary
var buildTimingSummary: Bool { get }
/// **DEPRECATED!** Use `xcodebuild_formatter: ''` instead - Disable xcpretty formatting of build output
var disableXcpretty: Bool? { get }
/// Use the test (RSpec style) format for build output
var xcprettyTestFormat: Bool? { get }
/// A custom xcpretty formatter to use
var xcprettyFormatter: String? { get }
/// Have xcpretty create a JUnit-style XML report at the provided path
var xcprettyReportJunit: String? { get }
/// Have xcpretty create a simple HTML report at the provided path
var xcprettyReportHtml: String? { get }
/// Have xcpretty create a JSON compilation database at the provided path
var xcprettyReportJson: String? { get }
/// Have xcpretty use unicode encoding when reporting builds
var xcprettyUtf: Bool? { get }
/// Analyze the project build time and store the output in 'culprits.txt' file
var analyzeBuildTime: Bool? { get }
/// Do not try to build a profile mapping from the xcodeproj. Match or a manually provided mapping should be used
var skipProfileDetection: Bool { get }
/// Allows for override of the default `xcodebuild` command
var xcodebuildCommand: String { get }
/// Sets a custom path for Swift Package Manager dependencies
var clonedSourcePackagesPath: String? { get }
/// Skips resolution of Swift Package Manager dependencies
var skipPackageDependenciesResolution: Bool { get }
/// Prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file
var disablePackageAutomaticUpdates: Bool { get }
/// Lets xcodebuild use system's scm configuration
var useSystemScm: Bool { get }
}
public extension GymfileProtocol {
var workspace: String? { return nil }
var project: String? { return nil }
var scheme: String? { return nil }
var clean: Bool { return false }
var outputDirectory: String { return "." }
var outputName: String? { return nil }
var configuration: String? { return nil }
var silent: Bool { return false }
var codesigningIdentity: String? { return nil }
var skipPackageIpa: Bool { return false }
var skipPackagePkg: Bool { return false }
var includeSymbols: Bool? { return nil }
var includeBitcode: Bool? { return nil }
var exportMethod: String? { return nil }
var exportOptions: [String: Any]? { return nil }
var exportXcargs: String? { return nil }
var skipBuildArchive: Bool? { return nil }
var skipArchive: Bool? { return nil }
var skipCodesigning: Bool? { return nil }
var catalystPlatform: String? { return nil }
var installerCertName: String? { return nil }
var buildPath: String? { return nil }
var archivePath: String? { return nil }
var derivedDataPath: String? { return nil }
var resultBundle: Bool { return false }
var resultBundlePath: String? { return nil }
var buildlogPath: String { return "~/Library/Logs/gym" }
var sdk: String? { return nil }
var toolchain: String? { return nil }
var destination: String? { return nil }
var exportTeamId: String? { return nil }
var xcargs: String? { return nil }
var xcconfig: String? { return nil }
var suppressXcodeOutput: Bool? { return nil }
var xcodebuildFormatter: String { return "xcbeautify" }
var buildTimingSummary: Bool { return false }
var disableXcpretty: Bool? { return nil }
var xcprettyTestFormat: Bool? { return nil }
var xcprettyFormatter: String? { return nil }
var xcprettyReportJunit: String? { return nil }
var xcprettyReportHtml: String? { return nil }
var xcprettyReportJson: String? { return nil }
var xcprettyUtf: Bool? { return nil }
var analyzeBuildTime: Bool? { return nil }
var skipProfileDetection: Bool { return false }
var xcodebuildCommand: String { return "xcodebuild" }
var clonedSourcePackagesPath: String? { return nil }
var skipPackageDependenciesResolution: Bool { return false }
var disablePackageAutomaticUpdates: Bool { return false }
var useSystemScm: Bool { return false }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.127]

View File

@ -0,0 +1,155 @@
// LaneFileProtocol.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
public protocol LaneFileProtocol: AnyObject {
var fastlaneVersion: String { get }
static func runLane(from fastfile: LaneFile?, named lane: String, with parameters: [String: String]) -> Bool
func recordLaneDescriptions()
func beforeAll(with lane: String)
func afterAll(with lane: String)
func onError(currentLane: String, errorInfo: String, errorClass: String?, errorMessage: String?)
}
public extension LaneFileProtocol {
var fastlaneVersion: String { return "" } // Defaults to "" because that means any is fine
func beforeAll(with _: String) {} // No-op by default
func afterAll(with _: String) {} // No-op by default
func recordLaneDescriptions() {} // No-op by default
}
@objcMembers
open class LaneFile: NSObject, LaneFileProtocol {
private(set) static var fastfileInstance: LaneFile?
private static var onErrorCalled = Set<String>()
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))
}
public func onError(currentLane: String, errorInfo _: String, errorClass _: String?, errorMessage _: String?) {
LaneFile.onErrorCalled.insert(currentLane)
}
private static var laneFunctionNames: [String] {
var lanes: [String] = []
var methodCount: UInt32 = 0
#if !SWIFT_PACKAGE
let methodList = class_copyMethodList(self, &methodCount)
#else
// In SPM we're calling this functions out of the scope of the normal binary that it's
// being built, so *self* in this scope would be the SPM executable instead of the Fastfile
// that we'd normally expect.
let methodList = class_copyMethodList(type(of: fastfileInstance!), &methodCount)
#endif
for i in 0 ..< Int(methodCount) {
let selName = sel_getName(method_getName(methodList![i]))
let name = String(cString: selName)
let lowercasedName = name.lowercased()
if lowercasedName.hasSuffix("lane") || lowercasedName.hasSuffix("lanewithoptions:") {
lanes.append(name)
}
}
return lanes
}
public static var lanes: [String: String] {
var laneToMethodName: [String: String] = [:]
for name in laneFunctionNames {
let lowercasedName = name.lowercased()
if lowercasedName.hasSuffix("lane") {
laneToMethodName[lowercasedName] = name
let lowercasedNameNoLane = trimLaneFromName(laneName: lowercasedName)
laneToMethodName[lowercasedNameNoLane] = name
} else if lowercasedName.hasSuffix("lanewithoptions:") {
let lowercasedNameNoOptions = trimLaneWithOptionsFromName(laneName: lowercasedName)
laneToMethodName[lowercasedNameNoOptions] = name
let lowercasedNameNoLane = trimLaneFromName(laneName: lowercasedNameNoOptions)
laneToMethodName[lowercasedNameNoLane] = name
}
}
return laneToMethodName
}
public static func loadFastfile() {
if fastfileInstance == nil {
let fastfileType: AnyObject.Type = NSClassFromString(className())!
let fastfileAsNSObjectType: NSObject.Type = fastfileType as! NSObject.Type
let currentFastfileInstance: Fastfile? = fastfileAsNSObjectType.init() as? Fastfile
fastfileInstance = currentFastfileInstance
}
}
public static func runLane(from fastfile: LaneFile?, named lane: String, with parameters: [String: String]) -> Bool {
log(message: "Running lane: \(lane)")
#if !SWIFT_PACKAGE
// When not in SPM environment, we load the Fastfile from its `className()`.
loadFastfile()
guard let fastfileInstance = fastfileInstance as? Fastfile else {
let message = "Unable to instantiate class named: \(className())"
log(message: message)
fatalError(message)
}
#else
// When in SPM environment, we can't load the Fastfile from its `className()` because the executable is in
// another scope, so `className()` won't be the expected Fastfile. Instead, we load the Fastfile as a Lanefile
// in a static way, by parameter.
guard let fastfileInstance = fastfile else {
log(message: "Found nil instance of fastfile")
preconditionFailure()
}
self.fastfileInstance = fastfileInstance
#endif
let currentLanes = lanes
let lowerCasedLaneRequested = lane.lowercased()
guard let laneMethod = currentLanes[lowerCasedLaneRequested] else {
let laneNames = laneFunctionNames.map { laneFunctionName in
if laneFunctionName.hasSuffix("lanewithoptions:") {
return trimLaneWithOptionsFromName(laneName: laneFunctionName)
} else {
return trimLaneFromName(laneName: laneFunctionName)
}
}.joined(separator: ", ")
let message = "[!] Could not find lane '\(lane)'. 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.beforeAll(with: lane)
// We need to catch all possible errors here and display a nice message.
_ = fastfileInstance.perform(NSSelectorFromString(laneMethod), with: parameters)
// Call only on success.
if !LaneFile.onErrorCalled.contains(lane) {
fastfileInstance.afterAll(with: lane)
}
log(message: "Done running lane: \(lane) 🚀")
return true
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,79 @@
// MainProcess.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
#if canImport(SwiftShell)
import SwiftShell
#endif
let argumentProcessor = ArgumentProcessor(args: CommandLine.arguments)
let timeout = argumentProcessor.commandTimeout
class MainProcess {
var doneRunningLane = false
var thread: Thread!
#if SWIFT_PACKAGE
var lastPrintDate = Date.distantFuture
var timeBetweenPrints = Int.min
var rubySocketCommand: AsyncCommand!
#endif
@objc func connectToFastlaneAndRunLane(_ fastfile: LaneFile?) {
runner.startSocketThread(port: argumentProcessor.port)
let completedRun = Fastfile.runLane(from: fastfile, named: argumentProcessor.currentLane, with: argumentProcessor.laneParameters())
if completedRun {
runner.disconnectFromFastlaneProcess()
}
doneRunningLane = true
}
func startFastlaneThread(with fastFile: LaneFile?) {
#if !SWIFT_PACKAGE
thread = Thread(target: self, selector: #selector(connectToFastlaneAndRunLane), object: nil)
#else
thread = Thread(target: self, selector: #selector(connectToFastlaneAndRunLane), object: fastFile)
#endif
thread.name = "worker thread"
#if SWIFT_PACKAGE
let PATH = run("/bin/bash", "-c", "-l", "eval $(/usr/libexec/path_helper -s) ; echo $PATH").stdout
main.env["PATH"] = PATH
let path = main.run(bash: "which fastlane").stdout
let pids = main.run("lsof", "-t", "-i", ":\(argumentProcessor.port)").stdout.split(separator: "\n")
pids.forEach { main.run("kill", "-9", $0) }
rubySocketCommand = main.runAsync(path, "socket_server", "-c", argumentProcessor.commandTimeout, "-p", argumentProcessor.port)
lastPrintDate = Date()
rubySocketCommand.stderror.onStringOutput { print($0) }
rubySocketCommand.stdout.onStringOutput { stdout in
print(stdout)
self.timeBetweenPrints = Int(self.lastPrintDate.timeIntervalSinceNow)
}
// swiftformat:disable:next redundantSelf
_ = Runner.waitWithPolling(self.timeBetweenPrints, toEventually: { $0 > 5 }, timeout: 10)
thread.start()
#endif
}
}
public class Main {
let process = MainProcess()
public init() {}
public func run(with fastFile: LaneFile?) {
process.startFastlaneThread(with: fastFile)
while !process.doneRunningLane, RunLoop.current.run(mode: RunLoopMode.defaultRunLoopMode, before: Date(timeIntervalSinceNow: 2)) {
// no op
}
}
}

View File

@ -0,0 +1,20 @@
// Matchfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `match`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Matchfile: MatchfileProtocol {
// If you want to enable `match`, run `fastlane match init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,231 @@
// MatchfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol MatchfileProtocol: AnyObject {
/// Define the profile type, can be appstore, adhoc, development, enterprise, developer_id, mac_installer_distribution, developer_id_installer
var type: String { get }
/// Create additional cert types needed for macOS installers (valid values: mac_installer_distribution, developer_id_installer)
var additionalCertTypes: [String]? { get }
/// Only fetch existing certificates and profiles, don't generate new ones
var readonly: Bool { get }
/// Create a certificate type for Xcode 11 and later (Apple Development or Apple Distribution)
var generateAppleCerts: Bool { get }
/// Skip syncing provisioning profiles
var skipProvisioningProfiles: Bool { get }
/// The bundle identifier(s) of your app (comma-separated string or array of strings)
var appIdentifier: [String] { get }
/// Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
var apiKeyPath: String? { get }
/// Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
var apiKey: [String: Any]? { get }
/// Your Apple ID Username
var username: String? { get }
/// The ID of your Developer Portal team if you're in multiple teams
var teamId: String? { get }
/// The name of your Developer Portal team if you're in multiple teams
var teamName: String? { get }
/// Define where you want to store your certificates
var storageMode: String { get }
/// URL to the git repo containing all the certificates
var gitUrl: String { get }
/// Specific git branch to use
var gitBranch: String { get }
/// git user full name to commit
var gitFullName: String? { get }
/// git user email to commit
var gitUserEmail: String? { get }
/// Make a shallow clone of the repository (truncate the history to 1 revision)
var shallowClone: Bool { get }
/// Clone just the branch specified, instead of the whole repo. This requires that the branch already exists. Otherwise the command will fail
var cloneBranchDirectly: Bool { get }
/// Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
var gitBasicAuthorization: String? { get }
/// Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64
var gitBearerAuthorization: String? { get }
/// Use a private key to access the git repo (e.g.: access to GitHub repository via Deploy keys), usually a id_rsa named file or the contents hereof
var gitPrivateKey: String? { get }
/// Name of the Google Cloud Storage bucket to use
var googleCloudBucketName: String? { get }
/// Path to the gc_keys.json file
var googleCloudKeysFile: String? { get }
/// ID of the Google Cloud project to use for authentication
var googleCloudProjectId: String? { get }
/// Skips confirming to use the system google account
var skipGoogleCloudAccountConfirmation: Bool { get }
/// Name of the S3 region
var s3Region: String? { get }
/// S3 access key
var s3AccessKey: String? { get }
/// S3 secret access key
var s3SecretAccessKey: String? { get }
/// Name of the S3 bucket
var s3Bucket: String? { get }
/// Prefix to be used on all objects uploaded to S3
var s3ObjectPrefix: String? { get }
/// Skip encryption of all objects uploaded to S3. WARNING: only enable this on S3 buckets with sufficiently restricted permissions and server-side encryption enabled. See https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingEncryption.html
var s3SkipEncryption: Bool { get }
/// GitLab Project Path (i.e. 'gitlab-org/gitlab')
var gitlabProject: String? { get }
/// GitLab Host (i.e. 'https://gitlab.com')
var gitlabHost: String { get }
/// GitLab CI_JOB_TOKEN
var jobToken: String? { get }
/// GitLab Access Token
var privateToken: String? { get }
/// Keychain the items should be imported to
var keychainName: String { get }
/// This might be required the first time you access certificates on a new mac. For the login/default keychain this is your macOS account password
var keychainPassword: String? { get }
/// Renew the provisioning profiles every time you run match
var force: Bool { get }
/// Renew the provisioning profiles if the device count on the developer portal has changed. Ignored for profile types 'appstore' and 'developer_id'
var forceForNewDevices: Bool { get }
/// Include Apple Silicon Mac devices in provisioning profiles for iOS/iPadOS apps
var includeMacInProfiles: Bool { get }
/// Include all matching certificates in the provisioning profile. Works only for the 'development' provisioning profile type
var includeAllCertificates: Bool { get }
/// Select certificate by id. Useful if multiple certificates are stored in one place
var certificateId: String? { get }
/// Renew the provisioning profiles if the certificate count on the developer portal has changed. Works only for the 'development' provisioning profile type. Requires 'include_all_certificates' option to be 'true'
var forceForNewCertificates: Bool { get }
/// Disables confirmation prompts during nuke, answering them with yes
var skipConfirmation: Bool { get }
/// Remove certs from repository during nuke without revoking them on the developer portal
var safeRemoveCerts: Bool { get }
/// Skip generation of a README.md for the created git repository
var skipDocs: Bool { get }
/// Set the provisioning profile's platform to work with (i.e. ios, tvos, macos, catalyst)
var platform: String { get }
/// Enable this if you have the Mac Catalyst capability enabled and your project was created with Xcode 11.3 or earlier. Prepends 'maccatalyst.' to the app identifier for the provisioning profile mapping
var deriveCatalystAppIdentifier: Bool { get }
/// The name of provisioning profile template. If the developer account has provisioning profile templates (aka: custom entitlements), the template name can be found by inspecting the Entitlements drop-down while creating/editing a provisioning profile (e.g. "Apple Pay Pass Suppression Development")
var templateName: String? { get }
/// A custom name for the provisioning profile. This will replace the default provisioning profile name if specified
var profileName: String? { get }
/// Should the command fail if it was about to create a duplicate of an existing provisioning profile. It can happen due to issues on Apple Developer Portal, when profile to be recreated was not properly deleted first
var failOnNameTaken: Bool { get }
/// Set to true if there is no access to Apple developer portal but there are certificates, keys and profiles provided. Only works with match import action
var skipCertificateMatching: Bool { get }
/// Path in which to export certificates, key and profile
var outputPath: String? { get }
/// Skips setting the partition list (which can sometimes take a long time). Setting the partition list is usually needed to prevent Xcode from prompting to allow a cert to be used for signing
var skipSetPartitionList: Bool { get }
/// Print out extra information and all commands
var verbose: Bool { get }
}
public extension MatchfileProtocol {
var type: String { return "development" }
var additionalCertTypes: [String]? { return nil }
var readonly: Bool { return false }
var generateAppleCerts: Bool { return true }
var skipProvisioningProfiles: Bool { return false }
var appIdentifier: [String] { return [] }
var apiKeyPath: String? { return nil }
var apiKey: [String: Any]? { return nil }
var username: String? { return nil }
var teamId: String? { return nil }
var teamName: String? { return nil }
var storageMode: String { return "git" }
var gitUrl: String { return "" }
var gitBranch: String { return "master" }
var gitFullName: String? { return nil }
var gitUserEmail: String? { return nil }
var shallowClone: Bool { return false }
var cloneBranchDirectly: Bool { return false }
var gitBasicAuthorization: String? { return nil }
var gitBearerAuthorization: String? { return nil }
var gitPrivateKey: String? { return nil }
var googleCloudBucketName: String? { return nil }
var googleCloudKeysFile: String? { return nil }
var googleCloudProjectId: String? { return nil }
var skipGoogleCloudAccountConfirmation: Bool { return false }
var s3Region: String? { return nil }
var s3AccessKey: String? { return nil }
var s3SecretAccessKey: String? { return nil }
var s3Bucket: String? { return nil }
var s3ObjectPrefix: String? { return nil }
var s3SkipEncryption: Bool { return false }
var gitlabProject: String? { return nil }
var gitlabHost: String { return "https://gitlab.com" }
var jobToken: String? { return nil }
var privateToken: String? { return nil }
var keychainName: String { return "login.keychain" }
var keychainPassword: String? { return nil }
var force: Bool { return false }
var forceForNewDevices: Bool { return false }
var includeMacInProfiles: Bool { return false }
var includeAllCertificates: Bool { return false }
var certificateId: String? { return nil }
var forceForNewCertificates: Bool { return false }
var skipConfirmation: Bool { return false }
var safeRemoveCerts: Bool { return false }
var skipDocs: Bool { return false }
var platform: String { return "ios" }
var deriveCatalystAppIdentifier: Bool { return false }
var templateName: String? { return nil }
var profileName: String? { return nil }
var failOnNameTaken: Bool { return false }
var skipCertificateMatching: Bool { return false }
var outputPath: String? { return nil }
var skipSetPartitionList: Bool { return false }
var verbose: Bool { return false }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.121]

View File

@ -0,0 +1,101 @@
// OptionalConfigValue.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
public enum OptionalConfigValue<T> {
case fastlaneDefault(T)
case userDefined(T)
case `nil`
func asRubyArgument(name: String, type: RubyCommand.Argument.ArgType? = nil) -> RubyCommand.Argument? {
if case let .userDefined(value) = self {
return RubyCommand.Argument(name: name, value: value, type: type)
}
return nil
}
}
extension OptionalConfigValue: ExpressibleByUnicodeScalarLiteral where T == String? {
public typealias UnicodeScalarLiteralType = String
public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
self = .userDefined(value)
}
}
extension OptionalConfigValue: ExpressibleByExtendedGraphemeClusterLiteral where T == String? {
public typealias ExtendedGraphemeClusterLiteralType = String
public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
self = .userDefined(value)
}
}
extension OptionalConfigValue: ExpressibleByStringLiteral where T == String? {
public typealias StringLiteralType = String
public init(stringLiteral value: StringLiteralType) {
self = .userDefined(value)
}
}
extension OptionalConfigValue: ExpressibleByStringInterpolation where T == String? {}
extension OptionalConfigValue: ExpressibleByNilLiteral {
public init(nilLiteral _: ()) {
self = .nil
}
}
extension OptionalConfigValue: ExpressibleByIntegerLiteral where T == Int? {
public typealias IntegerLiteralType = Int
public init(integerLiteral value: IntegerLiteralType) {
self = .userDefined(value)
}
}
extension OptionalConfigValue: ExpressibleByArrayLiteral where T == [String] {
public typealias ArrayLiteralElement = String
public init(arrayLiteral elements: ArrayLiteralElement...) {
self = .userDefined(elements)
}
}
extension OptionalConfigValue: ExpressibleByFloatLiteral where T == Float {
public typealias FloatLiteralType = Float
public init(floatLiteral value: FloatLiteralType) {
self = .userDefined(value)
}
}
extension OptionalConfigValue: ExpressibleByBooleanLiteral where T == Bool {
public typealias BooleanLiteralType = Bool
public init(booleanLiteral value: BooleanLiteralType) {
self = .userDefined(value)
}
}
extension OptionalConfigValue: ExpressibleByDictionaryLiteral where T == [String: Any] {
public typealias Key = String
public typealias Value = Any
public init(dictionaryLiteral elements: (Key, Value)...) {
var dict: [Key: Value] = [:]
for element in elements {
dict[element.0] = element.1
}
self = .userDefined(dict)
}
}

View File

@ -0,0 +1,16 @@
// Plugins.swift
// Copyright (c) 2024 FastlaneTools
// This autogenerated file will be overwritten or replaced when installing/updating plugins or running "fastlane generate_swift"
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.56]

View File

@ -0,0 +1,20 @@
// Precheckfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `precheck`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Precheckfile: PrecheckfileProtocol {
// If you want to enable `precheck`, run `fastlane precheck init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,55 @@
// PrecheckfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol PrecheckfileProtocol: AnyObject {
/// Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
var apiKeyPath: String? { get }
/// Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-hash-option)
var apiKey: [String: Any]? { get }
/// The bundle identifier of your app
var appIdentifier: String { get }
/// Your Apple ID Username
var username: String? { get }
/// The ID of your App Store Connect team if you're in multiple teams
var teamId: String? { get }
/// The name of your App Store Connect team if you're in multiple teams
var teamName: String? { get }
/// The platform to use (optional)
var platform: String { get }
/// The default rule level unless otherwise configured
var defaultRuleLevel: String { get }
/// Should check in-app purchases?
var includeInAppPurchases: Bool { get }
/// Should force check live app?
var useLive: Bool { get }
/// using text indicating that your IAP is free
var freeStuffInIap: String? { get }
}
public extension PrecheckfileProtocol {
var apiKeyPath: String? { return nil }
var apiKey: [String: Any]? { return nil }
var appIdentifier: String { return "" }
var username: String? { return nil }
var teamId: String? { return nil }
var teamName: String? { return nil }
var platform: String { return "ios" }
var defaultRuleLevel: String { return "error" }
var includeInAppPurchases: Bool { return true }
var useLive: Bool { return false }
var freeStuffInIap: String? { return nil }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.120]

View File

@ -0,0 +1,157 @@
// RubyCommand.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
struct RubyCommand: RubyCommandable {
var type: CommandType { return .action }
struct Argument {
enum ArgType {
case stringClosure
var typeString: String {
switch self {
case .stringClosure:
return "string_closure" // this should match when is in ruby's SocketServerActionCommandExecutor
}
}
}
let name: String
let value: Any?
let type: ArgType?
init(name: String, value: Any?, type: ArgType? = nil) {
self.name = name
self.value = value
self.type = type
}
var hasValue: Bool {
return value != nil
}
var json: String {
if let someValue = value {
let typeJson: String
if let type = type {
typeJson = ", \"value_type\" : \"\(type.typeString)\""
} else {
typeJson = ""
}
if type == .stringClosure {
return "{\"name\" : \"\(name)\", \"value\" : \"ignored_for_closure\"\(typeJson)}"
} else if let array = someValue as? [String] {
return "{\"name\" : \"\(name)\", \"value\" : \(array)\(typeJson)}"
} else if let hash = someValue as? [String: Any] {
let jsonData = try! JSONSerialization.data(withJSONObject: hash, options: [])
let jsonString = String(data: jsonData, encoding: .utf8)!
return "{\"name\" : \"\(name)\", \"value\" : \(jsonString)\(typeJson)}"
} else {
let dictionary = [
"name": name,
"value": someValue,
]
let jsonData = try! JSONSerialization.data(withJSONObject: dictionary, options: [])
let jsonString = String(data: jsonData, encoding: .utf8)!
return jsonString
}
} else {
// Just exclude this arg if it doesn't have a value
return ""
}
}
}
let commandID: String
let methodName: String
let className: String?
let args: [Argument]
let id: String = UUID().uuidString
var closure: ((String) -> Void)? {
let callbacks = args.filter { ($0.type != nil) && $0.type == .stringClosure }
guard let callback = callbacks.first else {
return nil
}
guard let callbackArgValue = callback.value else {
return nil
}
guard let callbackClosure = callbackArgValue as? ((String) -> Void) else {
return nil
}
return callbackClosure
}
func callbackClosure(_ callbackArg: String) -> ((String) -> Void)? {
// WARNING: This will perform the first callback it receives
let callbacks = args.filter { ($0.type != nil) && $0.type == .stringClosure }
guard let callback = callbacks.first else {
verbose(message: "received call to performCallback with \(callbackArg), but no callback available to perform")
return nil
}
guard let callbackArgValue = callback.value else {
verbose(message: "received call to performCallback with \(callbackArg), but callback is nil")
return nil
}
guard let callbackClosure = callbackArgValue as? ((String) -> Void) else {
verbose(message: "received call to performCallback with \(callbackArg), but callback type is unknown \(callbackArgValue.self)")
return nil
}
return callbackClosure
}
func performCallback(callbackArg: String, socket: SocketClient, completion: @escaping () -> Void) {
verbose(message: "Performing callback with: \(callbackArg)")
socket.leave()
callbackClosure(callbackArg)?(callbackArg)
completion()
}
var commandJson: String {
let argsArrayJson = args
.map { $0.json }
.filter { $0 != "" }
let argsJson: String?
if !argsArrayJson.isEmpty {
argsJson = "\"args\" : [\(argsArrayJson.joined(separator: ","))]"
} else {
argsJson = nil
}
let commandIDJson = "\"commandID\" : \"\(commandID)\""
let methodNameJson = "\"methodName\" : \"\(methodName)\""
var jsonParts = [commandIDJson, methodNameJson]
if let argsJson = argsJson {
jsonParts.append(argsJson)
}
if let className = className {
let classNameJson = "\"className\" : \"\(className)\""
jsonParts.append(classNameJson)
}
let commandJsonString = "{\(jsonParts.joined(separator: ","))}"
return commandJsonString
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,43 @@
// RubyCommandable.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
enum CommandType {
case action
case control
var token: String {
switch self {
case .action:
return "action"
case .control:
return "control"
}
}
}
protocol RubyCommandable {
var type: CommandType { get }
var commandJson: String { get }
var id: String { get }
}
extension RubyCommandable {
var json: String {
return """
{ "commandType": "\(type.token)", "command": \(commandJson) }
"""
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

279
fastlane/swift/Runner.swift Normal file
View File

@ -0,0 +1,279 @@
// Runner.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
let logger: Logger = .init()
let runner: Runner = .init()
func desc(_: String) {
// no-op, this is handled in fastlane/lane_list.rb
}
class Runner {
private var thread: Thread!
private var socketClient: SocketClient!
private let dispatchGroup = DispatchGroup()
private var returnValue: String? // lol, so safe
private var currentlyExecutingCommand: RubyCommandable?
private var shouldLeaveDispatchGroupDuringDisconnect = false
private var executeNext: AtomicDictionary<String, Bool> = {
if #available(macOS 10.12, *) {
return UnfairAtomicDictionary<String, Bool>()
} else {
return OSSPinAtomicDictionary<String, Bool>()
}
}()
func executeCommand(_ command: RubyCommandable) -> String {
dispatchGroup.enter()
currentlyExecutingCommand = command
socketClient.send(rubyCommand: command)
let secondsToWait = DispatchTimeInterval.seconds(SocketClient.defaultCommandTimeoutSeconds)
// swiftformat:disable:next redundantSelf
let timeoutResult = Self.waitWithPolling(self.executeNext[command.id], toEventually: { $0 == true }, timeout: SocketClient.defaultCommandTimeoutSeconds)
executeNext.removeValue(forKey: command.id)
let failureMessage = "command didn't execute in: \(SocketClient.defaultCommandTimeoutSeconds) seconds"
let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
guard success else {
log(message: "command timeout")
preconditionFailure()
}
if let _returnValue = returnValue {
return _returnValue
} else {
return ""
}
}
static func waitWithPolling<T>(_ expression: @autoclosure @escaping () throws -> T, toEventually predicate: @escaping (T) -> Bool, timeout: Int, pollingInterval: DispatchTimeInterval = .milliseconds(4)) -> DispatchTimeoutResult {
func memoizedClosure<T>(_ closure: @escaping () throws -> T) -> (Bool) throws -> T {
var cache: T?
return { withoutCaching in
if withoutCaching || cache == nil {
cache = try closure()
}
guard let cache = cache else {
preconditionFailure()
}
return cache
}
}
let runLoop = RunLoop.current
let timeoutDate = Date(timeInterval: TimeInterval(timeout), since: Date())
var fulfilled = false
let _expression = memoizedClosure(expression)
repeat {
do {
let exp = try _expression(true)
fulfilled = predicate(exp)
} catch {
fatalError("Error raised \(error.localizedDescription)")
}
if !fulfilled {
runLoop.run(until: Date(timeIntervalSinceNow: pollingInterval.timeInterval))
} else {
break
}
} while Date().compare(timeoutDate) == .orderedAscending
if fulfilled {
return .success
} else {
return .timedOut
}
}
}
// Handle threading stuff
extension Runner {
func startSocketThread(port: UInt32) {
let secondsToWait = DispatchTimeInterval.seconds(SocketClient.connectTimeoutSeconds)
dispatchGroup.enter()
socketClient = SocketClient(port: port, commandTimeoutSeconds: timeout, socketDelegate: self)
thread = Thread(target: self, selector: #selector(startSocketComs), object: nil)
guard let thread = thread else {
preconditionFailure("Thread did not instantiate correctly")
}
thread.name = "socket thread"
thread.start()
let connectTimeout = DispatchTime.now() + secondsToWait
let timeoutResult = dispatchGroup.wait(timeout: connectTimeout)
let failureMessage = "couldn't start socket thread in: \(SocketClient.connectTimeoutSeconds) seconds"
let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
guard success else {
log(message: "socket thread timeout")
preconditionFailure()
}
}
func disconnectFromFastlaneProcess() {
shouldLeaveDispatchGroupDuringDisconnect = true
dispatchGroup.enter()
socketClient.sendComplete()
let connectTimeout = DispatchTime.now() + 2
_ = dispatchGroup.wait(timeout: connectTimeout)
}
@objc func startSocketComs() {
guard let socketClient = socketClient else {
return
}
socketClient.connectAndOpenStreams()
dispatchGroup.leave()
}
private func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait _: DispatchTimeInterval) -> Bool {
switch timeoutResult {
case .success:
return true
case .timedOut:
log(message: "timeout: \(failureMessage)")
return false
}
}
}
extension Runner: SocketClientDelegateProtocol {
func commandExecuted(serverResponse: SocketClientResponse, completion: (SocketClient) -> Void) {
switch serverResponse {
case let .success(returnedObject, closureArgumentValue):
verbose(message: "command executed")
returnValue = returnedObject
if let command = currentlyExecutingCommand as? RubyCommand {
if let closureArgumentValue = closureArgumentValue, !closureArgumentValue.isEmpty {
command.performCallback(callbackArg: closureArgumentValue, socket: socketClient) {
self.executeNext[command.id] = true
}
} else {
executeNext[command.id] = true
}
}
dispatchGroup.leave()
completion(socketClient)
case .clientInitiatedCancelAcknowledged:
verbose(message: "server acknowledged a cancel request")
dispatchGroup.leave()
if let command = currentlyExecutingCommand as? RubyCommand {
executeNext[command.id] = true
}
completion(socketClient)
case .alreadyClosedSockets, .connectionFailure, .malformedRequest, .malformedResponse, .serverError:
log(message: "error encountered while executing command:\n\(serverResponse)")
dispatchGroup.leave()
if let command = currentlyExecutingCommand as? RubyCommand {
executeNext[command.id] = true
}
completion(socketClient)
case let .commandTimeout(timeout):
log(message: "Runner timed out after \(timeout) second(s)")
}
}
func connectionsOpened() {
DispatchQueue.main.async {
verbose(message: "connected!")
}
}
func connectionsClosed() {
DispatchQueue.main.async {
if let thread = self.thread {
thread.cancel()
}
self.thread = nil
self.socketClient.closeSession()
self.socketClient = nil
verbose(message: "connection closed!")
if self.shouldLeaveDispatchGroupDuringDisconnect {
self.dispatchGroup.leave()
}
exit(0)
}
}
}
class Logger {
enum LogMode {
init(logMode: String) {
switch logMode {
case "normal", "default":
self = .normal
case "verbose":
self = .verbose
default:
logger.log(message: "unrecognized log mode: \(logMode), defaulting to 'normal'")
self = .normal
}
}
case normal
case verbose
}
public static var logMode: LogMode = .normal
func log(message: String) {
let timestamp = NSDate().timeIntervalSince1970
print("[\(timestamp)]: \(message)")
}
func verbose(message: String) {
if Logger.logMode == .verbose {
let timestamp = NSDate().timeIntervalSince1970
print("[\(timestamp)]: \(message)")
}
}
}
func log(message: String) {
logger.log(message: message)
}
func verbose(message: String) {
logger.verbose(message: message)
}
private extension DispatchTimeInterval {
var timeInterval: TimeInterval {
var result: TimeInterval = 0
switch self {
case let .seconds(value):
result = TimeInterval(value)
case let .milliseconds(value):
result = TimeInterval(value) * 0.001
case let .microseconds(value):
result = TimeInterval(value) * 0.000_001
case let .nanoseconds(value):
result = TimeInterval(value) * 0.000_000_001
case .never:
fatalError()
@unknown default:
fatalError()
}
return result
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,20 @@
// RunnerArgument.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
struct RunnerArgument {
let name: String
let value: String
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,20 @@
// Scanfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `scan`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Scanfile: ScanfileProtocol {
// If you want to enable `scan`, run `fastlane scan init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,323 @@
// ScanfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol ScanfileProtocol: AnyObject {
/// Path to the workspace file
var workspace: String? { get }
/// Path to the project file
var project: String? { get }
/// Path to the Swift Package
var packagePath: String? { get }
/// The project's scheme. Make sure it's marked as `Shared`
var scheme: String? { get }
/// The name of the simulator type you want to run tests on (e.g. 'iPhone 6' or 'iPhone SE (2nd generation) (14.5)')
var device: String? { get }
/// Array of devices to run the tests on (e.g. ['iPhone 6', 'iPad Air', 'iPhone SE (2nd generation) (14.5)'])
var devices: [String]? { get }
/// Should skip auto detecting of devices if none were specified
var skipDetectDevices: Bool { get }
/// Should fail if devices not found
var ensureDevicesFound: Bool { get }
/// Enabling this option will automatically killall Simulator processes before the run
var forceQuitSimulator: Bool { get }
/// Enabling this option will automatically erase the simulator before running the application
var resetSimulator: Bool { get }
/// Enabling this option will disable the simulator from showing the 'Slide to type' prompt
var disableSlideToType: Bool { get }
/// Enabling this option will launch the first simulator prior to calling any xcodebuild command
var prelaunchSimulator: Bool? { get }
/// Enabling this option will automatically uninstall the application before running it
var reinstallApp: Bool { get }
/// The bundle identifier of the app to uninstall (only needed when enabling reinstall_app)
var appIdentifier: String? { get }
/// Array of strings matching Test Bundle/Test Suite/Test Cases to run
var onlyTesting: String? { get }
/// Array of strings matching Test Bundle/Test Suite/Test Cases to skip
var skipTesting: String? { get }
/// The testplan associated with the scheme that should be used for testing
var testplan: String? { get }
/// Array of strings matching test plan configurations to run
var onlyTestConfigurations: String? { get }
/// Array of strings matching test plan configurations to skip
var skipTestConfigurations: String? { get }
/// Run tests using the provided `.xctestrun` file
var xctestrun: String? { get }
/// The toolchain that should be used for building the application (e.g. `com.apple.dt.toolchain.Swift_2_3, org.swift.30p620160816a`)
var toolchain: String? { get }
/// Should the project be cleaned before building it?
var clean: Bool { get }
/// Should code coverage be generated? (Xcode 7 and up)
var codeCoverage: Bool? { get }
/// Should the address sanitizer be turned on?
var addressSanitizer: Bool? { get }
/// Should the thread sanitizer be turned on?
var threadSanitizer: Bool? { get }
/// Should the HTML report be opened when tests are completed?
var openReport: Bool { get }
/// The directory in which all reports will be stored
var outputDirectory: String { get }
/// Define how the output should look like. Valid values are: standard, basic, rspec, or raw (disables xcpretty during xcodebuild)
var outputStyle: String? { get }
/// Comma separated list of the output types (e.g. html, junit, json-compilation-database)
var outputTypes: String { get }
/// Comma separated list of the output files, corresponding to the types provided by :output_types (order should match). If specifying an output type of json-compilation-database with :use_clang_report_name enabled, that option will take precedence
var outputFiles: String? { get }
/// The directory where to store the raw log
var buildlogPath: String { get }
/// If the logs generated by the app (e.g. using NSLog, perror, etc.) in the Simulator should be written to the output_directory
var includeSimulatorLogs: Bool { get }
/// Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path
var suppressXcodeOutput: Bool? { get }
/// xcodebuild formatter to use (ex: 'xcbeautify', 'xcbeautify --quieter', 'xcpretty', 'xcpretty -test'). Use empty string (ex: '') to disable any formatter (More information: https://docs.fastlane.tools/best-practices/xcodebuild-formatters/)
var xcodebuildFormatter: String { get }
/// Remove retry attempts from test results table and the JUnit report (if not using xcpretty)
var outputRemoveRetryAttempts: Bool { get }
/// **DEPRECATED!** Use `output_style: 'raw'` instead - Disable xcpretty formatting of build, similar to `output_style='raw'` but this will also skip the test results table
var disableXcpretty: Bool? { get }
/// **DEPRECATED!** Use 'xcpretty_formatter' instead - A custom xcpretty formatter to use
var formatter: String? { get }
/// A custom xcpretty formatter to use
var xcprettyFormatter: String? { get }
/// Pass in xcpretty additional command line arguments (e.g. '--test --no-color' or '--tap --no-utf')
var xcprettyArgs: String? { get }
/// The directory where build products and other derived data will go
var derivedDataPath: String? { get }
/// Should zip the derived data build products and place in output path?
var shouldZipBuildProducts: Bool { get }
/// Should provide additional copy of .xctestrun file (settings.xctestrun) and place in output path?
var outputXctestrun: Bool { get }
/// Custom path for the result bundle, overrides result_bundle
var resultBundlePath: String? { get }
/// Should an Xcode result bundle be generated in the output directory
var resultBundle: Bool { get }
/// Generate the json compilation database with clang naming convention (compile_commands.json)
var useClangReportName: Bool { get }
/// Optionally override the per-target setting in the scheme for running tests in parallel. Equivalent to -parallel-testing-enabled
var parallelTesting: Bool? { get }
/// Specify the exact number of test runners that will be spawned during parallel testing. Equivalent to -parallel-testing-worker-count
var concurrentWorkers: Int? { get }
/// Constrain the number of simulator devices on which to test concurrently. Equivalent to -maximum-concurrent-test-simulator-destinations
var maxConcurrentSimulators: Int? { get }
/// Do not run test bundles in parallel on the specified destinations. Testing will occur on each destination serially. Equivalent to -disable-concurrent-testing
var disableConcurrentTesting: Bool { get }
/// Should debug build be skipped before test build?
var skipBuild: Bool { get }
/// Test without building, requires a derived data path
var testWithoutBuilding: Bool? { get }
/// Build for testing only, does not run tests
var buildForTesting: Bool? { get }
/// The SDK that should be used for building the application
var sdk: String? { get }
/// The configuration to use when building the app. Defaults to 'Release'
var configuration: String? { get }
/// Pass additional arguments to xcodebuild. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
var xcargs: String? { get }
/// Use an extra XCCONFIG file to build your app
var xcconfig: String? { get }
/// App name to use in slack message and logfile name
var appName: String? { get }
/// Target version of the app being build or tested. Used to filter out simulator version
var deploymentTargetVersion: String? { get }
/// Create an Incoming WebHook for your Slack group to post results there
var slackUrl: String? { get }
/// #channel or @username
var slackChannel: String? { get }
/// The message included with each message posted to slack
var slackMessage: String? { get }
/// Use webhook's default username and icon settings? (true/false)
var slackUseWebhookConfiguredUsernameAndIcon: Bool { get }
/// Overrides the webhook's username property if slack_use_webhook_configured_username_and_icon is false
var slackUsername: String { get }
/// Overrides the webhook's image property if slack_use_webhook_configured_username_and_icon is false
var slackIconUrl: String { get }
/// Don't publish to slack, even when an URL is given
var skipSlack: Bool { get }
/// Only post on Slack if the tests fail
var slackOnlyOnFailure: Bool { get }
/// Specifies default payloads to include in Slack messages. For more info visit https://docs.fastlane.tools/actions/slack
var slackDefaultPayloads: [String]? { get }
/// Use only if you're a pro, use the other options instead
var destination: String? { get }
/// Adds arch=x86_64 to the xcodebuild 'destination' argument to run simulator in a Rosetta mode
var runRosettaSimulator: Bool { get }
/// Platform to build when using a Catalyst enabled app. Valid values are: ios, macos
var catalystPlatform: String? { get }
/// **DEPRECATED!** Use `--output_files` instead - Sets custom full report file name when generating a single report
var customReportFileName: String? { get }
/// Allows for override of the default `xcodebuild` command
var xcodebuildCommand: String { get }
/// Sets a custom path for Swift Package Manager dependencies
var clonedSourcePackagesPath: String? { get }
/// Skips resolution of Swift Package Manager dependencies
var skipPackageDependenciesResolution: Bool { get }
/// Prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file
var disablePackageAutomaticUpdates: Bool { get }
/// Lets xcodebuild use system's scm configuration
var useSystemScm: Bool { get }
/// The number of times a test can fail
var numberOfRetries: Int { get }
/// Should this step stop the build if the tests fail? Set this to false if you're using trainer
var failBuild: Bool { get }
}
public extension ScanfileProtocol {
var workspace: String? { return nil }
var project: String? { return nil }
var packagePath: String? { return nil }
var scheme: String? { return nil }
var device: String? { return nil }
var devices: [String]? { return nil }
var skipDetectDevices: Bool { return false }
var ensureDevicesFound: Bool { return false }
var forceQuitSimulator: Bool { return false }
var resetSimulator: Bool { return false }
var disableSlideToType: Bool { return true }
var prelaunchSimulator: Bool? { return nil }
var reinstallApp: Bool { return false }
var appIdentifier: String? { return nil }
var onlyTesting: String? { return nil }
var skipTesting: String? { return nil }
var testplan: String? { return nil }
var onlyTestConfigurations: String? { return nil }
var skipTestConfigurations: String? { return nil }
var xctestrun: String? { return nil }
var toolchain: String? { return nil }
var clean: Bool { return false }
var codeCoverage: Bool? { return nil }
var addressSanitizer: Bool? { return nil }
var threadSanitizer: Bool? { return nil }
var openReport: Bool { return false }
var outputDirectory: String { return "./test_output" }
var outputStyle: String? { return nil }
var outputTypes: String { return "html,junit" }
var outputFiles: String? { return nil }
var buildlogPath: String { return "~/Library/Logs/scan" }
var includeSimulatorLogs: Bool { return false }
var suppressXcodeOutput: Bool? { return nil }
var xcodebuildFormatter: String { return "xcbeautify" }
var outputRemoveRetryAttempts: Bool { return false }
var disableXcpretty: Bool? { return nil }
var formatter: String? { return nil }
var xcprettyFormatter: String? { return nil }
var xcprettyArgs: String? { return nil }
var derivedDataPath: String? { return nil }
var shouldZipBuildProducts: Bool { return false }
var outputXctestrun: Bool { return false }
var resultBundlePath: String? { return nil }
var resultBundle: Bool { return false }
var useClangReportName: Bool { return false }
var parallelTesting: Bool? { return nil }
var concurrentWorkers: Int? { return nil }
var maxConcurrentSimulators: Int? { return nil }
var disableConcurrentTesting: Bool { return false }
var skipBuild: Bool { return false }
var testWithoutBuilding: Bool? { return nil }
var buildForTesting: Bool? { return nil }
var sdk: String? { return nil }
var configuration: String? { return nil }
var xcargs: String? { return nil }
var xcconfig: String? { return nil }
var appName: String? { return nil }
var deploymentTargetVersion: String? { return nil }
var slackUrl: String? { return nil }
var slackChannel: String? { return nil }
var slackMessage: String? { return nil }
var slackUseWebhookConfiguredUsernameAndIcon: Bool { return false }
var slackUsername: String { return "fastlane" }
var slackIconUrl: String { return "https://fastlane.tools/assets/img/fastlane_icon.png" }
var skipSlack: Bool { return false }
var slackOnlyOnFailure: Bool { return false }
var slackDefaultPayloads: [String]? { return nil }
var destination: String? { return nil }
var runRosettaSimulator: Bool { return false }
var catalystPlatform: String? { return nil }
var customReportFileName: String? { return nil }
var xcodebuildCommand: String { return "env NSUnbufferedIO=YES xcodebuild" }
var clonedSourcePackagesPath: String? { return nil }
var skipPackageDependenciesResolution: Bool { return false }
var disablePackageAutomaticUpdates: Bool { return false }
var useSystemScm: Bool { return false }
var numberOfRetries: Int { return 0 }
var failBuild: Bool { return true }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.132]

View File

@ -0,0 +1,20 @@
// Screengrabfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `screengrab`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Screengrabfile: ScreengrabfileProtocol {
// If you want to enable `screengrab`, run `fastlane screengrab init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,99 @@
// ScreengrabfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol ScreengrabfileProtocol: AnyObject {
/// Path to the root of your Android SDK installation, e.g. ~/tools/android-sdk-macosx
var androidHome: String? { get }
/// **DEPRECATED!** The Android build tools version to use, e.g. '23.0.2'
var buildToolsVersion: String? { get }
/// A list of locales which should be used
var locales: [String] { get }
/// Enabling this option will automatically clear previously generated screenshots before running screengrab
var clearPreviousScreenshots: Bool { get }
/// The directory where to store the screenshots
var outputDirectory: String { get }
/// Don't open the summary after running _screengrab_
var skipOpenSummary: Bool { get }
/// The package name of the app under test (e.g. com.yourcompany.yourapp)
var appPackageName: String { get }
/// The package name of the tests bundle (e.g. com.yourcompany.yourapp.test)
var testsPackageName: String? { get }
/// Only run tests in these Java packages
var useTestsInPackages: [String]? { get }
/// Only run tests in these Java classes
var useTestsInClasses: [String]? { get }
/// Additional launch arguments
var launchArguments: [String]? { get }
/// The fully qualified class name of your test instrumentation runner
var testInstrumentationRunner: String { get }
/// **DEPRECATED!** Return the device to this locale after running tests
var endingLocale: String { get }
/// **DEPRECATED!** Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors
var useAdbRoot: Bool { get }
/// The path to the APK for the app under test
var appApkPath: String? { get }
/// The path to the APK for the tests bundle
var testsApkPath: String? { get }
/// Use the device or emulator with the given serial number or qualifier
var specificDevice: String? { get }
/// Type of device used for screenshots. Matches Google Play Types (phone, sevenInch, tenInch, tv, wear)
var deviceType: String { get }
/// Whether or not to exit Screengrab on test failure. Exiting on failure will not copy screenshots to local machine nor open screenshots summary
var exitOnTestFailure: Bool { get }
/// Enabling this option will automatically uninstall the application before running it
var reinstallApp: Bool { get }
/// Add timestamp suffix to screenshot filename
var useTimestampSuffix: Bool { get }
/// Configure the host used by adb to connect, allows running on remote devices farm
var adbHost: String? { get }
}
public extension ScreengrabfileProtocol {
var androidHome: String? { return nil }
var buildToolsVersion: String? { return nil }
var locales: [String] { return ["en-US"] }
var clearPreviousScreenshots: Bool { return false }
var outputDirectory: String { return "fastlane/metadata/android" }
var skipOpenSummary: Bool { return false }
var appPackageName: String { return "" }
var testsPackageName: String? { return nil }
var useTestsInPackages: [String]? { return nil }
var useTestsInClasses: [String]? { return nil }
var launchArguments: [String]? { return nil }
var testInstrumentationRunner: String { return "androidx.test.runner.AndroidJUnitRunner" }
var endingLocale: String { return "en-US" }
var useAdbRoot: Bool { return false }
var appApkPath: String? { return nil }
var testsApkPath: String? { return nil }
var specificDevice: String? { return nil }
var deviceType: String { return "phone" }
var exitOnTestFailure: Bool { return true }
var reinstallApp: Bool { return false }
var useTimestampSuffix: Bool { return true }
var adbHost: String? { return nil }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.122]

View File

@ -0,0 +1,20 @@
// Snapshotfile.swift
// Copyright (c) 2024 FastlaneTools
// This class is automatically included in FastlaneRunner during build
// This autogenerated file will be overwritten or replaced during build time, or when you initialize `snapshot`
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
public class Snapshotfile: SnapshotfileProtocol {
// If you want to enable `snapshot`, run `fastlane snapshot init`
// After, this file will be replaced with a custom implementation that contains values you supplied
// during the `init` process, and you won't see this message
}
// Generated with fastlane 2.220.0

View File

@ -0,0 +1,207 @@
// SnapshotfileProtocol.swift
// Copyright (c) 2024 FastlaneTools
public protocol SnapshotfileProtocol: AnyObject {
/// Path to the workspace file
var workspace: String? { get }
/// Path to the project file
var project: String? { get }
/// Pass additional arguments to xcodebuild for the test phase. Be sure to quote the setting names and values e.g. OTHER_LDFLAGS="-ObjC -lstdc++"
var xcargs: String? { get }
/// Use an extra XCCONFIG file to build your app
var xcconfig: String? { get }
/// A list of devices you want to take the screenshots from
var devices: [String]? { get }
/// A list of languages which should be used
var languages: [String] { get }
/// A list of launch arguments which should be used
var launchArguments: [String] { get }
/// The directory where to store the screenshots
var outputDirectory: String { get }
/// If the logs generated by the app (e.g. using NSLog, perror, etc.) in the Simulator should be written to the output_directory
var outputSimulatorLogs: Bool { get }
/// By default, the latest version should be used automatically. If you want to change it, do it here
var iosVersion: String? { get }
/// Don't open the HTML summary after running _snapshot_
var skipOpenSummary: Bool { get }
/// Do not check for most recent SnapshotHelper code
var skipHelperVersionCheck: Bool { get }
/// Enabling this option will automatically clear previously generated screenshots before running snapshot
var clearPreviousScreenshots: Bool { get }
/// Enabling this option will automatically uninstall the application before running it
var reinstallApp: Bool { get }
/// Enabling this option will automatically erase the simulator before running the application
var eraseSimulator: Bool { get }
/// Enabling this option will prevent displaying the simulator window
var headless: Bool { get }
/// Enabling this option will automatically override the status bar to show 9:41 AM, full battery, and full reception (Adjust 'SNAPSHOT_SIMULATOR_WAIT_FOR_BOOT_TIMEOUT' environment variable if override status bar is not working. Might be because simulator is not fully booted. Defaults to 10 seconds)
var overrideStatusBar: Bool { get }
/// Fully customize the status bar by setting each option here. Requires `override_status_bar` to be set to `true`. See `xcrun simctl status_bar --help`
var overrideStatusBarArguments: String? { get }
/// Enabling this option will configure the Simulator's system language
var localizeSimulator: Bool { get }
/// Enabling this option will configure the Simulator to be in dark mode (false for light, true for dark)
var darkMode: Bool? { get }
/// The bundle identifier of the app to uninstall (only needed when enabling reinstall_app)
var appIdentifier: String? { get }
/// A list of photos that should be added to the simulator before running the application
var addPhotos: [String]? { get }
/// A list of videos that should be added to the simulator before running the application
var addVideos: [String]? { get }
/// A path to screenshots.html template
var htmlTemplate: String? { get }
/// The directory where to store the build log
var buildlogPath: String { get }
/// Should the project be cleaned before building it?
var clean: Bool { get }
/// Test without building, requires a derived data path
var testWithoutBuilding: Bool? { get }
/// The configuration to use when building the app. Defaults to 'Release'
var configuration: String? { get }
/// The SDK that should be used for building the application
var sdk: String? { get }
/// The scheme you want to use, this must be the scheme for the UI Tests
var scheme: String? { get }
/// The number of times a test can fail before snapshot should stop retrying
var numberOfRetries: Int { get }
/// Should snapshot stop immediately after the tests completely failed on one device?
var stopAfterFirstError: Bool { get }
/// The directory where build products and other derived data will go
var derivedDataPath: String? { get }
/// Should an Xcode result bundle be generated in the output directory
var resultBundle: Bool { get }
/// The name of the target you want to test (if you desire to override the Target Application from Xcode)
var testTargetName: String? { get }
/// Separate the log files per device and per language
var namespaceLogFiles: String? { get }
/// Take snapshots on multiple simulators concurrently. Note: This option is only applicable when running against Xcode 9
var concurrentSimulators: Bool { get }
/// Disable the simulator from showing the 'Slide to type' prompt
var disableSlideToType: Bool { get }
/// Sets a custom path for Swift Package Manager dependencies
var clonedSourcePackagesPath: String? { get }
/// Skips resolution of Swift Package Manager dependencies
var skipPackageDependenciesResolution: Bool { get }
/// Prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file
var disablePackageAutomaticUpdates: Bool { get }
/// The testplan associated with the scheme that should be used for testing
var testplan: String? { get }
/// Array of strings matching Test Bundle/Test Suite/Test Cases to run
var onlyTesting: String? { get }
/// Array of strings matching Test Bundle/Test Suite/Test Cases to skip
var skipTesting: String? { get }
/// xcodebuild formatter to use (ex: 'xcbeautify', 'xcbeautify --quieter', 'xcpretty', 'xcpretty -test'). Use empty string (ex: '') to disable any formatter (More information: https://docs.fastlane.tools/best-practices/xcodebuild-formatters/)
var xcodebuildFormatter: String { get }
/// **DEPRECATED!** Use `xcodebuild_formatter: ''` instead - Additional xcpretty arguments
var xcprettyArgs: String? { get }
/// Disable xcpretty formatting of build
var disableXcpretty: Bool? { get }
/// Suppress the output of xcodebuild to stdout. Output is still saved in buildlog_path
var suppressXcodeOutput: Bool? { get }
/// Lets xcodebuild use system's scm configuration
var useSystemScm: Bool { get }
}
public extension SnapshotfileProtocol {
var workspace: String? { return nil }
var project: String? { return nil }
var xcargs: String? { return nil }
var xcconfig: String? { return nil }
var devices: [String]? { return nil }
var languages: [String] { return ["en-US"] }
var launchArguments: [String] { return [""] }
var outputDirectory: String { return "screenshots" }
var outputSimulatorLogs: Bool { return false }
var iosVersion: String? { return nil }
var skipOpenSummary: Bool { return false }
var skipHelperVersionCheck: Bool { return false }
var clearPreviousScreenshots: Bool { return false }
var reinstallApp: Bool { return false }
var eraseSimulator: Bool { return false }
var headless: Bool { return true }
var overrideStatusBar: Bool { return false }
var overrideStatusBarArguments: String? { return nil }
var localizeSimulator: Bool { return false }
var darkMode: Bool? { return nil }
var appIdentifier: String? { return nil }
var addPhotos: [String]? { return nil }
var addVideos: [String]? { return nil }
var htmlTemplate: String? { return nil }
var buildlogPath: String { return "~/Library/Logs/snapshot" }
var clean: Bool { return false }
var testWithoutBuilding: Bool? { return nil }
var configuration: String? { return nil }
var sdk: String? { return nil }
var scheme: String? { return nil }
var numberOfRetries: Int { return 1 }
var stopAfterFirstError: Bool { return false }
var derivedDataPath: String? { return nil }
var resultBundle: Bool { return false }
var testTargetName: String? { return nil }
var namespaceLogFiles: String? { return nil }
var concurrentSimulators: Bool { return true }
var disableSlideToType: Bool { return false }
var clonedSourcePackagesPath: String? { return nil }
var skipPackageDependenciesResolution: Bool { return false }
var disablePackageAutomaticUpdates: Bool { return false }
var testplan: String? { return nil }
var onlyTesting: String? { return nil }
var skipTesting: String? { return nil }
var xcodebuildFormatter: String { return "xcbeautify" }
var xcprettyArgs: String? { return nil }
var disableXcpretty: Bool? { return nil }
var suppressXcodeOutput: Bool? { return nil }
var useSystemScm: Bool { return false }
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.116]

View File

@ -0,0 +1,332 @@
// SocketClient.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Dispatch
import Foundation
public enum SocketClientResponse: Error {
case alreadyClosedSockets
case malformedRequest
case malformedResponse
case serverError
case clientInitiatedCancelAcknowledged
case commandTimeout(seconds: Int)
case connectionFailure
case success(returnedObject: String?, closureArgumentValue: String?)
}
class SocketClient: NSObject {
enum SocketStatus {
case ready
case closed
}
static let connectTimeoutSeconds = 2
static let defaultCommandTimeoutSeconds = 10800 // 3 hours
static let doneToken = "done" // TODO: remove these
static let cancelToken = "cancelFastlaneRun"
fileprivate var inputStream: InputStream!
fileprivate var outputStream: OutputStream!
fileprivate var cleaningUpAfterDone = false
fileprivate let dispatchGroup = DispatchGroup()
fileprivate let readSemaphore = DispatchSemaphore(value: 1)
fileprivate let writeSemaphore = DispatchSemaphore(value: 1)
fileprivate let commandTimeoutSeconds: Int
private let writeQueue: DispatchQueue
private let readQueue: DispatchQueue
private let streamQueue: DispatchQueue
private let host: String
private let port: UInt32
let maxReadLength = 65536 // max for ipc on 10.12 is kern.ipc.maxsockbuf: 8388608 ($sysctl kern.ipc.maxsockbuf)
private(set) weak var socketDelegate: SocketClientDelegateProtocol?
public private(set) var socketStatus: SocketStatus
// localhost only, this prevents other computers from connecting
init(host: String = "localhost", port: UInt32 = 2000, commandTimeoutSeconds: Int = defaultCommandTimeoutSeconds, socketDelegate: SocketClientDelegateProtocol) {
self.host = host
self.port = port
self.commandTimeoutSeconds = commandTimeoutSeconds
readQueue = DispatchQueue(label: "readQueue", qos: .background, attributes: .concurrent)
writeQueue = DispatchQueue(label: "writeQueue", qos: .background, attributes: .concurrent)
streamQueue = DispatchQueue.global(qos: .background)
socketStatus = .closed
self.socketDelegate = socketDelegate
super.init()
}
func connectAndOpenStreams() {
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
streamQueue.sync {
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, self.host as CFString, self.port, &readStream, &writeStream)
self.inputStream = readStream!.takeRetainedValue()
self.outputStream = writeStream!.takeRetainedValue()
self.inputStream.delegate = self
self.outputStream.delegate = self
self.inputStream.schedule(in: .main, forMode: .defaultRunLoopMode)
self.outputStream.schedule(in: .main, forMode: .defaultRunLoopMode)
}
dispatchGroup.enter()
readQueue.sync {
self.inputStream.open()
}
dispatchGroup.enter()
writeQueue.sync {
self.outputStream.open()
}
let secondsToWait = DispatchTimeInterval.seconds(SocketClient.connectTimeoutSeconds)
let connectTimeout = DispatchTime.now() + secondsToWait
let timeoutResult = dispatchGroup.wait(timeout: connectTimeout)
let failureMessage = "Couldn't connect to ruby process within: \(SocketClient.connectTimeoutSeconds) seconds"
let success = testDispatchTimeoutResult(timeoutResult, failureMessage: failureMessage, timeToWait: secondsToWait)
guard success else {
socketDelegate?.commandExecuted(serverResponse: .connectionFailure) { _ in }
return
}
socketStatus = .ready
socketDelegate?.connectionsOpened()
}
public func send(rubyCommand: RubyCommandable) {
verbose(message: "sending: \(rubyCommand.json)")
send(string: rubyCommand.json)
writeSemaphore.signal()
}
public func sendComplete() {
closeSession(sendAbort: true)
}
private func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait: DispatchTimeInterval) -> Bool {
switch timeoutResult {
case .success:
return true
case .timedOut:
log(message: "Timeout: \(failureMessage)")
if case let .seconds(seconds) = timeToWait {
socketDelegate?.commandExecuted(serverResponse: .commandTimeout(seconds: seconds)) { _ in }
}
return false
}
}
private func stopInputSession() {
inputStream.close()
}
private func stopOutputSession() {
outputStream.close()
}
private func sendThroughQueue(string: String) {
let data = string.data(using: .utf8)!
data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
if let buffer = buffer.baseAddress {
self.outputStream.write(buffer.assumingMemoryBound(to: UInt8.self), maxLength: data.count)
}
}
}
private func privateSend(string: String) {
writeQueue.sync {
writeSemaphore.wait()
self.sendThroughQueue(string: string)
writeSemaphore.signal()
let timeoutSeconds = self.cleaningUpAfterDone ? 1 : self.commandTimeoutSeconds
let timeToWait = DispatchTimeInterval.seconds(timeoutSeconds)
let commandTimeout = DispatchTime.now() + timeToWait
let timeoutResult = writeSemaphore.wait(timeout: commandTimeout)
_ = self.testDispatchTimeoutResult(timeoutResult, failureMessage: "Ruby process didn't return after: \(SocketClient.connectTimeoutSeconds) seconds", timeToWait: timeToWait)
}
}
private func send(string: String) {
guard !cleaningUpAfterDone else {
// This will happen after we abort if there are commands waiting to be executed
// Need to check state of SocketClient in command runner to make sure we can accept `send`
socketDelegate?.commandExecuted(serverResponse: .alreadyClosedSockets) { _ in }
return
}
if string == SocketClient.doneToken {
cleaningUpAfterDone = true
}
privateSend(string: string)
}
func closeSession(sendAbort: Bool = true) {
socketStatus = .closed
stopInputSession()
if sendAbort {
send(rubyCommand: ControlCommand(commandType: .done))
}
stopOutputSession()
socketDelegate?.connectionsClosed()
}
public func enter() {
dispatchGroup.enter()
}
public func leave() {
readSemaphore.signal()
writeSemaphore.signal()
}
}
extension SocketClient: StreamDelegate {
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
guard !cleaningUpAfterDone else {
// Still getting response from server even though we are done.
// No big deal, we're closing the streams anyway.
// That being said, we need to balance out the dispatchGroups
dispatchGroup.leave()
return
}
if aStream === inputStream {
switch eventCode {
case Stream.Event.openCompleted:
dispatchGroup.leave()
case Stream.Event.errorOccurred:
verbose(message: "input stream error occurred")
closeSession(sendAbort: true)
case Stream.Event.hasBytesAvailable:
read()
case Stream.Event.endEncountered:
// nothing special here
break
case Stream.Event.hasSpaceAvailable:
// we don't care about this
break
default:
verbose(message: "input stream caused unrecognized event: \(eventCode)")
}
} else if aStream === outputStream {
switch eventCode {
case Stream.Event.openCompleted:
dispatchGroup.leave()
case Stream.Event.errorOccurred:
// probably safe to close all the things because Ruby already disconnected
verbose(message: "output stream received error")
case Stream.Event.endEncountered:
// nothing special here
break
case Stream.Event.hasSpaceAvailable:
// we don't care about this
break
default:
verbose(message: "output stream caused unrecognized event: \(eventCode)")
}
}
}
func read() {
readQueue.sync {
self.readSemaphore.wait()
var buffer = [UInt8](repeating: 0, count: maxReadLength)
var output = ""
while self.inputStream!.hasBytesAvailable {
let bytesRead: Int = inputStream!.read(&buffer, maxLength: buffer.count)
if bytesRead >= 0 {
guard let read = String(bytes: buffer[..<bytesRead], encoding: .utf8) else {
fatalError("Unable to decode bytes from buffer \(buffer[..<bytesRead])")
}
output.append(contentsOf: read)
} else {
verbose(message: "Stream read() error")
}
}
self.processResponse(string: output)
readSemaphore.signal()
}
}
func handleFailure(message: [String]) {
log(message: "Encountered a problem: \(message.joined(separator: "\n"))")
let shutdownCommand = ControlCommand(commandType: .cancel(cancelReason: .serverError))
send(rubyCommand: shutdownCommand)
}
func processResponse(string: String) {
guard !string.isEmpty else {
socketDelegate?.commandExecuted(serverResponse: .malformedResponse) {
self.handleFailure(message: ["empty response from ruby process"])
$0.writeSemaphore.signal()
}
return
}
let responseString = string.trimmingCharacters(in: .whitespacesAndNewlines)
let socketResponse = SocketResponse(payload: responseString)
verbose(message: "response is: \(responseString)")
switch socketResponse.responseType {
case .clientInitiatedCancel:
socketDelegate?.commandExecuted(serverResponse: .clientInitiatedCancelAcknowledged) {
$0.writeSemaphore.signal()
self.closeSession(sendAbort: false)
}
case let .failure(failureInformation, failureClass, failureMessage):
LaneFile.fastfileInstance?.onError(currentLane: ArgumentProcessor(args: CommandLine.arguments).currentLane, errorInfo: failureInformation.joined(), errorClass: failureClass, errorMessage: failureMessage)
socketDelegate?.commandExecuted(serverResponse: .serverError) {
$0.writeSemaphore.signal()
self.handleFailure(message: failureMessage.map { m in [m] + failureInformation } ?? failureInformation)
}
case let .parseFailure(failureInformation):
socketDelegate?.commandExecuted(serverResponse: .malformedResponse) {
$0.writeSemaphore.signal()
self.handleFailure(message: failureInformation)
}
case let .readyForNext(returnedObject, closureArgumentValue):
socketDelegate?.commandExecuted(serverResponse: .success(returnedObject: returnedObject, closureArgumentValue: closureArgumentValue)) {
$0.writeSemaphore.signal()
}
}
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,21 @@
// SocketClientDelegateProtocol.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
protocol SocketClientDelegateProtocol: AnyObject {
func connectionsOpened()
func connectionsClosed()
func commandExecuted(serverResponse: SocketClientResponse, completion: (SocketClient) -> Void)
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1,84 @@
// SocketResponse.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
struct SocketResponse {
enum ResponseType {
case parseFailure(failureInformation: [String])
case failure(failureInformation: [String], failureClass: String?, failureMessage: String?)
case readyForNext(returnedObject: String?, closureArgumentValue: String?)
case clientInitiatedCancel
init(statusDictionary: [String: Any]) {
guard let status = statusDictionary["status"] as? String else {
self = .parseFailure(failureInformation: ["Message failed to parse from Ruby server"])
return
}
if status == "ready_for_next" {
verbose(message: "ready for next")
let returnedObject = statusDictionary["return_object"] as? String
let closureArgumentValue = statusDictionary["closure_argument_value"] as? String
self = .readyForNext(returnedObject: returnedObject, closureArgumentValue: closureArgumentValue)
return
} else if status == "cancelled" {
self = .clientInitiatedCancel
return
} else if status == "failure" {
guard let failureInformation = statusDictionary["failure_information"] as? [String] else {
self = .parseFailure(failureInformation: ["Ruby server indicated failure but Swift couldn't receive it"])
return
}
let failureClass = statusDictionary["failure_class"] as? String
let failureMessage = statusDictionary["failure_message"] as? String
self = .failure(failureInformation: failureInformation, failureClass: failureClass, failureMessage: failureMessage)
return
}
self = .parseFailure(failureInformation: ["Message status: \(status) not a supported status"])
}
}
let responseType: ResponseType
init(payload: String) {
guard let data = SocketResponse.convertToDictionary(text: payload) else {
responseType = .parseFailure(failureInformation: ["Unable to parse message from Ruby server"])
return
}
guard case let statusDictionary? = data["payload"] as? [String: Any] else {
responseType = .parseFailure(failureInformation: ["Payload missing from Ruby server response"])
return
}
responseType = ResponseType(statusDictionary: statusDictionary)
}
}
extension SocketResponse {
static func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
log(message: error.localizedDescription)
}
}
return nil
}
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1 @@
brew("swiftformat")

View File

@ -0,0 +1,94 @@
{
"entries": {
"brew": {
"swiftformat": {
"version": "0.53.5",
"bottle": {
"rebuild": 0,
"root_url": "https://ghcr.io/v2/homebrew/core",
"files": {
"arm64_sonoma": {
"cellar": ":any_skip_relocation",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:04e089d4b1ae1217dd6c8133b3c661add56d7c4f4f24ee67becd3cf8f54e6e80",
"sha256": "04e089d4b1ae1217dd6c8133b3c661add56d7c4f4f24ee67becd3cf8f54e6e80"
},
"arm64_ventura": {
"cellar": ":any_skip_relocation",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:19a6ce102e7df1cdee150dee619025aa3b2a4980070bee4f8cdd6976c0936d46",
"sha256": "19a6ce102e7df1cdee150dee619025aa3b2a4980070bee4f8cdd6976c0936d46"
},
"arm64_monterey": {
"cellar": ":any_skip_relocation",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:745ba037da0e1fe62f2f22faa45a17655b89d8870bacd9db32597ce1fd779509",
"sha256": "745ba037da0e1fe62f2f22faa45a17655b89d8870bacd9db32597ce1fd779509"
},
"sonoma": {
"cellar": ":any_skip_relocation",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:6830f0bd5d06dca19d2bcd614e6d0c87e7a3d703d33bce90d0448a83310dddcc",
"sha256": "6830f0bd5d06dca19d2bcd614e6d0c87e7a3d703d33bce90d0448a83310dddcc"
},
"ventura": {
"cellar": ":any_skip_relocation",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:dacbfeca6cbe99fc73448f08c0289f135e807bc220ac1dcb61952410f1b43535",
"sha256": "dacbfeca6cbe99fc73448f08c0289f135e807bc220ac1dcb61952410f1b43535"
},
"monterey": {
"cellar": ":any_skip_relocation",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:a5e30f5378aca201ca8bc7a350ebac28b3202366be1b37cf254f77c27761753a",
"sha256": "a5e30f5378aca201ca8bc7a350ebac28b3202366be1b37cf254f77c27761753a"
},
"x86_64_linux": {
"cellar": "/home/linuxbrew/.linuxbrew/Cellar",
"url": "https://ghcr.io/v2/homebrew/core/swiftformat/blobs/sha256:909ae79dbe735c9377355e202d07a58aeff1af1707ba7a3c843cf7c3b10f68a9",
"sha256": "909ae79dbe735c9377355e202d07a58aeff1af1707ba7a3c843cf7c3b10f68a9"
}
}
}
}
}
},
"system": {
"macos": {
"catalina": {
"HOMEBREW_VERSION": "3.2.0-77-gd305f72",
"HOMEBREW_PREFIX": "/usr/local",
"Homebrew/homebrew-core": "0b13b342053d414d1b241c2c7a446b74d79cc90e",
"CLT": "11.0.0.33.12",
"Xcode": "12.4",
"macOS": "10.15.7"
},
"big_sur": {
"HOMEBREW_VERSION": "3.3.9-34-g2e92128",
"HOMEBREW_PREFIX": "/usr/local",
"Homebrew/homebrew-core": "c28163ed56d6e54f2f71ecf678d4b4d33bac23a5",
"CLT": "12.4.0.0.1.1610135815",
"Xcode": "12.5",
"macOS": "11.0.1"
},
"monterey": {
"HOMEBREW_VERSION": "3.6.10-11-gb683beb",
"HOMEBREW_PREFIX": "/opt/homebrew",
"Homebrew/homebrew-core": "0bc04af3657134103a6f2b48b31e278e2537e85f",
"CLT": "13.4.0.0.1.1651278267",
"Xcode": "13.4.1",
"macOS": "12.5"
},
"ventura": {
"HOMEBREW_VERSION": "4.2.2-4-g080e61f",
"HOMEBREW_PREFIX": "/opt/homebrew",
"Homebrew/homebrew-core": "api",
"CLT": "15.0.0.0.1.1694021235",
"Xcode": "15.1",
"macOS": "13.6"
},
"sonoma": {
"HOMEBREW_VERSION": "4.2.16-71-g044e48b",
"HOMEBREW_PREFIX": "/opt/homebrew",
"Homebrew/homebrew-core": "api",
"CLT": "15.0.0.0.1.1694021235",
"Xcode": "15.3",
"macOS": "14.2.1"
}
}
}
}

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
task(default: %w[setup])
task(setup: [:brew, :lint])
task(:brew) do
raise '`brew` is required. Please install brew. https://brew.sh/' unless system('which brew')
puts('➡️ Brew')
sh('brew bundle')
end
task(:lint) do
Dir.chdir('..') do
sh("swiftformat . --config formatting/.swiftformat --verbose --selfrequired waitWithPolling --exclude Fastfile.swift --swiftversion 4.0")
end
end

47
fastlane/swift/main.swift Normal file
View File

@ -0,0 +1,47 @@
// main.swift
// Copyright (c) 2024 FastlaneTools
//
// ** NOTE **
// This file is provided by fastlane and WILL be overwritten in future updates
// If you want to add extra functionality to this project, create a new file in a
// new group so that it won't be marked for upgrade
//
import Foundation
let argumentProcessor = ArgumentProcessor(args: CommandLine.arguments)
let timeout = argumentProcessor.commandTimeout
class MainProcess {
var doneRunningLane = false
var thread: Thread!
@objc func connectToFastlaneAndRunLane() {
runner.startSocketThread(port: argumentProcessor.port)
let completedRun = Fastfile.runLane(from: nil, named: argumentProcessor.currentLane, with: argumentProcessor.laneParameters())
if completedRun {
runner.disconnectFromFastlaneProcess()
}
doneRunningLane = true
}
func startFastlaneThread() {
thread = Thread(target: self, selector: #selector(connectToFastlaneAndRunLane), object: nil)
thread.name = "worker thread"
thread.start()
}
}
let process = MainProcess()
process.startFastlaneThread()
while !process.doneRunningLane, RunLoop.current.run(mode: RunLoopMode.defaultRunLoopMode, before: Date(timeIntervalSinceNow: 2)) {
// no op
}
// Please don't remove the lines below
// They are used to detect outdated files
// FastlaneRunnerAPIVersion [0.9.2]

View File

@ -0,0 +1 @@
{"Actions.swift":"Autogenerated API","Fastlane.swift":"Autogenerated API","DeliverfileProtocol.swift":"Autogenerated API","GymfileProtocol.swift":"Autogenerated API","MatchfileProtocol.swift":"Autogenerated API","Plugins.swift":"Autogenerated API","PrecheckfileProtocol.swift":"Autogenerated API","ScanfileProtocol.swift":"Autogenerated API","ScreengrabfileProtocol.swift":"Autogenerated API","SnapshotfileProtocol.swift":"Autogenerated API","LaneFileProtocol.swift":"Fastfile Components","OptionalConfigValue.swift":"Fastfile Components","Atomic.swift":"Networking","ControlCommand.swift":"Networking","RubyCommand.swift":"Networking","RubyCommandable.swift":"Networking","Runner.swift":"Networking","SocketClient.swift":"Networking","SocketClientDelegateProtocol.swift":"Networking","SocketResponse.swift":"Networking","main.swift":"Runner Code","ArgumentProcessor.swift":"Runner Code","RunnerArgument.swift":"Runner Code"}