fastlane 2.160.0 → 2.165.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +78 -78
- data/cert/lib/cert/options.rb +28 -1
- data/cert/lib/cert/runner.rb +51 -34
- data/deliver/lib/deliver/app_screenshot_iterator.rb +4 -4
- data/deliver/lib/deliver/module.rb +2 -0
- data/deliver/lib/deliver/options.rb +5 -5
- data/deliver/lib/deliver/queue_worker.rb +14 -29
- data/deliver/lib/deliver/upload_metadata.rb +20 -5
- data/deliver/lib/deliver/upload_screenshots.rb +28 -13
- data/fastlane/lib/fastlane/actions/.download_dsyms.rb.swp +0 -0
- data/fastlane/lib/fastlane/actions/actions_helper.rb +20 -1
- data/fastlane/lib/fastlane/actions/app_store_build_number.rb +39 -3
- data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +15 -1
- data/fastlane/lib/fastlane/actions/check_app_store_metadata.rb +1 -0
- data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +2 -2
- data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +2 -2
- data/fastlane/lib/fastlane/actions/docs/create_app_online.md +1 -1
- data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +2 -2
- data/fastlane/lib/fastlane/actions/docs/run_tests.md +2 -2
- data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +12 -3
- data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +2 -2
- data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +1 -1
- data/fastlane/lib/fastlane/actions/download_dsyms.rb +1 -0
- data/fastlane/lib/fastlane/actions/ensure_git_status_clean.rb +13 -2
- data/fastlane/lib/fastlane/actions/get_certificates.rb +1 -0
- data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +1 -0
- data/fastlane/lib/fastlane/actions/import_from_git.rb +9 -1
- data/fastlane/lib/fastlane/actions/is_ci.rb +1 -1
- data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +15 -0
- data/fastlane/lib/fastlane/actions/register_device.rb +46 -5
- data/fastlane/lib/fastlane/actions/register_devices.rb +50 -16
- data/fastlane/lib/fastlane/actions/set_changelog.rb +31 -3
- data/fastlane/lib/fastlane/actions/sync_code_signing.rb +1 -0
- data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +3 -2
- data/fastlane/lib/fastlane/fast_file.rb +74 -23
- data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +1 -0
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/Deliverfile.swift +1 -1
- data/fastlane/swift/DeliverfileProtocol.swift +4 -4
- data/fastlane/swift/Fastlane.swift +120 -27
- data/fastlane/swift/Gymfile.swift +1 -1
- data/fastlane/swift/GymfileProtocol.swift +1 -1
- data/fastlane/swift/LaneFileProtocol.swift +28 -36
- data/fastlane/swift/MainProcess.swift +1 -1
- data/fastlane/swift/Matchfile.swift +1 -1
- data/fastlane/swift/MatchfileProtocol.swift +21 -5
- data/fastlane/swift/Precheckfile.swift +1 -1
- data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
- data/fastlane/swift/Scanfile.swift +1 -1
- data/fastlane/swift/ScanfileProtocol.swift +1 -1
- data/fastlane/swift/Screengrabfile.swift +1 -1
- data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
- data/fastlane/swift/Snapshotfile.swift +1 -1
- data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
- data/fastlane/swift/main.swift +1 -1
- data/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb +6 -7
- data/fastlane_core/lib/fastlane_core/device_manager.rb +8 -4
- data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
- data/fastlane_core/lib/fastlane_core/keychain_importer.rb +3 -3
- data/gym/lib/gym/generators/package_command_generator_xcode7.rb +2 -2
- data/match/lib/match/generator.rb +6 -1
- data/match/lib/match/importer.rb +63 -18
- data/match/lib/match/migrate.rb +13 -2
- data/match/lib/match/nuke.rb +65 -22
- data/match/lib/match/options.rb +34 -3
- data/match/lib/match/runner.rb +38 -10
- data/match/lib/match/spaceship_ensure.rb +27 -21
- data/match/lib/match/storage/google_cloud_storage.rb +20 -3
- data/match/lib/match/storage/s3_storage.rb +19 -3
- data/scan/lib/scan/detect_values.rb +5 -8
- data/scan/lib/scan/runner.rb +2 -1
- data/sigh/lib/assets/resign.sh +1 -1
- data/sigh/lib/sigh/download_all.rb +16 -4
- data/sigh/lib/sigh/options.rb +21 -0
- data/sigh/lib/sigh/runner.rb +83 -41
- data/snapshot/lib/assets/SnapshotHelper.swift +4 -0
- data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +2 -1
- data/spaceship/README.md +1 -1
- data/spaceship/lib/spaceship/client.rb +9 -4
- data/spaceship/lib/spaceship/connect_api.rb +27 -0
- data/spaceship/lib/spaceship/connect_api/api_client.rb +12 -3
- data/spaceship/lib/spaceship/connect_api/client.rb +20 -7
- data/spaceship/lib/spaceship/connect_api/models/app.rb +51 -0
- data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +3 -1
- data/spaceship/lib/spaceship/connect_api/models/beta_tester.rb +2 -1
- data/spaceship/lib/spaceship/connect_api/models/certificate.rb +42 -0
- data/spaceship/lib/spaceship/connect_api/models/custom_app_organization.rb +43 -0
- data/spaceship/lib/spaceship/connect_api/models/custom_app_user.rb +41 -0
- data/spaceship/lib/spaceship/connect_api/models/device.rb +5 -0
- data/spaceship/lib/spaceship/connect_api/models/profile.rb +7 -1
- data/spaceship/lib/spaceship/connect_api/models/user_invitation.rb +59 -0
- data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +45 -2
- data/spaceship/lib/spaceship/connect_api/spaceship.rb +7 -4
- data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +13 -0
- data/spaceship/lib/spaceship/connect_api/token.rb +6 -1
- data/spaceship/lib/spaceship/connect_api/tunes/tunes.rb +75 -1
- data/spaceship/lib/spaceship/connect_api/users/users.rb +40 -0
- data/spaceship/lib/spaceship/helper/net_http_generic_request.rb +11 -5
- data/supply/lib/supply/uploader.rb +1 -1
- metadata +19 -15
@@ -12,31 +12,26 @@ import Foundation
|
|
12
12
|
|
13
13
|
public protocol LaneFileProtocol: class {
|
14
14
|
var fastlaneVersion: String { get }
|
15
|
-
static func runLane(from fastfile: LaneFile?, named: String, parameters: [String: String]) -> Bool
|
15
|
+
static func runLane(from fastfile: LaneFile?, named lane: String, with parameters: [String: String]) -> Bool
|
16
16
|
|
17
17
|
func recordLaneDescriptions()
|
18
|
-
func beforeAll()
|
19
|
-
func afterAll(
|
18
|
+
func beforeAll(with lane: String)
|
19
|
+
func afterAll(with lane: String)
|
20
20
|
func onError(currentLane: String, errorInfo: String)
|
21
21
|
}
|
22
22
|
|
23
23
|
public extension LaneFileProtocol {
|
24
|
-
var fastlaneVersion: String { return "" } //
|
25
|
-
func beforeAll() {} //
|
26
|
-
func afterAll(
|
27
|
-
func onError(currentLane _: String, errorInfo _: String) {} //
|
28
|
-
func recordLaneDescriptions() {} //
|
24
|
+
var fastlaneVersion: String { return "" } // Defaults to "" because that means any is fine
|
25
|
+
func beforeAll(with lane: String) {} // No-op by default
|
26
|
+
func afterAll(with lane: String) {} // No-op by default
|
27
|
+
func onError(currentLane _: String, errorInfo _: String) {} // No-op by default
|
28
|
+
func recordLaneDescriptions() {} // No-op by default
|
29
29
|
}
|
30
30
|
|
31
31
|
@objcMembers
|
32
32
|
open class LaneFile: NSObject, LaneFileProtocol {
|
33
33
|
private(set) static var fastfileInstance: LaneFile?
|
34
34
|
|
35
|
-
// Called before any lane is executed.
|
36
|
-
private func setupAllTheThings() {
|
37
|
-
LaneFile.fastfileInstance!.beforeAll()
|
38
|
-
}
|
39
|
-
|
40
35
|
private static func trimLaneFromName(laneName: String) -> String {
|
41
36
|
return String(laneName.prefix(laneName.count - 4))
|
42
37
|
}
|
@@ -51,8 +46,8 @@ open class LaneFile: NSObject, LaneFileProtocol {
|
|
51
46
|
#if !SWIFT_PACKAGE
|
52
47
|
let methodList = class_copyMethodList(self, &methodCount)
|
53
48
|
#else
|
54
|
-
// In SPM we're calling this functions out of the scope of the normal binary that it
|
55
|
-
//
|
49
|
+
// In SPM we're calling this functions out of the scope of the normal binary that it's
|
50
|
+
// being built, so *self* in this scope would be the SPM executable instead of the Fastfile
|
56
51
|
// that we'd normally expect.
|
57
52
|
let methodList = class_copyMethodList(type(of: fastfileInstance!), &methodCount)
|
58
53
|
#endif
|
@@ -95,32 +90,28 @@ open class LaneFile: NSObject, LaneFileProtocol {
|
|
95
90
|
}
|
96
91
|
}
|
97
92
|
|
98
|
-
public static func runLane(from fastfile: LaneFile?, named: String, parameters: [String: String]) -> Bool {
|
99
|
-
log(message: "Running lane: \(
|
93
|
+
public static func runLane(from fastfile: LaneFile?, named lane: String, with parameters: [String: String]) -> Bool {
|
94
|
+
log(message: "Running lane: \(lane)")
|
100
95
|
#if !SWIFT_PACKAGE
|
101
|
-
//
|
102
|
-
// in the executable's scope that loads the library, so in that case `className()` won't be the
|
103
|
-
// expected Fastfile and so, we do not dynamically load it as we do without SPM.
|
96
|
+
// When not in SPM environment, we load the Fastfile from its `className()`.
|
104
97
|
loadFastfile()
|
105
|
-
|
106
|
-
|
107
|
-
#if !SWIFT_PACKAGE
|
108
|
-
guard let fastfileInstance: LaneFile = self.fastfileInstance else {
|
98
|
+
guard let fastfileInstance = self.fastfileInstance as? Fastfile else {
|
109
99
|
let message = "Unable to instantiate class named: \(className())"
|
110
100
|
log(message: message)
|
111
101
|
fatalError(message)
|
112
102
|
}
|
113
103
|
#else
|
114
|
-
//
|
115
|
-
//
|
116
|
-
|
104
|
+
// When in SPM environment, we can't load the Fastfile from its `className()` because the executable is in
|
105
|
+
// another scope, so `className()` won't be the expected Fastfile. Instead, we load the Fastfile as a Lanefile
|
106
|
+
// in a static way, by parameter.
|
107
|
+
guard let fastfileInstance = fastfile else {
|
117
108
|
log(message: "Found nil instance of fastfile")
|
118
109
|
preconditionFailure()
|
119
110
|
}
|
111
|
+
self.fastfileInstance = fastfileInstance
|
120
112
|
#endif
|
121
|
-
self.fastfileInstance = fastfile!
|
122
113
|
let currentLanes = lanes
|
123
|
-
let lowerCasedLaneRequested =
|
114
|
+
let lowerCasedLaneRequested = lane.lowercased()
|
124
115
|
|
125
116
|
guard let laneMethod = currentLanes[lowerCasedLaneRequested] else {
|
126
117
|
let laneNames = laneFunctionNames.map { laneFuctionName in
|
@@ -131,7 +122,7 @@ open class LaneFile: NSObject, LaneFileProtocol {
|
|
131
122
|
}
|
132
123
|
}.joined(separator: ", ")
|
133
124
|
|
134
|
-
let message = "[!] Could not find lane '\(
|
125
|
+
let message = "[!] Could not find lane '\(lane)'. Available lanes: \(laneNames)"
|
135
126
|
log(message: message)
|
136
127
|
|
137
128
|
let shutdownCommand = ControlCommand(commandType: .cancel(cancelReason: .clientError), message: message)
|
@@ -139,15 +130,16 @@ open class LaneFile: NSObject, LaneFileProtocol {
|
|
139
130
|
return false
|
140
131
|
}
|
141
132
|
|
142
|
-
//
|
143
|
-
fastfileInstance.
|
133
|
+
// Call all methods that need to be called before we start calling lanes.
|
134
|
+
fastfileInstance.beforeAll(with: lane)
|
144
135
|
|
145
|
-
// We need to catch all possible errors here and display a nice message
|
136
|
+
// We need to catch all possible errors here and display a nice message.
|
146
137
|
_ = fastfileInstance.perform(NSSelectorFromString(laneMethod), with: parameters)
|
147
138
|
|
148
|
-
// only
|
149
|
-
fastfileInstance.afterAll(
|
150
|
-
|
139
|
+
// Call only on success.
|
140
|
+
fastfileInstance.afterAll(with: lane)
|
141
|
+
|
142
|
+
log(message: "Done running lane: \(lane) 🚀")
|
151
143
|
return true
|
152
144
|
}
|
153
145
|
}
|
@@ -28,7 +28,7 @@ class MainProcess {
|
|
28
28
|
@objc func connectToFastlaneAndRunLane(_ fastfile: LaneFile?) {
|
29
29
|
runner.startSocketThread(port: argumentProcessor.port)
|
30
30
|
|
31
|
-
let completedRun = Fastfile.runLane(from: fastfile, named: argumentProcessor.currentLane,
|
31
|
+
let completedRun = Fastfile.runLane(from: fastfile, named: argumentProcessor.currentLane, with: argumentProcessor.laneParameters())
|
32
32
|
if completedRun {
|
33
33
|
runner.disconnectFromFastlaneProcess()
|
34
34
|
}
|
@@ -17,11 +17,17 @@ public protocol MatchfileProtocol: class {
|
|
17
17
|
/// Skip syncing provisioning profiles
|
18
18
|
var skipProvisioningProfiles: Bool { get }
|
19
19
|
|
20
|
-
/// The bundle identifier(s) of your app (comma-separated)
|
20
|
+
/// The bundle identifier(s) of your app (comma-separated string or array of strings)
|
21
21
|
var appIdentifier: [String] { get }
|
22
22
|
|
23
|
+
/// Path to your App Store Connect API Key JSON file (https://docs.fastlane.tools/app-store-connect-api/#using-fastlane-api-key-json-file)
|
24
|
+
var apiKeyPath: String? { get }
|
25
|
+
|
26
|
+
/// Your App Store Connect API Key information (https://docs.fastlane.tools/app-store-connect-api/#use-return-value-and-pass-in-as-an-option)
|
27
|
+
var apiKey: [String: Any]? { get }
|
28
|
+
|
23
29
|
/// Your Apple ID Username
|
24
|
-
var username: String { get }
|
30
|
+
var username: String? { get }
|
25
31
|
|
26
32
|
/// The ID of your Developer Portal team if you're in multiple teams
|
27
33
|
var teamId: String? { get }
|
@@ -53,7 +59,7 @@ public protocol MatchfileProtocol: class {
|
|
53
59
|
/// Use a basic authorization header to access the git repo (e.g.: access via HTTPS, GitHub Actions, etc), usually a string in Base64
|
54
60
|
var gitBasicAuthorization: String? { get }
|
55
61
|
|
56
|
-
/// Use a bearer authorization header to access the git repo (e.g.: access to an Azure
|
62
|
+
/// Use a bearer authorization header to access the git repo (e.g.: access to an Azure DevOps repository), usually a string in Base64
|
57
63
|
var gitBearerAuthorization: String? { get }
|
58
64
|
|
59
65
|
/// 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
|
@@ -116,9 +122,15 @@ public protocol MatchfileProtocol: class {
|
|
116
122
|
/// 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
|
117
123
|
var failOnNameTaken: Bool { get }
|
118
124
|
|
125
|
+
/// 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
|
126
|
+
var skipCertificateMatching: Bool { get }
|
127
|
+
|
119
128
|
/// Path in which to export certificates, key and profile
|
120
129
|
var outputPath: String? { get }
|
121
130
|
|
131
|
+
/// 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
|
132
|
+
var skipSetPartitionList: Bool { get }
|
133
|
+
|
122
134
|
/// Print out extra information and all commands
|
123
135
|
var verbose: Bool { get }
|
124
136
|
}
|
@@ -130,7 +142,9 @@ public extension MatchfileProtocol {
|
|
130
142
|
var generateAppleCerts: Bool { return true }
|
131
143
|
var skipProvisioningProfiles: Bool { return false }
|
132
144
|
var appIdentifier: [String] { return [] }
|
133
|
-
var
|
145
|
+
var apiKeyPath: String? { return nil }
|
146
|
+
var apiKey: [String: Any]? { return nil }
|
147
|
+
var username: String? { return nil }
|
134
148
|
var teamId: String? { return nil }
|
135
149
|
var teamName: String? { return nil }
|
136
150
|
var storageMode: String { return "git" }
|
@@ -162,10 +176,12 @@ public extension MatchfileProtocol {
|
|
162
176
|
var templateName: String? { return nil }
|
163
177
|
var profileName: String? { return nil }
|
164
178
|
var failOnNameTaken: Bool { return false }
|
179
|
+
var skipCertificateMatching: Bool { return false }
|
165
180
|
var outputPath: String? { return nil }
|
181
|
+
var skipSetPartitionList: Bool { return false }
|
166
182
|
var verbose: Bool { return false }
|
167
183
|
}
|
168
184
|
|
169
185
|
// Please don't remove the lines below
|
170
186
|
// They are used to detect outdated files
|
171
|
-
// FastlaneRunnerAPIVersion [0.9.
|
187
|
+
// FastlaneRunnerAPIVersion [0.9.45]
|
data/fastlane/swift/main.swift
CHANGED
@@ -20,7 +20,7 @@ class MainProcess {
|
|
20
20
|
@objc func connectToFastlaneAndRunLane() {
|
21
21
|
runner.startSocketThread(port: argumentProcessor.port)
|
22
22
|
|
23
|
-
let completedRun = Fastfile.runLane(from: nil, named: argumentProcessor.currentLane,
|
23
|
+
let completedRun = Fastfile.runLane(from: nil, named: argumentProcessor.currentLane, with: argumentProcessor.laneParameters())
|
24
24
|
if completedRun {
|
25
25
|
runner.disconnectFromFastlaneProcess()
|
26
26
|
}
|
@@ -19,7 +19,7 @@ module FastlaneCore
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def action_launched(launch_context: nil)
|
22
|
-
|
22
|
+
if should_show_message?
|
23
23
|
show_message
|
24
24
|
end
|
25
25
|
|
@@ -52,16 +52,15 @@ module FastlaneCore
|
|
52
52
|
UI.message("You can disable this by adding `opt_out_usage` at the top of your Fastfile")
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
56
|
-
|
55
|
+
def should_show_message?
|
56
|
+
return false if FastlaneCore::Env.truthy?("FASTLANE_OPT_OUT_USAGE")
|
57
57
|
|
58
|
+
file_name = ".did_show_opt_info"
|
58
59
|
new_path = File.join(FastlaneCore.fastlane_user_dir, file_name)
|
59
|
-
|
60
|
-
|
61
|
-
return did_show if did_show
|
60
|
+
return false if File.exist?(new_path)
|
62
61
|
|
63
62
|
File.write(new_path, '1')
|
64
|
-
|
63
|
+
true
|
65
64
|
end
|
66
65
|
|
67
66
|
def finalize_session
|
@@ -301,7 +301,7 @@ module FastlaneCore
|
|
301
301
|
Helper.backticks("open -a #{simulator_path} --args -CurrentDeviceUDID #{device.udid}", print: FastlaneCore::Globals.verbose?)
|
302
302
|
end
|
303
303
|
|
304
|
-
def copy_logs(device, log_identity, logs_destination_dir)
|
304
|
+
def copy_logs(device, log_identity, logs_destination_dir, log_collection_start_time)
|
305
305
|
logs_destination_dir = File.expand_path(logs_destination_dir)
|
306
306
|
os_version = FastlaneCore::CommandExecutor.execute(command: 'sw_vers -productVersion', print_all: false, print_command: false)
|
307
307
|
|
@@ -310,7 +310,7 @@ module FastlaneCore
|
|
310
310
|
|
311
311
|
are_logarchives_supported = device_supports_logarchives && host_computer_supports_logarchives
|
312
312
|
if are_logarchives_supported
|
313
|
-
copy_logarchive(device, log_identity, logs_destination_dir)
|
313
|
+
copy_logarchive(device, log_identity, logs_destination_dir, log_collection_start_time)
|
314
314
|
else
|
315
315
|
copy_logfile(device, log_identity, logs_destination_dir)
|
316
316
|
end
|
@@ -340,13 +340,17 @@ module FastlaneCore
|
|
340
340
|
UI.success("Copying file '#{logfile_src}' to '#{logfile_dst}'...")
|
341
341
|
end
|
342
342
|
|
343
|
-
def copy_logarchive(device, log_identity, logs_destination_dir)
|
343
|
+
def copy_logarchive(device, log_identity, logs_destination_dir, log_collection_start_time)
|
344
344
|
require 'shellwords'
|
345
345
|
|
346
346
|
logarchive_dst = File.join(logs_destination_dir, "system_logs-#{log_identity}.logarchive")
|
347
347
|
FileUtils.rm_rf(logarchive_dst)
|
348
348
|
FileUtils.mkdir_p(File.expand_path("..", logarchive_dst))
|
349
|
-
|
349
|
+
|
350
|
+
logs_collection_start = log_collection_start_time.strftime('%Y-%m-%d %H:%M:%S')
|
351
|
+
command = "xcrun simctl spawn #{device.udid} log collect "
|
352
|
+
command << "--start '#{logs_collection_start}' "
|
353
|
+
command << "--output #{logarchive_dst.shellescape} 2>/dev/null"
|
350
354
|
FastlaneCore::CommandExecutor.execute(command: command, print_all: false, print_command: true)
|
351
355
|
end
|
352
356
|
end
|
@@ -4,7 +4,7 @@ require 'security'
|
|
4
4
|
|
5
5
|
module FastlaneCore
|
6
6
|
class KeychainImporter
|
7
|
-
def self.import_file(path, keychain_path, keychain_password: nil, certificate_password: "", output: FastlaneCore::Globals.verbose?)
|
7
|
+
def self.import_file(path, keychain_path, keychain_password: nil, certificate_password: "", skip_set_partition_list: false, output: FastlaneCore::Globals.verbose?)
|
8
8
|
UI.user_error!("Could not find file '#{path}'") unless File.exist?(path)
|
9
9
|
|
10
10
|
command = "security import #{path.shellescape} -k '#{keychain_path.shellescape}'"
|
@@ -19,7 +19,7 @@ module FastlaneCore
|
|
19
19
|
UI.command_output(stdout.read.to_s) if output
|
20
20
|
|
21
21
|
# Set partition list only if success since it can be a time consuming process if a lot of keys are installed
|
22
|
-
if thrd.value.success?
|
22
|
+
if thrd.value.success? && !skip_set_partition_list
|
23
23
|
keychain_password ||= resolve_keychain_password(keychain_path)
|
24
24
|
set_partition_list(path, keychain_path, keychain_password: keychain_password, output: output)
|
25
25
|
else
|
@@ -39,7 +39,7 @@ module FastlaneCore
|
|
39
39
|
# See https://openradar.appspot.com/28524119
|
40
40
|
if Helper.backticks('security -h | grep set-key-partition-list', print: false).length > 0
|
41
41
|
command = "security set-key-partition-list"
|
42
|
-
command << " -S apple-tool:,apple:"
|
42
|
+
command << " -S apple-tool:,apple:,codesign:"
|
43
43
|
command << " -s" # This is a needed in Catalina to prevent "security: SecKeychainItemCopyAccess: A missing value was detected."
|
44
44
|
command << " -k #{keychain_password.to_s.shellescape}"
|
45
45
|
command << " #{keychain_path.shellescape}"
|
@@ -66,14 +66,14 @@ module Gym
|
|
66
66
|
if path
|
67
67
|
# Try to find IPA file in the output directory, used when app thinning was not set
|
68
68
|
Gym.cache[:ipa_path] = File.join(temporary_output_path, "#{Gym.config[:output_name]}.ipa")
|
69
|
-
FileUtils.mv(path, Gym.cache[:ipa_path]) unless File.expand_path(path).casecmp(File.expand_path(Gym.cache[:ipa_path]).downcase)
|
69
|
+
FileUtils.mv(path, Gym.cache[:ipa_path]) unless File.expand_path(path).casecmp?(File.expand_path(Gym.cache[:ipa_path]).downcase)
|
70
70
|
elsif Dir.exist?(apps_path)
|
71
71
|
# Try to find "generic" IPA file inside "Apps" folder, used when app thinning was set
|
72
72
|
files = Dir[File.join(apps_path, "*.ipa")]
|
73
73
|
# Generic IPA file doesn't have suffix so its name is the shortest
|
74
74
|
path = files.min_by(&:length)
|
75
75
|
Gym.cache[:ipa_path] = File.join(temporary_output_path, "#{Gym.config[:output_name]}.ipa")
|
76
|
-
FileUtils.cp(path, Gym.cache[:ipa_path]) unless File.expand_path(path).casecmp(File.expand_path(Gym.cache[:ipa_path]).downcase)
|
76
|
+
FileUtils.cp(path, Gym.cache[:ipa_path]) unless File.expand_path(path).casecmp?(File.expand_path(Gym.cache[:ipa_path]).downcase)
|
77
77
|
else
|
78
78
|
ErrorHandler.handle_empty_archive unless path
|
79
79
|
end
|
@@ -26,11 +26,14 @@ module Match
|
|
26
26
|
generate_apple_certs: params[:generate_apple_certs],
|
27
27
|
output_path: output_path,
|
28
28
|
force: true, # we don't need a certificate without its private key, we only care about a new certificate
|
29
|
+
api_key_path: params[:api_key_path],
|
30
|
+
api_key: params[:api_key],
|
29
31
|
username: params[:username],
|
30
32
|
team_id: params[:team_id],
|
31
33
|
team_name: params[:team_name],
|
32
34
|
keychain_path: FastlaneCore::Helper.keychain_path(params[:keychain_name]),
|
33
|
-
keychain_password: params[:keychain_password]
|
35
|
+
keychain_password: params[:keychain_password],
|
36
|
+
skip_set_partition_list: params[:skip_set_partition_list]
|
34
37
|
})
|
35
38
|
|
36
39
|
Cert.config = arguments
|
@@ -80,6 +83,8 @@ module Match
|
|
80
83
|
cert_id: certificate_id,
|
81
84
|
provisioning_name: profile_name,
|
82
85
|
ignore_profiles_with_different_name: true,
|
86
|
+
api_key_path: params[:api_key_path],
|
87
|
+
api_key: params[:api_key],
|
83
88
|
team_id: params[:team_id],
|
84
89
|
team_name: params[:team_name],
|
85
90
|
template_name: params[:template_name],
|
data/match/lib/match/importer.rb
CHANGED
@@ -28,10 +28,17 @@ module Match
|
|
28
28
|
google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
|
29
29
|
google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
|
30
30
|
google_cloud_project_id: params[:google_cloud_project_id].to_s,
|
31
|
+
s3_bucket: params[:s3_bucket],
|
32
|
+
s3_region: params[:s3_region],
|
33
|
+
s3_access_key: params[:s3_access_key],
|
34
|
+
s3_secret_access_key: params[:s3_secret_access_key],
|
35
|
+
s3_object_prefix: params[:s3_object_prefix],
|
31
36
|
readonly: params[:readonly],
|
32
37
|
username: params[:username],
|
33
38
|
team_id: params[:team_id],
|
34
|
-
team_name: params[:team_name]
|
39
|
+
team_name: params[:team_name],
|
40
|
+
api_key_path: params[:api_key_path],
|
41
|
+
api_key: params[:api_key]
|
35
42
|
})
|
36
43
|
storage.download
|
37
44
|
|
@@ -48,11 +55,25 @@ module Match
|
|
48
55
|
|
49
56
|
case cert_type
|
50
57
|
when :development
|
51
|
-
certificate_type =
|
58
|
+
certificate_type = [
|
59
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DEVELOPMENT,
|
60
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::MAC_APP_DEVELOPMENT,
|
61
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPMENT
|
62
|
+
].join(',')
|
52
63
|
when :distribution, :enterprise
|
53
|
-
certificate_type =
|
64
|
+
certificate_type = [
|
65
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION,
|
66
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::MAC_APP_DISTRIBUTION,
|
67
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::DISTRIBUTION
|
68
|
+
].join(',')
|
54
69
|
when :developer_id_application
|
55
|
-
certificate_type =
|
70
|
+
certificate_type = [
|
71
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION
|
72
|
+
].join(',')
|
73
|
+
when :mac_installer_distribution
|
74
|
+
certificate_type = [
|
75
|
+
Spaceship::ConnectAPI::Certificate::CertificateType::MAC_INSTALLER_DISTRIBUTION
|
76
|
+
].join(',')
|
56
77
|
else
|
57
78
|
UI.user_error!("Cert type '#{cert_type}' is not supported")
|
58
79
|
end
|
@@ -61,23 +82,41 @@ module Match
|
|
61
82
|
output_dir_certs = File.join(storage.prefixed_working_directory, "certs", cert_type.to_s)
|
62
83
|
output_dir_profiles = File.join(storage.prefixed_working_directory, "profiles", prov_type.to_s)
|
63
84
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
85
|
+
should_skip_certificate_matching = params[:skip_certificate_matching]
|
86
|
+
# In case there is no access to Apple Developer portal but we have the certificates, keys and profiles
|
87
|
+
if should_skip_certificate_matching
|
88
|
+
cert_name = File.basename(cert_path, ".*")
|
89
|
+
p12_name = File.basename(p12_path, ".*")
|
68
90
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
91
|
+
# Make dir if doesn't exist
|
92
|
+
FileUtils.mkdir_p(output_dir_certs)
|
93
|
+
dest_cert_path = File.join(output_dir_certs, "#{cert_name}.cer")
|
94
|
+
dest_p12_path = File.join(output_dir_certs, "#{p12_name}.p12")
|
95
|
+
else
|
96
|
+
# Need to get the cert id by comparing base64 encoded cert content with certificate content from the API responses
|
97
|
+
token = api_token(params)
|
98
|
+
if token
|
99
|
+
UI.message("Creating authorization token for App Store Connect API")
|
100
|
+
Spaceship::ConnectAPI.token = token
|
101
|
+
else
|
102
|
+
UI.message("Login to App Store Connect (#{params[:username]})")
|
103
|
+
Spaceship::ConnectAPI.login(params[:username], use_portal: true, use_tunes: false, portal_team_id: params[:team_id], team_name: params[:team_name])
|
104
|
+
end
|
105
|
+
certs = Spaceship::ConnectAPI::Certificate.all(filter: { certificateType: certificate_type })
|
106
|
+
|
107
|
+
# Base64 encode contents to find match from API to find a cert ID
|
108
|
+
cert_contents_base_64 = Base64.strict_encode64(File.binread(cert_path))
|
109
|
+
matching_cert = certs.find do |cert|
|
110
|
+
cert.certificate_content == cert_contents_base_64
|
111
|
+
end
|
74
112
|
|
75
|
-
|
113
|
+
UI.user_error!("This certificate cannot be imported - the certificate contents did not match with any available on the Developer Portal") if matching_cert.nil?
|
76
114
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
115
|
+
# Make dir if doesn't exist
|
116
|
+
FileUtils.mkdir_p(output_dir_certs)
|
117
|
+
dest_cert_path = File.join(output_dir_certs, "#{matching_cert.id}.cer")
|
118
|
+
dest_p12_path = File.join(output_dir_certs, "#{matching_cert.id}.p12")
|
119
|
+
end
|
81
120
|
|
82
121
|
files_to_commit = [dest_cert_path, dest_p12_path]
|
83
122
|
|
@@ -108,5 +147,11 @@ module Match
|
|
108
147
|
UI.user_error!("#{file_description} does not exist at path: #{file_path}") unless !file_path.nil? || optional
|
109
148
|
file_path
|
110
149
|
end
|
150
|
+
|
151
|
+
def api_token(params)
|
152
|
+
@api_token ||= Spaceship::ConnectAPI::Token.create(params[:api_key]) if params[:api_key]
|
153
|
+
@api_token ||= Spaceship::ConnectAPI::Token.from_json_file(params[:api_key_path]) if params[:api_key_path]
|
154
|
+
return @api_token
|
155
|
+
end
|
111
156
|
end
|
112
157
|
end
|