fastlane 2.139.0 → 2.144.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 +85 -72
- data/cert/lib/cert/options.rb +12 -5
- data/cert/lib/cert/runner.rb +13 -0
- data/deliver/lib/deliver/options.rb +28 -2
- data/deliver/lib/deliver/runner.rb +13 -2
- data/fastlane/lib/fastlane/action.rb +1 -1
- data/fastlane/lib/fastlane/actions/.hockey.rb.swp +0 -0
- data/fastlane/lib/fastlane/actions/.slack.rb.swp +0 -0
- data/fastlane/lib/fastlane/actions/.update_project_provisioning.rb.swp +0 -0
- data/fastlane/lib/fastlane/actions/README.md +2 -0
- data/fastlane/lib/fastlane/actions/app_store_build_number.rb +13 -5
- data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +7 -1
- data/fastlane/lib/fastlane/actions/build_app.rb +157 -6
- data/fastlane/lib/fastlane/actions/build_ios_app.rb +28 -132
- data/fastlane/lib/fastlane/actions/build_mac_app.rb +46 -0
- data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +3 -0
- data/fastlane/lib/fastlane/actions/cocoapods.rb +2 -2
- data/fastlane/lib/fastlane/actions/crashlytics.rb +14 -2
- data/fastlane/lib/fastlane/actions/create_pull_request.rb +29 -0
- data/fastlane/lib/fastlane/actions/docs/{build_ios_app.md → build_app.md} +1 -1
- data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +22 -6
- data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +22 -6
- data/fastlane/lib/fastlane/actions/ensure_git_branch.rb +1 -1
- data/fastlane/lib/fastlane/actions/ensure_xcode_version.rb +35 -7
- data/fastlane/lib/fastlane/actions/frame_screenshots.rb +2 -1
- data/fastlane/lib/fastlane/actions/get_github_release.rb +3 -0
- data/fastlane/lib/fastlane/actions/gradle.rb +43 -2
- data/fastlane/lib/fastlane/actions/gym.rb +3 -7
- data/fastlane/lib/fastlane/actions/import_from_git.rb +4 -0
- data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +9 -3
- data/fastlane/lib/fastlane/actions/notarize.rb +183 -0
- data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +7 -1
- data/fastlane/lib/fastlane/actions/run_tests.rb +5 -22
- data/fastlane/lib/fastlane/actions/s3.rb +5 -291
- data/fastlane/lib/fastlane/actions/set_github_release.rb +1 -1
- data/fastlane/lib/fastlane/actions/spm.rb +8 -0
- data/fastlane/lib/fastlane/actions/swiftlint.rb +45 -9
- data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +190 -0
- data/fastlane/lib/fastlane/actions/update_plist.rb +37 -2
- data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +13 -3
- data/fastlane/lib/fastlane/actions/upload_to_app_store.rb +1 -0
- data/fastlane/lib/fastlane/fast_file.rb +13 -3
- data/fastlane/lib/fastlane/helper/adb_helper.rb +1 -1
- data/fastlane/lib/fastlane/helper/s3_client_helper.rb +56 -0
- data/fastlane/lib/fastlane/plugins/plugin_manager.rb +1 -1
- data/fastlane/lib/fastlane/plugins/template/.rubocop.yml +2 -0
- data/fastlane/lib/fastlane/runner.rb +23 -18
- data/fastlane/lib/fastlane/server/socket_server_action_command_executor.rb +1 -1
- 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 +422 -45
- data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.xcworkspace/xcuserdata/josh.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/fastlane/swift/Gymfile.swift +1 -1
- data/fastlane/swift/GymfileProtocol.swift +17 -1
- data/fastlane/swift/Matchfile.swift +1 -1
- data/fastlane/swift/MatchfileProtocol.swift +23 -3
- data/fastlane/swift/Precheckfile.swift +1 -1
- data/fastlane/swift/RubyCommand.swift +1 -1
- data/fastlane/swift/Scanfile.swift +1 -1
- data/fastlane/swift/ScanfileProtocol.swift +21 -1
- data/fastlane/swift/Screengrabfile.swift +1 -1
- data/fastlane/swift/Snapshotfile.swift +1 -1
- data/fastlane/swift/SnapshotfileProtocol.swift +9 -1
- data/fastlane_core/lib/fastlane_core/cert_checker.rb +28 -0
- data/fastlane_core/lib/fastlane_core/device_manager.rb +1 -1
- data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +1 -0
- data/fastlane_core/lib/fastlane_core/keychain_importer.rb +2 -0
- data/fastlane_core/lib/fastlane_core/project.rb +27 -0
- data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +15 -2
- data/frameit/lib/frameit/commands_generator.rb +25 -0
- data/frameit/lib/frameit/config_parser.rb +31 -9
- data/frameit/lib/frameit/device.rb +90 -0
- data/frameit/lib/frameit/device_types.rb +121 -5
- data/frameit/lib/frameit/editor.rb +28 -40
- data/frameit/lib/frameit/offsets.rb +8 -1
- data/frameit/lib/frameit/options.rb +81 -54
- data/frameit/lib/frameit/runner.rb +17 -7
- data/frameit/lib/frameit/screenshot.rb +35 -47
- data/frameit/lib/frameit/template_finder.rb +15 -12
- data/gym/lib/gym/code_signing_mapping.rb +32 -3
- data/gym/lib/gym/detect_values.rb +34 -2
- data/gym/lib/gym/generators/package_command_generator.rb +8 -0
- data/gym/lib/gym/generators/package_command_generator_xcode7.rb +52 -17
- data/gym/lib/gym/module.rb +8 -0
- data/gym/lib/gym/options.rb +25 -1
- data/gym/lib/gym/runner.rb +70 -21
- data/match/lib/match/change_password.rb +1 -1
- data/match/lib/match/encryption.rb +4 -0
- data/match/lib/match/encryption/openssl.rb +1 -1
- data/match/lib/match/generator.rb +17 -3
- data/match/lib/match/importer.rb +35 -20
- data/match/lib/match/module.rb +5 -2
- data/match/lib/match/nuke.rb +59 -17
- data/match/lib/match/options.rb +38 -15
- data/match/lib/match/runner.rb +24 -8
- data/match/lib/match/setup.rb +1 -1
- data/match/lib/match/spaceship_ensure.rb +19 -9
- data/match/lib/match/storage.rb +4 -0
- data/match/lib/match/storage/git_storage.rb +5 -2
- data/match/lib/match/storage/google_cloud_storage.rb +2 -2
- data/match/lib/match/storage/s3_storage.rb +162 -0
- data/pilot/lib/pilot/.manager.rb.swp +0 -0
- data/pilot/lib/pilot/build_manager.rb +24 -9
- data/scan/lib/scan/detect_values.rb +6 -1
- data/scan/lib/scan/manager.rb +18 -1
- data/scan/lib/scan/options.rb +28 -1
- data/scan/lib/scan/runner.rb +9 -7
- data/scan/lib/scan/slack_poster.rb +1 -1
- data/scan/lib/scan/test_command_generator.rb +12 -5
- data/screengrab/lib/screengrab/runner.rb +31 -18
- data/sigh/lib/sigh/.runner.rb.swp +0 -0
- data/snapshot/lib/snapshot/fixes/simulator_shared_pasteboard.rb +16 -0
- data/snapshot/lib/snapshot/options.rb +12 -1
- data/snapshot/lib/snapshot/simulator_launchers/launcher_configuration.rb +2 -0
- data/snapshot/lib/snapshot/simulator_launchers/simulator_launcher_base.rb +13 -0
- data/spaceship/lib/spaceship/connect_api/.DS_Store +0 -0
- data/spaceship/lib/spaceship/connect_api/models/.bundle_id.rb.swp +0 -0
- data/{gym/lib/gym/.runner.rb.swp → spaceship/lib/spaceship/connect_api/models/.bundle_id_capability.rb.swp} +0 -0
- data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -0
- data/spaceship/lib/spaceship/connect_api/models/beta_feedback.rb +4 -0
- data/spaceship/lib/spaceship/connect_api/models/build.rb +1 -2
- data/spaceship/lib/spaceship/connect_api/models/certificate.rb +2 -0
- data/spaceship/lib/spaceship/connect_api/testflight/testflight.rb +29 -0
- data/spaceship/lib/spaceship/portal/app.rb +11 -2
- data/spaceship/lib/spaceship/tunes/app_version.rb +6 -1
- data/spaceship/lib/spaceship/tunes/iap.rb +11 -11
- data/spaceship/lib/spaceship/tunes/iap_detail.rb +7 -3
- data/spaceship/lib/spaceship/tunes/iap_families.rb +12 -1
- data/spaceship/lib/spaceship/tunes/iap_family_details.rb +26 -17
- data/spaceship/lib/spaceship/tunes/iap_status.rb +5 -1
- data/spaceship/lib/spaceship/tunes/tunes_client.rb +2 -2
- data/supply/lib/supply/client.rb +1 -1
- metadata +63 -18
@@ -1,13 +1,9 @@
|
|
1
1
|
module Fastlane
|
2
2
|
module Actions
|
3
|
-
require 'fastlane/actions/
|
4
|
-
class GymAction <
|
5
|
-
#####################################################
|
6
|
-
# @!group Documentation
|
7
|
-
#####################################################
|
8
|
-
|
3
|
+
require 'fastlane/actions/build_app'
|
4
|
+
class GymAction < BuildAppAction
|
9
5
|
def self.description
|
10
|
-
"Alias for the `
|
6
|
+
"Alias for the `build_app` action"
|
11
7
|
end
|
12
8
|
end
|
13
9
|
end
|
@@ -26,6 +26,10 @@ module Fastlane
|
|
26
26
|
description: "The branch or tag to check-out on the repository",
|
27
27
|
default_value: 'HEAD',
|
28
28
|
optional: true),
|
29
|
+
FastlaneCore::ConfigItem.new(key: :dependencies,
|
30
|
+
description: "The array of additional Fastfiles in the repository",
|
31
|
+
default_value: [],
|
32
|
+
optional: true),
|
29
33
|
FastlaneCore::ConfigItem.new(key: :path,
|
30
34
|
description: "The path of the Fastfile in the repository",
|
31
35
|
default_value: 'fastlane/Fastfile',
|
@@ -4,12 +4,17 @@ module Fastlane
|
|
4
4
|
module Actions
|
5
5
|
module SharedValues
|
6
6
|
LATEST_TESTFLIGHT_BUILD_NUMBER = :LATEST_TESTFLIGHT_BUILD_NUMBER
|
7
|
+
LATEST_TESTFLIGHT_VERSION = :LATEST_TESTFLIGHT_VERSION
|
7
8
|
end
|
8
9
|
|
9
10
|
class LatestTestflightBuildNumberAction < Action
|
10
11
|
def self.run(params)
|
11
|
-
|
12
|
-
Actions.lane_context[SharedValues::
|
12
|
+
AppStoreBuildNumberAction.run(params)
|
13
|
+
build_nr = Actions.lane_context[SharedValues::LATEST_BUILD_NUMBER]
|
14
|
+
build_v = Actions.lane_context[SharedValues::LATEST_VERSION]
|
15
|
+
Actions.lane_context[SharedValues::LATEST_TESTFLIGHT_BUILD_NUMBER] = build_nr
|
16
|
+
Actions.lane_context[SharedValues::LATEST_TESTFLIGHT_VERSION] = build_v
|
17
|
+
return build_nr
|
13
18
|
end
|
14
19
|
|
15
20
|
#####################################################
|
@@ -93,7 +98,8 @@ module Fastlane
|
|
93
98
|
|
94
99
|
def self.output
|
95
100
|
[
|
96
|
-
['LATEST_TESTFLIGHT_BUILD_NUMBER', 'The latest build number of the latest version of the app uploaded to TestFlight']
|
101
|
+
['LATEST_TESTFLIGHT_BUILD_NUMBER', 'The latest build number of the latest version of the app uploaded to TestFlight'],
|
102
|
+
['LATEST_TESTFLIGHT_VERSION', 'The version of the latest build number']
|
97
103
|
]
|
98
104
|
end
|
99
105
|
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Actions
|
3
|
+
class NotarizeAction < Action
|
4
|
+
def self.run(params)
|
5
|
+
package_path = params[:package]
|
6
|
+
bundle_id = params[:bundle_id]
|
7
|
+
try_early_stapling = params[:try_early_stapling]
|
8
|
+
print_log = params[:print_log]
|
9
|
+
verbose = params[:verbose]
|
10
|
+
|
11
|
+
# Compress and read bundle identifier only for .app bundle.
|
12
|
+
compressed_package_path = nil
|
13
|
+
if File.extname(package_path) == '.app'
|
14
|
+
compressed_package_path = "#{package_path}.zip"
|
15
|
+
Actions.sh(
|
16
|
+
"ditto -c -k --rsrc --keepParent \"#{package_path}\" \"#{compressed_package_path}\"",
|
17
|
+
log: verbose
|
18
|
+
)
|
19
|
+
|
20
|
+
unless bundle_id
|
21
|
+
info_plist_path = File.join(package_path, 'Contents', 'Info.plist')
|
22
|
+
bundle_id = Actions.sh(
|
23
|
+
"/usr/libexec/PlistBuddy -c \"Print :CFBundleIdentifier\" \"#{info_plist_path}\"",
|
24
|
+
log: verbose
|
25
|
+
).strip
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
UI.user_error!('Could not read bundle identifier, provide as a parameter') unless bundle_id
|
30
|
+
|
31
|
+
apple_id_account = CredentialsManager::AccountManager.new(user: params[:username])
|
32
|
+
|
33
|
+
# Add password as a temporary environment variable for altool.
|
34
|
+
# Use app specific password if specified.
|
35
|
+
ENV['FL_NOTARIZE_PASSWORD'] = ENV['FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD'] || apple_id_account.password
|
36
|
+
|
37
|
+
UI.message('Uploading package to notarization service, might take a while')
|
38
|
+
|
39
|
+
notarization_upload_command = "xcrun altool --notarize-app -t osx -f \"#{compressed_package_path || package_path}\" --primary-bundle-id #{bundle_id} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD --output-format xml"
|
40
|
+
notarization_upload_command << " --asc-provider \"#{params[:asc_provider]}\"" if params[:asc_provider]
|
41
|
+
|
42
|
+
notarization_upload_response = Actions.sh(
|
43
|
+
notarization_upload_command,
|
44
|
+
log: verbose
|
45
|
+
)
|
46
|
+
|
47
|
+
FileUtils.rm_rf(compressed_package_path) if compressed_package_path
|
48
|
+
|
49
|
+
notarization_upload_plist = Plist.parse_xml(notarization_upload_response)
|
50
|
+
notarization_request_id = notarization_upload_plist['notarization-upload']['RequestUUID']
|
51
|
+
|
52
|
+
UI.success("Successfully uploaded package to notarization service with request identifier #{notarization_request_id}")
|
53
|
+
|
54
|
+
notarization_info = {}
|
55
|
+
while notarization_info.empty? || (notarization_info['Status'] == 'in progress')
|
56
|
+
if notarization_info.empty?
|
57
|
+
UI.message('Waiting to query request status')
|
58
|
+
elsif try_early_stapling
|
59
|
+
UI.message('Request in progress, trying early staple')
|
60
|
+
|
61
|
+
begin
|
62
|
+
self.staple(package_path, verbose)
|
63
|
+
UI.message('Successfully notarized and early stapled package.')
|
64
|
+
|
65
|
+
return
|
66
|
+
rescue
|
67
|
+
UI.message('Early staple failed, waiting to query again')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
sleep(30)
|
72
|
+
|
73
|
+
UI.message('Querying request status')
|
74
|
+
|
75
|
+
notarization_info_response = Actions.sh(
|
76
|
+
"xcrun altool --notarization-info #{notarization_request_id} -u #{apple_id_account.user} -p @env:FL_NOTARIZE_PASSWORD --output-format xml",
|
77
|
+
log: verbose
|
78
|
+
)
|
79
|
+
|
80
|
+
notarization_info_plist = Plist.parse_xml(notarization_info_response)
|
81
|
+
notarization_info = notarization_info_plist['notarization-info']
|
82
|
+
end
|
83
|
+
|
84
|
+
log_url = notarization_info['LogFileURL']
|
85
|
+
ENV['FL_NOTARIZE_LOG_FILE_URL'] = log_url
|
86
|
+
log_suffix = ''
|
87
|
+
if log_url && print_log
|
88
|
+
log_response = Net::HTTP.get(URI(log_url))
|
89
|
+
log_json_object = JSON.parse(log_response)
|
90
|
+
log_suffix = ", with log:\n#{JSON.pretty_generate(log_json_object)}"
|
91
|
+
end
|
92
|
+
|
93
|
+
case notarization_info['Status']
|
94
|
+
when 'success'
|
95
|
+
UI.message('Stapling package')
|
96
|
+
|
97
|
+
self.staple(package_path, verbose)
|
98
|
+
|
99
|
+
UI.success("Successfully notarized and stapled package#{log_suffix}")
|
100
|
+
when 'invalid'
|
101
|
+
UI.user_error!("Could not notarize package with message '#{notarization_info['Status Message']}'#{log_suffix}")
|
102
|
+
else
|
103
|
+
UI.crash!("Could not notarize package with status '#{notarization_info['Status']}'#{log_suffix}")
|
104
|
+
end
|
105
|
+
ensure
|
106
|
+
ENV.delete('FL_NOTARIZE_PASSWORD')
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.staple(package_path, verbose)
|
110
|
+
Actions.sh(
|
111
|
+
"xcrun stapler staple \"#{package_path}\"",
|
112
|
+
log: verbose
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.description
|
117
|
+
'Notarizes a macOS app'
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.authors
|
121
|
+
['zeplin']
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.available_options
|
125
|
+
username = CredentialsManager::AppfileConfig.try_fetch_value(:apple_dev_portal_id)
|
126
|
+
username ||= CredentialsManager::AppfileConfig.try_fetch_value(:apple_id)
|
127
|
+
|
128
|
+
asc_provider = CredentialsManager::AppfileConfig.try_fetch_value(:itc_team_id)
|
129
|
+
|
130
|
+
[
|
131
|
+
FastlaneCore::ConfigItem.new(key: :package,
|
132
|
+
env_name: 'FL_NOTARIZE_PACKAGE',
|
133
|
+
description: 'Path to package to notarize, e.g. .app bundle or disk image',
|
134
|
+
is_string: true,
|
135
|
+
verify_block: proc do |value|
|
136
|
+
UI.user_error!("Could not find package at '#{value}'") unless File.exist?(value)
|
137
|
+
end),
|
138
|
+
FastlaneCore::ConfigItem.new(key: :try_early_stapling,
|
139
|
+
env_name: 'FL_NOTARIZE_TRY_EARLY_STAPLING',
|
140
|
+
description: 'Whether to try early stapling while the notarization request is in progress',
|
141
|
+
optional: true,
|
142
|
+
default_value: false,
|
143
|
+
type: Boolean),
|
144
|
+
FastlaneCore::ConfigItem.new(key: :bundle_id,
|
145
|
+
env_name: 'FL_NOTARIZE_BUNDLE_ID',
|
146
|
+
description: 'Bundle identifier to uniquely identify the package',
|
147
|
+
optional: true,
|
148
|
+
is_string: true),
|
149
|
+
FastlaneCore::ConfigItem.new(key: :username,
|
150
|
+
env_name: 'FL_NOTARIZE_USERNAME',
|
151
|
+
description: 'Apple ID username',
|
152
|
+
default_value: username,
|
153
|
+
default_value_dynamic: true),
|
154
|
+
FastlaneCore::ConfigItem.new(key: :asc_provider,
|
155
|
+
env_name: 'FL_NOTARIZE_ASC_PROVIDER',
|
156
|
+
description: 'Provider short name for accounts associated with multiple providers',
|
157
|
+
optional: true,
|
158
|
+
default_value: asc_provider),
|
159
|
+
FastlaneCore::ConfigItem.new(key: :print_log,
|
160
|
+
env_name: 'FL_NOTARIZE_PRINT_LOG',
|
161
|
+
description: 'Whether to print notarization log file, listing issues on failure and warnings on success',
|
162
|
+
optional: true,
|
163
|
+
default_value: false,
|
164
|
+
type: Boolean),
|
165
|
+
FastlaneCore::ConfigItem.new(key: :verbose,
|
166
|
+
env_name: 'FL_NOTARIZE_VERBOSE',
|
167
|
+
description: 'Whether to log requests',
|
168
|
+
optional: true,
|
169
|
+
default_value: false,
|
170
|
+
type: Boolean)
|
171
|
+
]
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.is_supported?(platform)
|
175
|
+
platform == :mac
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.category
|
179
|
+
:code_signing
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -26,6 +26,7 @@ module Fastlane
|
|
26
26
|
command << "--platforms=#{params[:platforms]}" if params[:platforms]
|
27
27
|
command << "--skip-import-validation" if params[:skip_import_validation]
|
28
28
|
command << "--skip-tests" if params[:skip_tests]
|
29
|
+
command << "--analyze" if params[:analyze]
|
29
30
|
|
30
31
|
result = Actions.sh(command.join(' '))
|
31
32
|
UI.success("Pod lib lint Successfully ⬆️ ")
|
@@ -144,7 +145,12 @@ module Fastlane
|
|
144
145
|
description: "Lint skips building and running tests during validation (available since cocoapods >= 1.3)",
|
145
146
|
type: Boolean,
|
146
147
|
default_value: false,
|
147
|
-
env_name: "FL_POD_LIB_LINT_SKIP_TESTS")
|
148
|
+
env_name: "FL_POD_LIB_LINT_SKIP_TESTS"),
|
149
|
+
FastlaneCore::ConfigItem.new(key: :analyze,
|
150
|
+
description: "Validate with the Xcode Static Analysis tool (available since cocoapods >= 1.6.1)",
|
151
|
+
type: Boolean,
|
152
|
+
default_value: false,
|
153
|
+
env_name: "FL_POD_LIB_LINT_ANALYZE")
|
148
154
|
]
|
149
155
|
end
|
150
156
|
|
@@ -10,17 +10,10 @@ module Fastlane
|
|
10
10
|
class RunTestsAction < Action
|
11
11
|
def self.run(values)
|
12
12
|
require 'scan'
|
13
|
-
|
13
|
+
manager = Scan::Manager.new
|
14
14
|
|
15
15
|
begin
|
16
|
-
|
17
|
-
Scan.config = values # we set this here to auto-detect missing values, which we need later on
|
18
|
-
unless values[:derived_data_path].to_s.empty?
|
19
|
-
plist_files_before = test_summary_filenames(values[:derived_data_path])
|
20
|
-
end
|
21
|
-
|
22
|
-
values[:destination] = destination # restore destination value
|
23
|
-
Scan::Manager.new.work(values)
|
16
|
+
manager.work(values)
|
24
17
|
|
25
18
|
zip_build_products_path = Scan.cache[:zip_build_products_path]
|
26
19
|
Actions.lane_context[SharedValues::SCAN_ZIP_BUILD_PRODUCTS_PATH] = zip_build_products_path if zip_build_products_path
|
@@ -37,8 +30,10 @@ module Fastlane
|
|
37
30
|
end
|
38
31
|
ensure
|
39
32
|
unless values[:derived_data_path].to_s.empty?
|
33
|
+
plist_files_before = manager.plist_files_before || []
|
34
|
+
|
40
35
|
Actions.lane_context[SharedValues::SCAN_DERIVED_DATA_PATH] = values[:derived_data_path]
|
41
|
-
plist_files_after = test_summary_filenames(values[:derived_data_path])
|
36
|
+
plist_files_after = manager.test_summary_filenames(values[:derived_data_path])
|
42
37
|
all_test_summaries = (plist_files_after - plist_files_before)
|
43
38
|
Actions.lane_context[SharedValues::SCAN_GENERATED_PLIST_FILES] = all_test_summaries
|
44
39
|
Actions.lane_context[SharedValues::SCAN_GENERATED_PLIST_FILE] = all_test_summaries.last
|
@@ -85,18 +80,6 @@ module Fastlane
|
|
85
80
|
|
86
81
|
private_class_method
|
87
82
|
|
88
|
-
def self.test_summary_filenames(derived_data_path)
|
89
|
-
files = []
|
90
|
-
|
91
|
-
# Xcode < 10
|
92
|
-
files += Dir["#{derived_data_path}/**/Logs/Test/*TestSummaries.plist"]
|
93
|
-
|
94
|
-
# Xcode 10
|
95
|
-
files += Dir["#{derived_data_path}/**/Logs/Test/*.xcresult/TestSummaries.plist"]
|
96
|
-
|
97
|
-
return files
|
98
|
-
end
|
99
|
-
|
100
83
|
def self.example_code
|
101
84
|
[
|
102
85
|
'run_tests',
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fastlane/erb_template_helper'
|
2
|
+
require 'fastlane/helper/s3_client_helper'
|
2
3
|
require 'ostruct'
|
3
4
|
require 'uri'
|
4
5
|
require 'cgi'
|
@@ -15,296 +16,9 @@ module Fastlane
|
|
15
16
|
S3_VERSION_OUTPUT_PATH ||= :S3_VERSION_OUTPUT_PATH
|
16
17
|
end
|
17
18
|
|
18
|
-
S3_ARGS_MAP = {
|
19
|
-
ipa: '-f',
|
20
|
-
dsym: '-d',
|
21
|
-
access_key: '-a',
|
22
|
-
secret_access_key: '-s',
|
23
|
-
bucket: '-b',
|
24
|
-
region: '-r',
|
25
|
-
acl: '--acl',
|
26
|
-
source: '--source-dir',
|
27
|
-
path: '-P'
|
28
|
-
}
|
29
|
-
|
30
|
-
# rubocop:disable Metrics/ClassLength
|
31
19
|
class S3Action < Action
|
32
20
|
def self.run(config)
|
33
|
-
|
34
|
-
params = {}
|
35
|
-
params[:ipa] = config[:ipa]
|
36
|
-
params[:dsym] = config[:dsym]
|
37
|
-
params[:access_key] = config[:access_key]
|
38
|
-
params[:secret_access_key] = config[:secret_access_key]
|
39
|
-
params[:bucket] = config[:bucket]
|
40
|
-
params[:region] = config[:region]
|
41
|
-
params[:acl] = config[:acl]
|
42
|
-
params[:source] = config[:source]
|
43
|
-
params[:path] = config[:path]
|
44
|
-
params[:upload_metadata] = config[:upload_metadata]
|
45
|
-
params[:plist_template_path] = config[:plist_template_path]
|
46
|
-
params[:plist_file_name] = config[:plist_file_name]
|
47
|
-
params[:html_template_path] = config[:html_template_path]
|
48
|
-
params[:html_file_name] = config[:html_file_name]
|
49
|
-
params[:version_template_path] = config[:version_template_path]
|
50
|
-
params[:version_file_name] = config[:version_file_name]
|
51
|
-
|
52
|
-
# Pulling parameters for other uses
|
53
|
-
s3_region = params[:region]
|
54
|
-
s3_access_key = params[:access_key]
|
55
|
-
s3_secret_access_key = params[:secret_access_key]
|
56
|
-
s3_bucket = params[:bucket]
|
57
|
-
ipa_file = params[:ipa]
|
58
|
-
dsym_file = params[:dsym]
|
59
|
-
s3_path = params[:path]
|
60
|
-
acl = params[:acl].to_sym
|
61
|
-
|
62
|
-
UI.user_error!("No S3 access key given, pass using `access_key: 'key'`") unless s3_access_key.to_s.length > 0
|
63
|
-
UI.user_error!("No S3 secret access key given, pass using `secret_access_key: 'secret key'`") unless s3_secret_access_key.to_s.length > 0
|
64
|
-
UI.user_error!("No S3 bucket given, pass using `bucket: 'bucket'`") unless s3_bucket.to_s.length > 0
|
65
|
-
UI.user_error!("No IPA file path given, pass using `ipa: 'ipa path'`") unless ipa_file.to_s.length > 0
|
66
|
-
|
67
|
-
plist_template_path = params[:plist_template_path]
|
68
|
-
plist_file_name = params[:plist_file_name]
|
69
|
-
html_template_path = params[:html_template_path]
|
70
|
-
html_file_name = params[:html_file_name]
|
71
|
-
version_template_path = params[:version_template_path]
|
72
|
-
version_file_name = params[:version_file_name]
|
73
|
-
|
74
|
-
s3_client = self.s3_client(s3_access_key, s3_secret_access_key, s3_region)
|
75
|
-
bucket = s3_client.buckets[s3_bucket]
|
76
|
-
|
77
|
-
url_part = self.expand_path_with_substitutions_from_ipa_plist(ipa_file, s3_path)
|
78
|
-
|
79
|
-
ipa_file_basename = File.basename(ipa_file)
|
80
|
-
ipa_file_name = "#{url_part}#{ipa_file_basename}"
|
81
|
-
ipa_file_data = File.open(ipa_file, 'rb')
|
82
|
-
|
83
|
-
ipa_url = self.upload_file(bucket, ipa_file_name, ipa_file_data, acl)
|
84
|
-
|
85
|
-
# Setting action and environment variables
|
86
|
-
Actions.lane_context[SharedValues::S3_IPA_OUTPUT_PATH] = ipa_url
|
87
|
-
ENV[SharedValues::S3_IPA_OUTPUT_PATH.to_s] = ipa_url
|
88
|
-
|
89
|
-
if dsym_file
|
90
|
-
dsym_file_basename = File.basename(dsym_file)
|
91
|
-
dsym_file_name = "#{url_part}#{dsym_file_basename}"
|
92
|
-
dsym_file_data = File.open(dsym_file, 'rb')
|
93
|
-
|
94
|
-
dsym_url = self.upload_file(bucket, dsym_file_name, dsym_file_data, acl)
|
95
|
-
|
96
|
-
# Setting action and environment variables
|
97
|
-
Actions.lane_context[SharedValues::S3_DSYM_OUTPUT_PATH] = dsym_url
|
98
|
-
ENV[SharedValues::S3_DSYM_OUTPUT_PATH.to_s] = dsym_url
|
99
|
-
|
100
|
-
end
|
101
|
-
|
102
|
-
if params[:upload_metadata] == false
|
103
|
-
return true
|
104
|
-
end
|
105
|
-
|
106
|
-
#####################################
|
107
|
-
#
|
108
|
-
# html and plist building
|
109
|
-
#
|
110
|
-
#####################################
|
111
|
-
|
112
|
-
# Gets info used for the plist
|
113
|
-
info = FastlaneCore::IpaFileAnalyser.fetch_info_plist_file(ipa_file)
|
114
|
-
|
115
|
-
build_num = info['CFBundleVersion']
|
116
|
-
bundle_id = info['CFBundleIdentifier']
|
117
|
-
bundle_version = info['CFBundleShortVersionString']
|
118
|
-
title = CGI.escapeHTML(info['CFBundleName'])
|
119
|
-
device_family = info['UIDeviceFamily']
|
120
|
-
full_version = "#{bundle_version}.#{build_num}"
|
121
|
-
|
122
|
-
# Creating plist and html names
|
123
|
-
s3_domain = AWS::Core::Endpoints.hostname(s3_region, 's3') || 's3.amazonaws.com'
|
124
|
-
plist_file_name ||= "#{url_part}#{URI.escape(title)}.plist"
|
125
|
-
plist_url = URI::HTTPS.build(host: s3_domain, path: "/#{s3_bucket}/#{plist_file_name}").to_s
|
126
|
-
|
127
|
-
html_file_name ||= "index.html"
|
128
|
-
|
129
|
-
version_file_name ||= "version.json"
|
130
|
-
|
131
|
-
# grabs module
|
132
|
-
eth = Fastlane::ErbTemplateHelper
|
133
|
-
|
134
|
-
# Creates plist from template
|
135
|
-
if plist_template_path && File.exist?(plist_template_path)
|
136
|
-
plist_template = eth.load_from_path(plist_template_path)
|
137
|
-
else
|
138
|
-
plist_template = eth.load("s3_plist_template")
|
139
|
-
end
|
140
|
-
plist_render = eth.render(plist_template, {
|
141
|
-
url: ipa_url,
|
142
|
-
ipa_url: ipa_url,
|
143
|
-
build_num: build_num,
|
144
|
-
bundle_id: bundle_id,
|
145
|
-
bundle_version: bundle_version,
|
146
|
-
title: title
|
147
|
-
})
|
148
|
-
|
149
|
-
# Creates html from template
|
150
|
-
if html_template_path && File.exist?(html_template_path)
|
151
|
-
html_template = eth.load_from_path(html_template_path)
|
152
|
-
else
|
153
|
-
html_template = eth.load("s3_html_template")
|
154
|
-
end
|
155
|
-
|
156
|
-
html_render = eth.render(html_template, {
|
157
|
-
url: plist_url,
|
158
|
-
plist_url: plist_url,
|
159
|
-
ipa_url: ipa_url,
|
160
|
-
build_num: build_num,
|
161
|
-
bundle_id: bundle_id,
|
162
|
-
bundle_version: bundle_version,
|
163
|
-
title: title,
|
164
|
-
device_family: device_family
|
165
|
-
})
|
166
|
-
|
167
|
-
# Creates version from template
|
168
|
-
if version_template_path && File.exist?(version_template_path)
|
169
|
-
version_template = eth.load_from_path(version_template_path)
|
170
|
-
else
|
171
|
-
version_template = eth.load("s3_version_template")
|
172
|
-
end
|
173
|
-
version_render = eth.render(version_template, {
|
174
|
-
url: plist_url,
|
175
|
-
plist_url: plist_url,
|
176
|
-
ipa_url: ipa_url,
|
177
|
-
build_num: build_num,
|
178
|
-
bundle_version: bundle_version,
|
179
|
-
full_version: full_version
|
180
|
-
})
|
181
|
-
|
182
|
-
#####################################
|
183
|
-
#
|
184
|
-
# html and plist uploading
|
185
|
-
#
|
186
|
-
#####################################
|
187
|
-
|
188
|
-
plist_url = self.upload_file(bucket, plist_file_name, plist_render, acl)
|
189
|
-
html_url = self.upload_file(bucket, html_file_name, html_render, acl)
|
190
|
-
version_url = self.upload_file(bucket, version_file_name, version_render, acl)
|
191
|
-
|
192
|
-
# Setting action and environment variables
|
193
|
-
Actions.lane_context[SharedValues::S3_PLIST_OUTPUT_PATH] = plist_url
|
194
|
-
ENV[SharedValues::S3_PLIST_OUTPUT_PATH.to_s] = plist_url
|
195
|
-
|
196
|
-
Actions.lane_context[SharedValues::S3_HTML_OUTPUT_PATH] = html_url
|
197
|
-
ENV[SharedValues::S3_HTML_OUTPUT_PATH.to_s] = html_url
|
198
|
-
|
199
|
-
Actions.lane_context[SharedValues::S3_VERSION_OUTPUT_PATH] = version_url
|
200
|
-
ENV[SharedValues::S3_VERSION_OUTPUT_PATH.to_s] = version_url
|
201
|
-
|
202
|
-
UI.success("Successfully uploaded ipa file to '#{Actions.lane_context[SharedValues::S3_IPA_OUTPUT_PATH]}'")
|
203
|
-
|
204
|
-
return true
|
205
|
-
end
|
206
|
-
|
207
|
-
# @return true if loading the AWS SDK from the 'aws-sdk' gem yields the expected v1 API, or false otherwise
|
208
|
-
def self.load_from_original_gem_name
|
209
|
-
begin
|
210
|
-
# We don't use `Actions.verify_gem!` here, because we want to silently be OK with this gem not being
|
211
|
-
# present, in case the user has already migrated to 'aws-sdk-v1' (see #load_from_v1_gem_name)
|
212
|
-
Gem::Specification.find_by_name('aws-sdk')
|
213
|
-
require 'aws-sdk'
|
214
|
-
rescue Gem::LoadError
|
215
|
-
UI.verbose("The 'aws-sdk' gem is not present")
|
216
|
-
return false
|
217
|
-
end
|
218
|
-
|
219
|
-
UI.verbose("The 'aws-sdk' gem is present")
|
220
|
-
true
|
221
|
-
end
|
222
|
-
|
223
|
-
def self.load_from_v1_gem_name
|
224
|
-
Actions.verify_gem!('aws-sdk-v1')
|
225
|
-
require 'aws-sdk-v1'
|
226
|
-
end
|
227
|
-
|
228
|
-
def self.v1_sdk_module_present?
|
229
|
-
begin
|
230
|
-
# Here we'll make sure that the `AWS` module is defined. If it is, the gem is the v1.x API.
|
231
|
-
Object.const_get("AWS")
|
232
|
-
rescue NameError
|
233
|
-
UI.verbose("Couldn't find the needed `AWS` module in the 'aws-sdk' gem")
|
234
|
-
return false
|
235
|
-
end
|
236
|
-
|
237
|
-
UI.verbose("Found the needed `AWS` module in the 'aws-sdk' gem")
|
238
|
-
true
|
239
|
-
end
|
240
|
-
|
241
|
-
def self.s3_client(s3_access_key, s3_secret_access_key, s3_region)
|
242
|
-
# The AWS SDK API changed completely in v2.x. The most stable way to keep using the V1 API is to
|
243
|
-
# require the 'aws-sdk-v1' gem directly. However, for those customers who are using the 'aws-sdk'
|
244
|
-
# gem at v1.x, we don't want to break their setup which currently works.
|
245
|
-
#
|
246
|
-
# Therefore, we will attempt to load the v1 API from the original gem name, but go on to load
|
247
|
-
# from the aws-sdk-v1 gem name if necessary
|
248
|
-
loaded_original_gem = load_from_original_gem_name
|
249
|
-
|
250
|
-
if !loaded_original_gem || !v1_sdk_module_present?
|
251
|
-
load_from_v1_gem_name
|
252
|
-
UI.verbose("Loaded AWS SDK v1.x from the `aws-sdk-v1` gem")
|
253
|
-
else
|
254
|
-
UI.verbose("Loaded AWS SDK v1.x from the `aws-sdk` gem")
|
255
|
-
end
|
256
|
-
|
257
|
-
if s3_region
|
258
|
-
s3_client = AWS::S3.new(
|
259
|
-
access_key_id: s3_access_key,
|
260
|
-
secret_access_key: s3_secret_access_key,
|
261
|
-
region: s3_region
|
262
|
-
)
|
263
|
-
else
|
264
|
-
s3_client = AWS::S3.new(
|
265
|
-
access_key_id: s3_access_key,
|
266
|
-
secret_access_key: s3_secret_access_key
|
267
|
-
)
|
268
|
-
end
|
269
|
-
s3_client
|
270
|
-
end
|
271
|
-
|
272
|
-
def self.upload_file(bucket, file_name, file_data, acl)
|
273
|
-
obj = bucket.objects.create(file_name, file_data, acl: acl)
|
274
|
-
|
275
|
-
# When you enable versioning on a S3 bucket,
|
276
|
-
# writing to an object will create an object version
|
277
|
-
# instead of replacing the existing object.
|
278
|
-
# http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/ObjectVersion.html
|
279
|
-
if obj.kind_of?(AWS::S3::ObjectVersion)
|
280
|
-
obj = obj.object
|
281
|
-
end
|
282
|
-
|
283
|
-
# Return public url
|
284
|
-
obj.public_url.to_s
|
285
|
-
end
|
286
|
-
|
287
|
-
#
|
288
|
-
# NOT a fan of this as this was taken straight from Shenzhen
|
289
|
-
# https://github.com/nomad/shenzhen/blob/986792db5d4d16a80c865a2748ee96ba63644821/lib/shenzhen/plugins/s3.rb#L32
|
290
|
-
#
|
291
|
-
# Need to find a way to not use this copied method
|
292
|
-
#
|
293
|
-
# AGAIN, I am not happy about this right now.
|
294
|
-
# Using this for prototype reasons.
|
295
|
-
#
|
296
|
-
def self.expand_path_with_substitutions_from_ipa_plist(ipa, path)
|
297
|
-
substitutions = path.scan(/\{CFBundle[^}]+\}/)
|
298
|
-
return path if substitutions.empty?
|
299
|
-
info = FastlaneCore::IpaFileAnalyser.fetch_info_plist_file(ipa) or return path
|
300
|
-
|
301
|
-
substitutions.uniq.each do |substitution|
|
302
|
-
key = substitution[1...-1]
|
303
|
-
value = info[key]
|
304
|
-
path.gsub!(Regexp.new(substitution), value) if value
|
305
|
-
end
|
306
|
-
|
307
|
-
return path
|
21
|
+
UI.user_error!("Please use the `aws_s3` plugin instead. Install using `fastlane add_plugin aws_s3`.")
|
308
22
|
end
|
309
23
|
|
310
24
|
def self.description
|
@@ -423,7 +137,7 @@ module Fastlane
|
|
423
137
|
end
|
424
138
|
|
425
139
|
def self.is_supported?(platform)
|
426
|
-
|
140
|
+
false
|
427
141
|
end
|
428
142
|
|
429
143
|
def self.example_code
|
@@ -434,8 +148,8 @@ module Fastlane
|
|
434
148
|
access_key: ENV["S3_ACCESS_KEY"], # Required from user.
|
435
149
|
secret_access_key: ENV["S3_SECRET_ACCESS_KEY"], # Required from user.
|
436
150
|
bucket: ENV["S3_BUCKET"], # Required from user.
|
437
|
-
ipa: "AppName.ipa", # Optional
|
438
|
-
dsym: "AppName.app.dSYM.zip", # Optional
|
151
|
+
ipa: "AppName.ipa", # Optional if you use `ipa` to build
|
152
|
+
dsym: "AppName.app.dSYM.zip", # Optional if you use `ipa` to build
|
439
153
|
path: "v{CFBundleShortVersionString}_b{CFBundleVersion}/", # This is actually the default.
|
440
154
|
upload_metadata: true, # Upload version.json, plist and HTML. Set to false to skip uploading of these files.
|
441
155
|
version_file_name: "app_version.json", # Name of the file to upload to S3. Defaults to "version.json"
|