fastlane 2.177.0 → 2.181.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +83 -70
- data/cert/lib/cert/options.rb +1 -0
- data/cert/lib/cert/runner.rb +5 -1
- data/deliver/lib/deliver/download_screenshots.rb +1 -2
- data/deliver/lib/deliver/options.rb +1 -0
- data/deliver/lib/deliver/runner.rb +10 -2
- data/deliver/lib/deliver/setup.rb +0 -1
- data/deliver/lib/deliver/upload_metadata.rb +2 -1
- data/fastlane/lib/fastlane/actions/app_store_build_number.rb +6 -1
- data/fastlane/lib/fastlane/actions/app_store_connect_api_key.rb +7 -4
- data/fastlane/lib/fastlane/actions/backup_file.rb +1 -1
- data/fastlane/lib/fastlane/actions/build_app.rb +4 -0
- data/fastlane/lib/fastlane/actions/check_app_store_metadata.rb +4 -0
- data/fastlane/lib/fastlane/actions/clipboard.rb +3 -6
- data/fastlane/lib/fastlane/actions/commit_github_file.rb +11 -1
- data/fastlane/lib/fastlane/actions/create_xcframework.rb +5 -0
- data/fastlane/lib/fastlane/actions/docs/upload_to_play_store.md +2 -1
- data/fastlane/lib/fastlane/actions/ensure_env_vars.rb +2 -6
- data/fastlane/lib/fastlane/actions/get_github_release.rb +11 -1
- data/fastlane/lib/fastlane/actions/get_provisioning_profile.rb +4 -0
- data/fastlane/lib/fastlane/actions/get_version_number.rb +17 -10
- data/fastlane/lib/fastlane/actions/git_branch.rb +4 -10
- data/fastlane/lib/fastlane/actions/git_tag_exists.rb +4 -0
- data/fastlane/lib/fastlane/actions/github_api.rb +2 -1
- data/fastlane/lib/fastlane/actions/increment_build_number.rb +8 -1
- data/fastlane/lib/fastlane/actions/install_provisioning_profile.rb +4 -0
- data/fastlane/lib/fastlane/actions/jira.rb +61 -14
- data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +1 -0
- data/fastlane/lib/fastlane/actions/match_nuke.rb +59 -0
- data/fastlane/lib/fastlane/actions/notarize.rb +98 -51
- data/fastlane/lib/fastlane/actions/register_device.rb +1 -1
- data/fastlane/lib/fastlane/actions/register_devices.rb +1 -1
- data/fastlane/lib/fastlane/actions/restore_file.rb +1 -1
- data/fastlane/lib/fastlane/actions/set_changelog.rb +1 -1
- data/fastlane/lib/fastlane/actions/slack.rb +148 -127
- data/fastlane/lib/fastlane/actions/sourcedocs.rb +164 -0
- data/fastlane/lib/fastlane/actions/spaceship_logs.rb +1 -1
- data/fastlane/lib/fastlane/actions/update_project_provisioning.rb +1 -2
- data/fastlane/lib/fastlane/erb_template_helper.rb +7 -1
- data/fastlane/lib/fastlane/fast_file.rb +9 -5
- data/fastlane/lib/fastlane/fastlane_require.rb +7 -1
- data/fastlane/lib/fastlane/helper/git_helper.rb +19 -7
- data/fastlane/lib/fastlane/lane_manager.rb +3 -2
- data/fastlane/lib/fastlane/plugins/plugin_fetcher.rb +1 -2
- data/fastlane/lib/fastlane/plugins/plugin_info_collector.rb +1 -2
- data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -2
- data/fastlane/lib/fastlane/setup/setup.rb +23 -10
- data/fastlane/lib/fastlane/swift_fastlane_function.rb +4 -0
- data/fastlane/lib/fastlane/swift_runner_upgrader.rb +2 -0
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/Deliverfile.swift +1 -1
- data/fastlane/swift/DeliverfileProtocol.swift +3 -3
- data/fastlane/swift/Fastlane.swift +550 -328
- data/fastlane/swift/Gymfile.swift +1 -1
- data/fastlane/swift/GymfileProtocol.swift +1 -1
- data/fastlane/swift/LaneFileProtocol.swift +9 -3
- data/fastlane/swift/Matchfile.swift +1 -1
- data/fastlane/swift/MatchfileProtocol.swift +1 -1
- data/fastlane/swift/Precheckfile.swift +1 -1
- data/fastlane/swift/PrecheckfileProtocol.swift +3 -3
- data/fastlane/swift/RubyCommand.swift +1 -1
- data/fastlane/swift/Scanfile.swift +1 -1
- data/fastlane/swift/ScanfileProtocol.swift +5 -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/SocketClient.swift +2 -1
- data/fastlane/swift/SocketResponse.swift +4 -2
- data/fastlane/swift/formatting/Brewfile.lock.json +18 -16
- data/fastlane_core/lib/fastlane_core.rb +22 -21
- data/fastlane_core/lib/fastlane_core/build_watcher.rb +50 -9
- data/fastlane_core/lib/fastlane_core/clipboard.rb +20 -0
- data/fastlane_core/lib/fastlane_core/configuration/configuration.rb +5 -3
- data/fastlane_core/lib/fastlane_core/helper.rb +24 -1
- data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +10 -6
- data/fastlane_core/lib/fastlane_core/project.rb +3 -14
- data/fastlane_core/lib/fastlane_core/queue_worker.rb +2 -2
- data/fastlane_core/lib/fastlane_core/ui/implementations/shell.rb +12 -1
- data/fastlane_core/lib/fastlane_core/ui/interface.rb +1 -1
- data/gym/lib/gym/generators/package_command_generator.rb +4 -0
- data/gym/lib/gym/generators/package_command_generator_xcode7.rb +13 -8
- data/gym/lib/gym/runner.rb +15 -4
- data/match/lib/match/change_password.rb +3 -3
- data/match/lib/match/encryption/interface.rb +1 -1
- data/match/lib/match/encryption/openssl.rb +2 -2
- data/match/lib/match/importer.rb +1 -1
- data/match/lib/match/migrate.rb +1 -1
- data/match/lib/match/module.rb +1 -0
- data/match/lib/match/nuke.rb +1 -1
- data/match/lib/match/runner.rb +1 -1
- data/match/lib/match/storage/google_cloud_storage.rb +1 -1
- data/match/lib/match/storage/s3_storage.rb +1 -1
- data/pilot/lib/pilot/build_manager.rb +9 -4
- data/pilot/lib/pilot/manager.rb +5 -1
- data/pilot/lib/pilot/options.rb +3 -2
- data/precheck/lib/precheck/options.rb +1 -0
- data/precheck/lib/precheck/runner.rb +5 -1
- data/scan/lib/scan/options.rb +10 -5
- data/scan/lib/scan/runner.rb +54 -1
- data/scan/lib/scan/test_command_generator.rb +10 -8
- data/screengrab/lib/screengrab/android_environment.rb +6 -4
- data/screengrab/lib/screengrab/runner.rb +1 -1
- data/sigh/lib/sigh/download_all.rb +1 -1
- data/sigh/lib/sigh/options.rb +1 -0
- data/sigh/lib/sigh/runner.rb +5 -1
- data/snapshot/lib/assets/SnapshotHelper.swift +1 -1
- data/snapshot/lib/snapshot/reports_generator.rb +4 -0
- data/spaceship/README.md +2 -12
- data/spaceship/lib/spaceship/commands_generator.rb +2 -1
- data/spaceship/lib/spaceship/connect_api/models/app_screenshot.rb +1 -1
- data/spaceship/lib/spaceship/connect_api/models/beta_group.rb +5 -0
- data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +13 -0
- data/spaceship/lib/spaceship/connect_api/token.rb +8 -2
- data/spaceship/lib/spaceship/spaceauth_runner.rb +19 -9
- data/spaceship/lib/spaceship/tunes/members.rb +1 -1
- data/supply/lib/supply/client.rb +3 -1
- data/supply/lib/supply/options.rb +2 -2
- data/supply/lib/supply/uploader.rb +1 -0
- metadata +28 -24
- data/gym/lib/gym/.runner.rb.swp +0 -0
data/pilot/lib/pilot/options.rb
CHANGED
@@ -31,6 +31,7 @@ module Pilot
|
|
31
31
|
short_option: "-u",
|
32
32
|
env_name: "PILOT_USERNAME",
|
33
33
|
description: "Your Apple ID Username",
|
34
|
+
optional: true,
|
34
35
|
default_value: user,
|
35
36
|
default_value_dynamic: true),
|
36
37
|
FastlaneCore::ConfigItem.new(key: :app_identifier,
|
@@ -182,8 +183,8 @@ module Pilot
|
|
182
183
|
FastlaneCore::ConfigItem.new(key: :notify_external_testers,
|
183
184
|
is_string: false,
|
184
185
|
env_name: "PILOT_NOTIFY_EXTERNAL_TESTERS",
|
185
|
-
description: "Should notify external testers?",
|
186
|
-
|
186
|
+
description: "Should notify external testers? (Not setting a value will use App Store Connect's default which is to notify)",
|
187
|
+
optional: true),
|
187
188
|
FastlaneCore::ConfigItem.new(key: :app_version,
|
188
189
|
env_name: "PILOT_APP_VERSION",
|
189
190
|
description: "The version number of the application build to distribute. If the version number is not specified, then the most recent build uploaded to TestFlight will be distributed. If specified, the most recent build for the version number will be distributed",
|
@@ -32,6 +32,10 @@ module Precheck
|
|
32
32
|
UI.message("Creating authorization token for App Store Connect API")
|
33
33
|
Spaceship::ConnectAPI.token = api_token
|
34
34
|
elsif Spaceship::Tunes.client.nil?
|
35
|
+
# Username is now optional since addition of App Store Connect API Key
|
36
|
+
# Force asking for username to prompt user if not already set
|
37
|
+
Precheck.config.fetch(:username, force_ask: true)
|
38
|
+
|
35
39
|
# Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
|
36
40
|
# Prompts select team if multiple teams and none specified
|
37
41
|
UI.message("Starting login with user '#{Precheck.config[:username]}'")
|
@@ -72,7 +76,7 @@ module Precheck
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def api_token
|
75
|
-
@api_token ||= Spaceship::ConnectAPI::Token.create(Precheck.config[:api_key]) if Precheck.config[:api_key]
|
79
|
+
@api_token ||= Spaceship::ConnectAPI::Token.create(**Precheck.config[:api_key]) if Precheck.config[:api_key]
|
76
80
|
@api_token ||= Spaceship::ConnectAPI::Token.from_json_file(Precheck.config[:api_key_path]) if Precheck.config[:api_key_path]
|
77
81
|
return @api_token
|
78
82
|
end
|
data/scan/lib/scan/options.rb
CHANGED
@@ -472,11 +472,16 @@ module Scan
|
|
472
472
|
type: Boolean,
|
473
473
|
default_value: false),
|
474
474
|
FastlaneCore::ConfigItem.new(key: :use_system_scm,
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
475
|
+
env_name: "SCAN_USE_SYSTEM_SCM",
|
476
|
+
description: "Lets xcodebuild use system's scm configuration",
|
477
|
+
optional: true,
|
478
|
+
type: Boolean,
|
479
|
+
default_value: false),
|
480
|
+
FastlaneCore::ConfigItem.new(key: :number_of_retries,
|
481
|
+
env_name: 'SCAN_NUMBER_OF_RETRIES',
|
482
|
+
description: "The number of times a test can fail before scan should stop retrying",
|
483
|
+
type: Integer,
|
484
|
+
default_value: 0)
|
480
485
|
|
481
486
|
]
|
482
487
|
end
|
data/scan/lib/scan/runner.rb
CHANGED
@@ -51,7 +51,14 @@ module Scan
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
execute(retries: Scan.config[:number_of_retries])
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute(retries: 0)
|
58
|
+
Scan.cache[:retry_attempt] = Scan.config[:number_of_retries] - retries
|
59
|
+
|
54
60
|
command = @test_command_generator.generate
|
61
|
+
|
55
62
|
prefix_hash = [
|
56
63
|
{
|
57
64
|
prefix: "Running Tests: ",
|
@@ -71,7 +78,12 @@ module Scan
|
|
71
78
|
error: proc do |error_output|
|
72
79
|
begin
|
73
80
|
exit_status = $?.exitstatus
|
74
|
-
|
81
|
+
if retries > 0
|
82
|
+
# If there are retries remaining, run the tests again
|
83
|
+
return retry_execute(retries: retries, error_output: error_output)
|
84
|
+
else
|
85
|
+
ErrorHandler.handle_build_error(error_output, @test_command_generator.xcodebuild_log_path)
|
86
|
+
end
|
75
87
|
rescue => ex
|
76
88
|
SlackPoster.new.run({
|
77
89
|
build_errors: 1
|
@@ -79,9 +91,50 @@ module Scan
|
|
79
91
|
raise ex
|
80
92
|
end
|
81
93
|
end)
|
94
|
+
|
82
95
|
exit_status
|
83
96
|
end
|
84
97
|
|
98
|
+
def retry_execute(retries:, error_output: "")
|
99
|
+
tests = retryable_tests(error_output)
|
100
|
+
|
101
|
+
if tests.empty?
|
102
|
+
UI.crash!("Failed to find failed tests to retry (could not parse error output)")
|
103
|
+
end
|
104
|
+
|
105
|
+
Scan.config[:only_testing] = tests
|
106
|
+
UI.important("Retrying tests: #{Scan.config[:only_testing].join(', ')}")
|
107
|
+
|
108
|
+
retries -= 1
|
109
|
+
UI.important("Number of retries remaining: #{retries}")
|
110
|
+
|
111
|
+
return execute(retries: retries)
|
112
|
+
end
|
113
|
+
|
114
|
+
def retryable_tests(input)
|
115
|
+
input = Helper.strip_ansi_colors(input)
|
116
|
+
|
117
|
+
retryable_tests = []
|
118
|
+
|
119
|
+
failing_tests = input.split("Failing tests:\n").fetch(1, [])
|
120
|
+
.split("\n\n").first
|
121
|
+
|
122
|
+
suites = failing_tests.split(/(?=\n\s+[\w\s]+:\n)/)
|
123
|
+
|
124
|
+
suites.each do |suite|
|
125
|
+
suite_name = suite.match(/\s*([\w\s]+):/).captures.first
|
126
|
+
|
127
|
+
test_cases = suite.split(":\n").fetch(1, []).split("\n").each
|
128
|
+
.select { |line| line.match?(/^\s+/) }
|
129
|
+
.map { |line| line.strip.gsub(".", "/").gsub("()", "") }
|
130
|
+
.map { |line| suite_name + "/" + line }
|
131
|
+
|
132
|
+
retryable_tests += test_cases
|
133
|
+
end
|
134
|
+
|
135
|
+
return retryable_tests.uniq
|
136
|
+
end
|
137
|
+
|
85
138
|
def handle_results(tests_exit_status)
|
86
139
|
if Scan.config[:disable_xcpretty]
|
87
140
|
unless tests_exit_status == 0
|
@@ -162,16 +162,18 @@ module Scan
|
|
162
162
|
Scan.cache[:build_path]
|
163
163
|
end
|
164
164
|
|
165
|
+
# The path to the result bundle
|
165
166
|
def result_bundle_path
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
Scan.cache[:result_bundle_path] = path
|
167
|
+
retry_count = Scan.cache[:retry_attempt] || 0
|
168
|
+
attempt = retry_count > 0 ? "-#{retry_count}" : ""
|
169
|
+
ext = FastlaneCore::Helper.xcode_version.to_i >= 11 ? '.xcresult' : '.test_result'
|
170
|
+
path = File.join(Scan.config[:output_directory], Scan.config[:scheme]) + attempt + ext
|
171
|
+
if File.directory?(path)
|
172
|
+
FileUtils.remove_dir(path)
|
173
173
|
end
|
174
|
-
|
174
|
+
Scan.cache[:result_bundle_path] = path
|
175
|
+
|
176
|
+
return path
|
175
177
|
end
|
176
178
|
end
|
177
179
|
end
|
@@ -34,22 +34,22 @@ module Screengrab
|
|
34
34
|
def find_platform_tools(android_home)
|
35
35
|
return nil unless android_home
|
36
36
|
|
37
|
-
platform_tools_path = File.join(android_home, 'platform-tools')
|
37
|
+
platform_tools_path = Helper.localize_file_path(File.join(android_home, 'platform-tools'))
|
38
38
|
File.directory?(platform_tools_path) ? platform_tools_path : nil
|
39
39
|
end
|
40
40
|
|
41
41
|
def find_build_tools(android_home, build_tools_version)
|
42
42
|
return nil unless android_home
|
43
43
|
|
44
|
-
build_tools_dir = File.join(android_home, 'build-tools')
|
44
|
+
build_tools_dir = Helper.localize_file_path(File.join(android_home, 'build-tools'))
|
45
45
|
|
46
46
|
return nil unless build_tools_dir && File.directory?(build_tools_dir)
|
47
47
|
|
48
|
-
return File.join(build_tools_dir, build_tools_version) if build_tools_version
|
48
|
+
return Helper.localize_file_path(File.join(build_tools_dir, build_tools_version)) if build_tools_version
|
49
49
|
|
50
50
|
version = select_build_tools_version(build_tools_dir)
|
51
51
|
|
52
|
-
return version ? File.join(build_tools_dir, version) : nil
|
52
|
+
return version ? Helper.localize_file_path(File.join(build_tools_dir, version)) : nil
|
53
53
|
end
|
54
54
|
|
55
55
|
def select_build_tools_version(build_tools_dir)
|
@@ -74,6 +74,7 @@ module Screengrab
|
|
74
74
|
return FastlaneCore::CommandExecutor.which('adb') unless platform_tools_path
|
75
75
|
|
76
76
|
adb_path = Helper.get_executable_path(File.join(platform_tools_path, 'adb'))
|
77
|
+
adb_path = Helper.localize_file_path(adb_path)
|
77
78
|
return executable_command?(adb_path) ? adb_path : nil
|
78
79
|
end
|
79
80
|
|
@@ -81,6 +82,7 @@ module Screengrab
|
|
81
82
|
return FastlaneCore::CommandExecutor.which('aapt') unless build_tools_path
|
82
83
|
|
83
84
|
aapt_path = Helper.get_executable_path(File.join(build_tools_path, 'aapt'))
|
85
|
+
aapt_path = Helper.localize_file_path(aapt_path)
|
84
86
|
return executable_command?(aapt_path) ? aapt_path : nil
|
85
87
|
end
|
86
88
|
|
@@ -308,7 +308,7 @@ module Screengrab
|
|
308
308
|
if out =~ /Permission denied/
|
309
309
|
dir = File.dirname(path)
|
310
310
|
base = File.basename(path)
|
311
|
-
run_adb_command("-s #{device_serial} shell run-as #{@config[:app_package_name]}
|
311
|
+
run_adb_command("-s #{device_serial} shell run-as #{@config[:app_package_name]} \"tar -cC #{dir} #{base}\" | tar -xv -f- -C #{tempdir}",
|
312
312
|
print_all: false,
|
313
313
|
print_command: true)
|
314
314
|
end
|
@@ -60,7 +60,7 @@ module Sigh
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def api_token
|
63
|
-
api_token ||= Spaceship::ConnectAPI::Token.create(Sigh.config[:api_key]) if Sigh.config[:api_key]
|
63
|
+
api_token ||= Spaceship::ConnectAPI::Token.create(**Sigh.config[:api_key]) if Sigh.config[:api_key]
|
64
64
|
api_token ||= Spaceship::ConnectAPI::Token.from_json_file(Sigh.config[:api_key_path]) if Sigh.config[:api_key_path]
|
65
65
|
return api_token
|
66
66
|
end
|
data/sigh/lib/sigh/options.rb
CHANGED
data/sigh/lib/sigh/runner.rb
CHANGED
@@ -21,6 +21,10 @@ module Sigh
|
|
21
21
|
UI.message("Creating authorization token for App Store Connect API")
|
22
22
|
Spaceship::ConnectAPI.token = api_token
|
23
23
|
else
|
24
|
+
# Username is now optional since addition of App Store Connect API Key
|
25
|
+
# Force asking for username to prompt user if not already set
|
26
|
+
Sigh.config.fetch(:username, force_ask: true)
|
27
|
+
|
24
28
|
# Team selection passed though FASTLANE_ITC_TEAM_ID and FASTLANE_ITC_TEAM_NAME environment variables
|
25
29
|
# Prompts select team if multiple teams and none specified
|
26
30
|
UI.message("Starting login with user '#{Sigh.config[:username]}'")
|
@@ -60,7 +64,7 @@ module Sigh
|
|
60
64
|
end
|
61
65
|
|
62
66
|
def api_token
|
63
|
-
@api_token ||= Spaceship::ConnectAPI::Token.create(Sigh.config[:api_key]) if Sigh.config[:api_key]
|
67
|
+
@api_token ||= Spaceship::ConnectAPI::Token.create(**Sigh.config[:api_key]) if Sigh.config[:api_key]
|
64
68
|
@api_token ||= Spaceship::ConnectAPI::Token.from_json_file(Sigh.config[:api_key_path]) if Sigh.config[:api_key_path]
|
65
69
|
return @api_token
|
66
70
|
end
|
@@ -84,6 +84,10 @@ module Snapshot
|
|
84
84
|
{
|
85
85
|
# snapshot in Xcode 9 saves screenshots with the SIMULATOR_DEVICE_NAME
|
86
86
|
# which includes spaces
|
87
|
+
'iPhone 12 Pro Max' => "iPhone 12 Pro Max",
|
88
|
+
'iPhone 12 Pro' => "iPhone 12 Pro",
|
89
|
+
'iPhone 12 mini' => "iPhone 12 mini",
|
90
|
+
'iPhone 12' => "iPhone 12",
|
87
91
|
'iPhone 11 Pro Max' => "iPhone 11 Pro Max",
|
88
92
|
'iPhone 11 Pro' => "iPhone 11 Pro",
|
89
93
|
'iPhone 11' => "iPhone 11",
|
data/spaceship/README.md
CHANGED
@@ -111,21 +111,11 @@ When your Apple account has 2 factor verification enabled, you'll automatically
|
|
111
111
|
|
112
112
|
#### Web sessions
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
```sh
|
117
|
-
fastlane spaceauth -u user@example.org
|
118
|
-
```
|
119
|
-
|
120
|
-
This will authenticate you and provide a string that can be transferred to your CI system. Copy everything from `---\n` to your CI server and provide it as environment variable named `FASTLANE_SESSION`. For example:
|
121
|
-
|
122
|
-
```
|
123
|
-
export FASTLANE_SESSION='---\n- !ruby/object:HTTP::Cookie\n name: DES5c148586dfd451e55afbaaa5f62418f91\n value: HSARMTKNSRVTWFla1+yO4gVPowH17VaaaxPFnUdMUegQZxqy1Ie1c2v6bM1vSOzIbuOmrl/FNenlScsd/NbF7/Lw4cpnL15jsyg0TOJwP32tC/NguPiyOaaaU+jrj4tf4uKdIywVaaaFSRVT\n domain: idmsa.apple.com\n for_domain: true\n path: "/"\n secure: true\n httponly: true\n expires: 2016-04-27 23:55:56.000000000 Z\n max_age: \n created_at: 2016-03-28 16:55:57.032086000 -07:00\n accessed_at: 2016-03-28 19:11:17.828141000 -07:00\n'
|
124
|
-
```
|
114
|
+
See [Continuous Integration > Authenticating with Apple services > Method 2: Two-step or two-factor authentication > Storing a manually verified session using spaceauth](https://docs.fastlane.tools/best-practices/continuous-integration/#storing-a-manually-verified-session-using-spaceauth)
|
125
115
|
|
126
116
|
#### Transporter
|
127
117
|
|
128
|
-
See [
|
118
|
+
See [Getting Started > iOS > Authentication > Method 3: Application-specific passwords](https://docs.fastlane.tools/getting-started/ios/authentication/#method-3-application-specific-passwords)
|
129
119
|
|
130
120
|
## _spaceship_ in use
|
131
121
|
|
@@ -39,9 +39,10 @@ module Spaceship
|
|
39
39
|
command :spaceauth do |c|
|
40
40
|
c.syntax = 'fastlane spaceship spaceauth'
|
41
41
|
c.description = 'Authentication helper for spaceship/fastlane to work with Apple 2-Step/2FA'
|
42
|
+
c.option('--copy_to_clipboard', 'Whether the session string should be copied to clipboard. For more info see https://docs.fastlane.tools/best-practices/continuous-integration/#storing-a-manually-verified-session-using-spaceauth`')
|
42
43
|
|
43
44
|
c.action do |args, options|
|
44
|
-
Spaceship::SpaceauthRunner.new(username: options.user).run
|
45
|
+
Spaceship::SpaceauthRunner.new(username: options.user, copy_to_clipboard: options.copy_to_clipboard).run
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
@@ -112,7 +112,7 @@ module Spaceship
|
|
112
112
|
timeout_minutes = (ENV["SPACESHIP_SCREENSHOT_UPLOAD_TIMEOUT"] || 20).to_i
|
113
113
|
|
114
114
|
loop do
|
115
|
-
# This error handling needs to be revised since any error
|
115
|
+
# This error handling needs to be revised since any error occurred can reach here.
|
116
116
|
# It should handle errors based on what status code is.
|
117
117
|
puts("Waiting for screenshots to appear before uploading. This is unlikely to be recovered unless it's 503 error. error=\"#{error}\"")
|
118
118
|
sleep(30)
|
@@ -38,6 +38,11 @@ module Spaceship
|
|
38
38
|
return client.post_bulk_beta_tester_assignments(beta_group_id: id, beta_testers: beta_testers)
|
39
39
|
end
|
40
40
|
|
41
|
+
def add_beta_testers(client: nil, beta_tester_ids:)
|
42
|
+
client ||= Spaceship::ConnectAPI
|
43
|
+
return client.add_beta_tester_to_group(beta_group_id: id, beta_tester_ids: beta_tester_ids)
|
44
|
+
end
|
45
|
+
|
41
46
|
def update(client: nil, attributes: nil)
|
42
47
|
return if attributes.empty?
|
43
48
|
|
@@ -275,6 +275,19 @@ module Spaceship
|
|
275
275
|
test_flight_request_client.post("bulkBetaTesterAssignments", body)
|
276
276
|
end
|
277
277
|
|
278
|
+
def add_beta_tester_to_group(beta_group_id: nil, beta_tester_ids: nil)
|
279
|
+
beta_tester_ids || []
|
280
|
+
body = {
|
281
|
+
data: beta_tester_ids.map do |id|
|
282
|
+
{
|
283
|
+
type: "betaTesters",
|
284
|
+
id: id
|
285
|
+
}
|
286
|
+
end
|
287
|
+
}
|
288
|
+
test_flight_request_client.post("betaGroups/#{beta_group_id}/relationships/betaTesters", body)
|
289
|
+
end
|
290
|
+
|
278
291
|
def delete_beta_tester_from_apps(beta_tester_id: nil, app_ids: [])
|
279
292
|
body = {
|
280
293
|
data: app_ids.map do |id|
|
@@ -37,7 +37,7 @@ module Spaceship
|
|
37
37
|
raise "App Store Connect API key JSON is missing field(s): #{missing_keys.join(', ')}"
|
38
38
|
end
|
39
39
|
|
40
|
-
self.create(json)
|
40
|
+
self.create(**json)
|
41
41
|
end
|
42
42
|
|
43
43
|
def self.create(key_id: nil, issuer_id: nil, filepath: nil, key: nil, is_key_content_base64: false, duration: nil, in_house: nil, **)
|
@@ -60,14 +60,16 @@ module Spaceship
|
|
60
60
|
key_id: key_id,
|
61
61
|
issuer_id: issuer_id,
|
62
62
|
key: OpenSSL::PKey::EC.new(key),
|
63
|
+
key_raw: key,
|
63
64
|
duration: duration,
|
64
65
|
in_house: in_house
|
65
66
|
)
|
66
67
|
end
|
67
68
|
|
68
|
-
def initialize(key_id: nil, issuer_id: nil, key: nil, duration: nil, in_house: nil)
|
69
|
+
def initialize(key_id: nil, issuer_id: nil, key: nil, key_raw: nil, duration: nil, in_house: nil)
|
69
70
|
@key_id = key_id
|
70
71
|
@key = key
|
72
|
+
@key_raw = key_raw
|
71
73
|
@issuer_id = issuer_id
|
72
74
|
@duration = duration
|
73
75
|
@in_house = in_house
|
@@ -97,6 +99,10 @@ module Spaceship
|
|
97
99
|
def expired?
|
98
100
|
@expiration < Time.now
|
99
101
|
end
|
102
|
+
|
103
|
+
def write_key_to_file(path)
|
104
|
+
File.open(path, 'w') { |f| f.write(@key_raw) }
|
105
|
+
end
|
100
106
|
end
|
101
107
|
end
|
102
108
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'colored'
|
2
2
|
require 'credentials_manager/appfile_config'
|
3
3
|
require 'yaml'
|
4
|
+
require 'fastlane_core'
|
4
5
|
|
5
6
|
require_relative 'tunes/tunes_client'
|
6
7
|
|
7
8
|
module Spaceship
|
8
9
|
class SpaceauthRunner
|
9
|
-
def initialize(username: nil)
|
10
|
+
def initialize(username: nil, copy_to_clipboard: nil)
|
10
11
|
@username = username
|
11
12
|
@username ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
|
12
13
|
@username ||= ask("Username: ")
|
14
|
+
@copy_to_clipboard = copy_to_clipboard
|
13
15
|
end
|
14
16
|
|
15
17
|
def run
|
@@ -22,7 +24,7 @@ module Spaceship
|
|
22
24
|
puts("Could not login to App Store Connect".red)
|
23
25
|
puts("Please check your credentials and try again.".yellow)
|
24
26
|
puts("This could be an issue with App Store Connect,".yellow)
|
25
|
-
puts("Please try unsetting the FASTLANE_SESSION environment variable".yellow)
|
27
|
+
puts("Please try unsetting the FASTLANE_SESSION environment variable by calling 'unset FASTLANE_SESSION'".yellow)
|
26
28
|
puts("(if it is set) and re-run `fastlane spaceauth`".yellow)
|
27
29
|
puts("")
|
28
30
|
puts("Exception type: #{ex.class}")
|
@@ -49,22 +51,30 @@ module Spaceship
|
|
49
51
|
cookie.name.start_with?("myacinfo") || cookie.name == "dqsid" || cookie.name.start_with?("DES")
|
50
52
|
end
|
51
53
|
|
52
|
-
yaml = cookies.to_yaml.gsub("\n", "\\n")
|
54
|
+
@yaml = cookies.to_yaml.gsub("\n", "\\n")
|
53
55
|
|
54
56
|
puts("---")
|
55
57
|
puts("")
|
56
58
|
puts("Pass the following via the FASTLANE_SESSION environment variable:")
|
57
|
-
puts(yaml.cyan.underline)
|
59
|
+
puts(@yaml.cyan.underline)
|
58
60
|
puts("")
|
59
61
|
puts("")
|
60
62
|
puts("Example:")
|
61
|
-
puts("export FASTLANE_SESSION='#{yaml}'".cyan.underline)
|
63
|
+
puts("export FASTLANE_SESSION='#{@yaml}'".cyan.underline)
|
62
64
|
|
63
|
-
if
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
if @copy_to_clipboard == false
|
66
|
+
puts("Skipped asking to copy the session string into your clipboard ⏭️".green)
|
67
|
+
elsif @copy_to_clipboard || (mac? && Spaceship::Client::UserInterface.interactive? && agree("🙄 Should fastlane copy the cookie into your clipboard, so you can easily paste it? (y/n)", true))
|
68
|
+
FastlaneCore::Clipboard.copy(content: @yaml)
|
69
|
+
puts("Successfully copied the session string into your clipboard 🎨".green)
|
67
70
|
end
|
71
|
+
|
72
|
+
return self
|
73
|
+
end
|
74
|
+
|
75
|
+
def session_string
|
76
|
+
FastlaneCore::UI.user_error!("`#{__method__}` method called before calling `run` in `SpaceauthRunner`") unless @yaml
|
77
|
+
@yaml
|
68
78
|
end
|
69
79
|
|
70
80
|
def mac?
|