fastlane 2.142.0 → 2.146.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +80 -80
- data/credentials_manager/lib/credentials_manager/appfile_config.rb +4 -0
- data/deliver/lib/deliver/app_screenshot.rb +1 -0
- data/deliver/lib/deliver/options.rb +30 -1
- data/deliver/lib/deliver/setup.rb +4 -4
- data/fastlane/lib/fastlane/actions/automatic_code_signing.rb +7 -1
- data/fastlane/lib/fastlane/actions/clean_build_artifacts.rb +3 -0
- data/fastlane/lib/fastlane/actions/crashlytics.rb +14 -2
- data/fastlane/lib/fastlane/actions/create_pull_request.rb +7 -1
- data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +10 -4
- data/fastlane/lib/fastlane/actions/docs/frame_screenshots.md +22 -6
- data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +23 -7
- data/fastlane/lib/fastlane/actions/frame_screenshots.rb +2 -1
- data/fastlane/lib/fastlane/actions/get_version_number.rb +1 -1
- data/fastlane/lib/fastlane/actions/pod_lib_lint.rb +7 -1
- data/fastlane/lib/fastlane/actions/s3.rb +3 -289
- data/fastlane/lib/fastlane/actions/setup_ci.rb +1 -1
- data/fastlane/lib/fastlane/actions/setup_jenkins.rb +11 -2
- data/fastlane/lib/fastlane/actions/slather.rb +1 -1
- data/fastlane/lib/fastlane/actions/swiftlint.rb +28 -7
- data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +203 -0
- data/fastlane/lib/fastlane/actions/upload_symbols_to_crashlytics.rb +1 -1
- data/fastlane/lib/fastlane/actions/verify_build.rb +1 -1
- data/fastlane/lib/fastlane/helper/s3_client_helper.rb +61 -0
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/Deliverfile.swift +1 -1
- data/fastlane/swift/Fastlane.swift +147 -8
- data/fastlane/swift/Gymfile.swift +1 -1
- data/fastlane/swift/Matchfile.swift +1 -1
- data/fastlane/swift/MatchfileProtocol.swift +17 -1
- data/fastlane/swift/Precheckfile.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/Snapshotfile.swift +1 -1
- data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +9 -0
- data/fastlane_core/lib/fastlane_core/device_manager.rb +3 -3
- data/fastlane_core/lib/fastlane_core/ipa_file_analyser.rb +1 -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 +29 -41
- 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 +39 -47
- data/frameit/lib/frameit/template_finder.rb +15 -12
- data/gym/lib/gym/generators/package_command_generator.rb +4 -0
- data/gym/lib/gym/generators/package_command_generator_xcode7.rb +5 -0
- data/gym/lib/gym/runner.rb +14 -0
- data/match/lib/match/change_password.rb +1 -1
- data/match/lib/match/encryption.rb +4 -0
- data/match/lib/match/importer.rb +37 -20
- data/match/lib/match/module.rb +1 -1
- data/match/lib/match/nuke.rb +5 -1
- data/match/lib/match/options.rb +18 -0
- data/match/lib/match/runner.rb +4 -0
- data/match/lib/match/setup.rb +1 -1
- data/match/lib/match/storage.rb +4 -0
- data/match/lib/match/storage/s3_storage.rb +167 -0
- data/pilot/lib/pilot/build_manager.rb +15 -4
- data/pilot/lib/pilot/options.rb +8 -0
- data/produce/lib/produce/developer_center.rb +11 -2
- data/produce/lib/produce/itunes_connect.rb +11 -3
- data/produce/lib/produce/options.rb +12 -0
- data/scan/lib/scan/options.rb +5 -0
- data/scan/lib/scan/test_command_generator.rb +5 -1
- data/screengrab/lib/screengrab/runner.rb +12 -4
- data/snapshot/lib/snapshot/reports_generator.rb +4 -0
- data/spaceship/lib/spaceship/connect_api/models/app.rb +11 -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 +23 -0
- data/spaceship/lib/spaceship/portal/app_service.rb +2 -2
- data/spaceship/lib/spaceship/portal/portal_client.rb +13 -0
- data/spaceship/lib/spaceship/tunes/app_version.rb +6 -1
- data/spaceship/lib/spaceship/tunes/application.rb +2 -1
- data/spaceship/lib/spaceship/tunes/tunes_client.rb +2 -2
- data/spaceship/lib/spaceship/two_step_or_factor_client.rb +52 -16
- data/supply/lib/supply/client.rb +4 -4
- data/supply/lib/supply/setup.rb +5 -3
- metadata +34 -17
- data/gym/lib/gym/.code_signing_mapping.rb.swp +0 -0
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'deliver/app_screenshot'
|
2
|
-
|
3
2
|
require_relative 'module'
|
4
3
|
require_relative 'device_types'
|
5
4
|
require_relative 'frame_downloader'
|
@@ -11,32 +10,36 @@ module Frameit
|
|
11
10
|
def self.get_template(screenshot)
|
12
11
|
return nil if screenshot.mac?
|
13
12
|
|
14
|
-
filename =
|
15
|
-
|
13
|
+
filename = create_file_name(screenshot.device_name, screenshot.color.nil? ? screenshot.default_color : screenshot.color)
|
16
14
|
templates = Dir["#{FrameDownloader.templates_path}/#{filename}.{png,jpg}"] # ~/.frameit folder
|
17
15
|
|
18
16
|
UI.verbose("Looking for #{filename} and found #{templates.count} template(s)")
|
19
17
|
|
18
|
+
return filename if Helper.test?
|
19
|
+
if templates.count == 0 && !screenshot.color.nil? && screenshot.color != screenshot.default_color
|
20
|
+
filename = create_file_name(screenshot.device_name, screenshot.default_color)
|
21
|
+
UI.important("Unfortunately device type '#{screenshot.device_name}' is not available in #{screenshot.color}, falling back to " + (screenshot.default_color.nil? ? "default" : screenshot.default_color) + "...")
|
22
|
+
templates = Dir["#{FrameDownloader.templates_path}/#{filename}.{png,jpg}"] # ~/.frameit folder
|
23
|
+
UI.verbose("Looking for #{filename} and found #{templates.count} template(s)")
|
24
|
+
end
|
25
|
+
|
20
26
|
if templates.count == 0
|
21
|
-
if screenshot.
|
27
|
+
if screenshot.deliver_screen_id == Deliver::AppScreenshot::ScreenSize::IOS_35
|
22
28
|
UI.important("Unfortunately 3.5\" device frames were discontinued. Skipping screen '#{screenshot.path}'")
|
23
29
|
UI.error("Looked for: '#{filename}.png'")
|
24
|
-
elsif screenshot.color == Frameit::Color::ROSE_GOLD || screenshot.color == Frameit::Color::GOLD
|
25
|
-
# Unfortunately not every device type is available in rose gold or gold
|
26
|
-
# This is why we can't have nice things #yatusabes
|
27
|
-
# fallback to a white iPhone, which looks similar
|
28
|
-
UI.important("Unfortunately device type '#{screenshot.device_name}' is not available in #{screenshot.color}, falling back to silver...")
|
29
|
-
screenshot.color = Frameit::Color::SILVER
|
30
|
-
return self.get_template(screenshot)
|
31
30
|
else
|
32
31
|
UI.error("Couldn't find template for screenshot type '#{filename}'")
|
33
32
|
UI.error("Please run `fastlane frameit download_frames` to download the latest frames")
|
34
33
|
end
|
35
|
-
return filename if Helper.test?
|
36
34
|
return nil
|
37
35
|
else
|
38
36
|
return templates.first.tr(" ", "\ ")
|
39
37
|
end
|
40
38
|
end
|
39
|
+
|
40
|
+
def self.create_file_name(device_name, color)
|
41
|
+
return "#{device_name} #{color}" unless color.nil?
|
42
|
+
return device_name
|
43
|
+
end
|
41
44
|
end
|
42
45
|
end
|
@@ -49,6 +49,10 @@ module Gym
|
|
49
49
|
generator.apps_path
|
50
50
|
end
|
51
51
|
|
52
|
+
def asset_packs_path
|
53
|
+
generator.asset_packs_path
|
54
|
+
end
|
55
|
+
|
52
56
|
# The generator we need to use for the currently used Xcode version
|
53
57
|
# Since we dropped Xcode 6 support, it's just this class, but maybe we'll have
|
54
58
|
# new classes in the future
|
@@ -136,6 +136,11 @@ module Gym
|
|
136
136
|
Gym.cache[:apps_path] ||= File.join(temporary_output_path, "Apps")
|
137
137
|
end
|
138
138
|
|
139
|
+
# The path to the Apps folder
|
140
|
+
def asset_packs_path
|
141
|
+
Gym.cache[:asset_packs_path] ||= File.join(temporary_output_path, "OnDemandResources")
|
142
|
+
end
|
143
|
+
|
139
144
|
private
|
140
145
|
|
141
146
|
def normalize_export_options(hash)
|
data/gym/lib/gym/runner.rb
CHANGED
@@ -39,6 +39,7 @@ module Gym
|
|
39
39
|
move_app_thinning
|
40
40
|
move_app_thinning_size_report
|
41
41
|
move_apps_folder
|
42
|
+
move_asset_packs
|
42
43
|
elsif is_mac
|
43
44
|
path = File.expand_path(Gym.config[:output_directory])
|
44
45
|
compress_and_move_dsym
|
@@ -325,6 +326,19 @@ module Gym
|
|
325
326
|
end
|
326
327
|
end
|
327
328
|
|
329
|
+
# Move Asset Packs folder to the output directory
|
330
|
+
# @return (String) The path to the resulting Asset Packs (aka OnDemandResources) folder
|
331
|
+
def move_asset_packs
|
332
|
+
if Dir.exist?(PackageCommandGenerator.asset_packs_path)
|
333
|
+
FileUtils.mv(PackageCommandGenerator.asset_packs_path, File.expand_path(Gym.config[:output_directory]), force: true)
|
334
|
+
asset_packs_path = File.join(File.expand_path(Gym.config[:output_directory]), File.basename(PackageCommandGenerator.asset_packs_path))
|
335
|
+
|
336
|
+
UI.success("Successfully exported Asset Pack folder:")
|
337
|
+
UI.message(asset_packs_path)
|
338
|
+
asset_packs_path
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
328
342
|
def find_archive_path
|
329
343
|
Dir.glob(File.join(BuildCommandGenerator.build_path, "*.ipa")).last
|
330
344
|
end
|
@@ -45,7 +45,7 @@ module Match
|
|
45
45
|
end
|
46
46
|
|
47
47
|
# This method is called from both here, and from `openssl.rb`
|
48
|
-
def self.ask_password(message: "Passphrase for
|
48
|
+
def self.ask_password(message: "Passphrase for Match storage: ", confirm: nil)
|
49
49
|
ensure_ui_interactive
|
50
50
|
loop do
|
51
51
|
password = UI.password(message)
|
data/match/lib/match/importer.rb
CHANGED
@@ -2,23 +2,16 @@ require_relative 'spaceship_ensure'
|
|
2
2
|
require_relative 'encryption'
|
3
3
|
require_relative 'storage'
|
4
4
|
require_relative 'module'
|
5
|
+
require 'fastlane_core/provisioning_profile'
|
5
6
|
require 'fileutils'
|
6
7
|
|
7
8
|
module Match
|
8
9
|
class Importer
|
9
|
-
def import_cert(params, cert_path: nil, p12_path: nil)
|
10
|
-
# Get and verify cert and
|
11
|
-
cert_path
|
12
|
-
p12_path
|
13
|
-
|
14
|
-
cert_path = File.absolute_path(cert_path)
|
15
|
-
p12_path = File.absolute_path(p12_path)
|
16
|
-
|
17
|
-
UI.user_error!("Certificate does not exist at path: #{cert_path}") unless File.exist?(cert_path)
|
18
|
-
UI.user_error!("Private key does not exist at path: #{p12_path}") unless File.exist?(p12_path)
|
19
|
-
|
20
|
-
# Base64 encode contents to find match from API to find a cert ID
|
21
|
-
cert_contents_base_64 = Base64.strict_encode64(File.open(cert_path).read)
|
10
|
+
def import_cert(params, cert_path: nil, p12_path: nil, profile_path: nil)
|
11
|
+
# Get and verify cert, p12 and profiles path
|
12
|
+
cert_path = ensure_valid_file_path(cert_path, "Certificate", ".cer")
|
13
|
+
p12_path = ensure_valid_file_path(p12_path, "Private key", ".p12")
|
14
|
+
profile_path = ensure_valid_file_path(profile_path, "Provisioning profile", ".mobileprovision or .provisionprofile", optional: true)
|
22
15
|
|
23
16
|
# Storage
|
24
17
|
storage = Storage.for_mode(params[:storage_mode], {
|
@@ -54,20 +47,25 @@ module Match
|
|
54
47
|
|
55
48
|
case cert_type
|
56
49
|
when :development
|
57
|
-
certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DEVELOPMENT
|
50
|
+
certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DEVELOPMENT + "," + Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPMENT
|
58
51
|
when :distribution, :enterprise
|
59
|
-
certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION
|
52
|
+
certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::IOS_DISTRIBUTION + "," + Spaceship::ConnectAPI::Certificate::CertificateType::DISTRIBUTION
|
53
|
+
when :developer_id_application
|
54
|
+
certificate_type = Spaceship::ConnectAPI::Certificate::CertificateType::DEVELOPER_ID_APPLICATION
|
60
55
|
else
|
61
56
|
UI.user_error!("Cert type '#{cert_type}' is not supported")
|
62
57
|
end
|
63
58
|
|
64
|
-
|
59
|
+
output_dir_certs = File.join(storage.prefixed_working_directory, "certs", cert_type.to_s)
|
60
|
+
output_dir_profiles = File.join(storage.prefixed_working_directory, "profiles", cert_type.to_s)
|
65
61
|
|
66
62
|
# Need to get the cert id by comparing base64 encoded cert content with certificate content from the API responses
|
67
63
|
Spaceship::Portal.login(params[:username])
|
68
64
|
Spaceship::Portal.select_team(team_id: params[:team_id], team_name: params[:team_name])
|
69
65
|
certs = Spaceship::ConnectAPI::Certificate.all(filter: { certificateType: certificate_type })
|
70
66
|
|
67
|
+
# Base64 encode contents to find match from API to find a cert ID
|
68
|
+
cert_contents_base_64 = Base64.strict_encode64(File.binread(cert_path))
|
71
69
|
matching_cert = certs.find do |cert|
|
72
70
|
cert.certificate_content == cert_contents_base_64
|
73
71
|
end
|
@@ -75,18 +73,37 @@ module Match
|
|
75
73
|
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
74
|
|
77
75
|
# Make dir if doesn't exist
|
78
|
-
FileUtils.mkdir_p(
|
79
|
-
dest_cert_path = File.join(
|
80
|
-
dest_p12_path = File.join(
|
76
|
+
FileUtils.mkdir_p(output_dir_certs)
|
77
|
+
dest_cert_path = File.join(output_dir_certs, "#{matching_cert.id}.cer")
|
78
|
+
dest_p12_path = File.join(output_dir_certs, "#{matching_cert.id}.p12")
|
79
|
+
|
80
|
+
files_to_commit = [dest_cert_path, dest_p12_path]
|
81
81
|
|
82
82
|
# Copy files
|
83
83
|
IO.copy_stream(cert_path, dest_cert_path)
|
84
84
|
IO.copy_stream(p12_path, dest_p12_path)
|
85
|
-
|
85
|
+
unless profile_path.nil?
|
86
|
+
FileUtils.mkdir_p(output_dir_profiles)
|
87
|
+
bundle_id = FastlaneCore::ProvisioningProfile.bundle_id(profile_path)
|
88
|
+
profile_extension = FastlaneCore::ProvisioningProfile.profile_extension(profile_path)
|
89
|
+
dest_profile_path = File.join(output_dir_profiles, "#{cert_type.to_s.capitalize}_#{bundle_id}#{profile_extension}")
|
90
|
+
files_to_commit.push(dest_profile_path)
|
91
|
+
IO.copy_stream(profile_path, dest_profile_path)
|
92
|
+
end
|
86
93
|
|
87
94
|
# Encrypt and commit
|
88
95
|
encryption.encrypt_files if encryption
|
89
96
|
storage.save_changes!(files_to_commit: files_to_commit)
|
90
97
|
end
|
98
|
+
|
99
|
+
def ensure_valid_file_path(file_path, file_description, file_extension, optional: false)
|
100
|
+
optional_file_message = optional ? " or leave empty to skip this file" : ""
|
101
|
+
file_path ||= UI.input("#{file_description} (#{file_extension}) path#{optional_file_message}:")
|
102
|
+
|
103
|
+
file_path = File.absolute_path(file_path) unless file_path == ""
|
104
|
+
file_path = File.exist?(file_path) ? file_path : nil
|
105
|
+
UI.user_error!("#{file_description} does not exist at path: #{file_path}") unless !file_path.nil? || optional
|
106
|
+
file_path
|
107
|
+
end
|
91
108
|
end
|
92
109
|
end
|
data/match/lib/match/module.rb
CHANGED
data/match/lib/match/nuke.rb
CHANGED
@@ -37,7 +37,11 @@ module Match
|
|
37
37
|
clone_branch_directly: params[:clone_branch_directly],
|
38
38
|
google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
|
39
39
|
google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
|
40
|
-
google_cloud_project_id: params[:google_cloud_project_id].to_s
|
40
|
+
google_cloud_project_id: params[:google_cloud_project_id].to_s,
|
41
|
+
s3_region: params[:s3_region].to_s,
|
42
|
+
s3_access_key: params[:s3_access_key].to_s,
|
43
|
+
s3_secret_access_key: params[:s3_secret_access_key].to_s,
|
44
|
+
s3_bucket: params[:s3_bucket].to_s
|
41
45
|
})
|
42
46
|
self.storage.download
|
43
47
|
|
data/match/lib/match/options.rb
CHANGED
@@ -159,6 +159,24 @@ module Match
|
|
159
159
|
description: "ID of the Google Cloud project to use for authentication",
|
160
160
|
optional: true),
|
161
161
|
|
162
|
+
# Storage: S3
|
163
|
+
FastlaneCore::ConfigItem.new(key: :s3_region,
|
164
|
+
env_name: "MATCH_S3_REGION",
|
165
|
+
description: "Name of the S3 region",
|
166
|
+
optional: true),
|
167
|
+
FastlaneCore::ConfigItem.new(key: :s3_access_key,
|
168
|
+
env_name: "MATCH_S3_ACCESS_KEY",
|
169
|
+
description: "S3 access key",
|
170
|
+
optional: true),
|
171
|
+
FastlaneCore::ConfigItem.new(key: :s3_secret_access_key,
|
172
|
+
env_name: "MATCH_S3_SECRET_ACCESS_KEY",
|
173
|
+
description: "S3 secret access key",
|
174
|
+
optional: true),
|
175
|
+
FastlaneCore::ConfigItem.new(key: :s3_bucket,
|
176
|
+
env_name: "MATCH_S3_BUCKET",
|
177
|
+
description: "Name of the S3 bucket",
|
178
|
+
optional: true),
|
179
|
+
|
162
180
|
# Keychain
|
163
181
|
FastlaneCore::ConfigItem.new(key: :keychain_name,
|
164
182
|
short_option: "-s",
|
data/match/lib/match/runner.rb
CHANGED
@@ -46,6 +46,10 @@ module Match
|
|
46
46
|
google_cloud_bucket_name: params[:google_cloud_bucket_name].to_s,
|
47
47
|
google_cloud_keys_file: params[:google_cloud_keys_file].to_s,
|
48
48
|
google_cloud_project_id: params[:google_cloud_project_id].to_s,
|
49
|
+
s3_region: params[:s3_region].to_s,
|
50
|
+
s3_access_key: params[:s3_access_key].to_s,
|
51
|
+
s3_secret_access_key: params[:s3_secret_access_key].to_s,
|
52
|
+
s3_bucket: params[:s3_bucket].to_s,
|
49
53
|
readonly: params[:readonly],
|
50
54
|
username: params[:readonly] ? nil : params[:username], # only pass username if not readonly
|
51
55
|
team_id: params[:team_id],
|
data/match/lib/match/setup.rb
CHANGED
data/match/lib/match/storage.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'storage/interface'
|
2
2
|
require_relative 'storage/git_storage'
|
3
3
|
require_relative 'storage/google_cloud_storage'
|
4
|
+
require_relative 'storage/s3_storage'
|
4
5
|
|
5
6
|
module Match
|
6
7
|
module Storage
|
@@ -12,6 +13,9 @@ module Match
|
|
12
13
|
},
|
13
14
|
"google_cloud" => lambda { |params|
|
14
15
|
return Storage::GoogleCloudStorage.configure(params)
|
16
|
+
},
|
17
|
+
"s3" => lambda { |params|
|
18
|
+
return Storage::S3Storage.configure(params)
|
15
19
|
}
|
16
20
|
}
|
17
21
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'fastlane_core/command_executor'
|
2
|
+
require 'fastlane_core/configuration/configuration'
|
3
|
+
require 'fastlane/helper/s3_client_helper'
|
4
|
+
|
5
|
+
require_relative '../options'
|
6
|
+
require_relative '../module'
|
7
|
+
require_relative '../spaceship_ensure'
|
8
|
+
require_relative './interface'
|
9
|
+
|
10
|
+
module Match
|
11
|
+
module Storage
|
12
|
+
# Store the code signing identities on AWS S3
|
13
|
+
class S3Storage < Interface
|
14
|
+
attr_reader :s3_bucket
|
15
|
+
attr_reader :s3_region
|
16
|
+
attr_reader :s3_client
|
17
|
+
attr_reader :readonly
|
18
|
+
attr_reader :username
|
19
|
+
attr_reader :team_id
|
20
|
+
attr_reader :team_name
|
21
|
+
|
22
|
+
def self.configure(params)
|
23
|
+
s3_region = params[:s3_region]
|
24
|
+
s3_access_key = params[:s3_access_key]
|
25
|
+
s3_secret_access_key = params[:s3_secret_access_key]
|
26
|
+
s3_bucket = params[:s3_bucket]
|
27
|
+
|
28
|
+
if params[:git_url].to_s.length > 0
|
29
|
+
UI.important("Looks like you still define a `git_url` somewhere, even though")
|
30
|
+
UI.important("you use S3 Storage. You can remove the `git_url`")
|
31
|
+
UI.important("from your Matchfile and Fastfile")
|
32
|
+
UI.message("The above is just a warning, fastlane will continue as usual now...")
|
33
|
+
end
|
34
|
+
|
35
|
+
return self.new(
|
36
|
+
s3_region: s3_region,
|
37
|
+
s3_access_key: s3_access_key,
|
38
|
+
s3_secret_access_key: s3_secret_access_key,
|
39
|
+
s3_bucket: s3_bucket,
|
40
|
+
readonly: params[:readonly],
|
41
|
+
username: params[:username],
|
42
|
+
team_id: params[:team_id],
|
43
|
+
team_name: params[:team_name]
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(s3_region: nil,
|
48
|
+
s3_access_key: nil,
|
49
|
+
s3_secret_access_key: nil,
|
50
|
+
s3_bucket: nil,
|
51
|
+
readonly: nil,
|
52
|
+
username: nil,
|
53
|
+
team_id: nil,
|
54
|
+
team_name: nil)
|
55
|
+
@s3_bucket = s3_bucket
|
56
|
+
@s3_region = s3_region
|
57
|
+
@s3_client = Fastlane::Helper::S3ClientHelper.new(access_key: s3_access_key, secret_access_key: s3_secret_access_key, region: s3_region)
|
58
|
+
@readonly = readonly
|
59
|
+
@username = username
|
60
|
+
@team_id = team_id
|
61
|
+
@team_name = team_name
|
62
|
+
end
|
63
|
+
|
64
|
+
# To make debugging easier, we have a custom exception here
|
65
|
+
def prefixed_working_directory
|
66
|
+
# We fall back to "*", which means certificates and profiles
|
67
|
+
# from all teams that use this bucket would be installed. This is not ideal, but
|
68
|
+
# unless the user provides a `team_id`, we can't know which one to use
|
69
|
+
# This only happens if `readonly` is activated, and no `team_id` was provided
|
70
|
+
@_folder_prefix ||= currently_used_team_id
|
71
|
+
if @_folder_prefix.nil?
|
72
|
+
# We use a `@_folder_prefix` variable, to keep state between multiple calls of this
|
73
|
+
# method, as the value won't change. This way the warning is only printed once
|
74
|
+
UI.important("Looks like you run `match` in `readonly` mode, and didn't provide a `team_id`. This will still work, however it is recommended to provide a `team_id` in your Appfile or Matchfile")
|
75
|
+
@_folder_prefix = "*"
|
76
|
+
end
|
77
|
+
return File.join(working_directory, @_folder_prefix)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Call this method for the initial clone/download of the
|
81
|
+
# user's certificates & profiles
|
82
|
+
# As part of this method, the `self.working_directory` attribute
|
83
|
+
# will be set
|
84
|
+
def download
|
85
|
+
# Check if we already have a functional working_directory
|
86
|
+
return if @working_directory && Dir.exist?(@working_directory)
|
87
|
+
|
88
|
+
# No existing working directory, creating a new one now
|
89
|
+
self.working_directory = Dir.mktmpdir
|
90
|
+
|
91
|
+
s3_client.find_bucket!(s3_bucket).objects.each do |object|
|
92
|
+
file_path = object.key # :team_id/path/to/file
|
93
|
+
download_path = File.join(self.working_directory, file_path)
|
94
|
+
|
95
|
+
FileUtils.mkdir_p(File.expand_path("..", download_path))
|
96
|
+
UI.verbose("Downloading file from S3 '#{file_path}' on bucket #{self.s3_bucket}")
|
97
|
+
|
98
|
+
object.download_file(download_path)
|
99
|
+
end
|
100
|
+
UI.verbose("Successfully downloaded files from S3 to #{self.working_directory}")
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a short string describing + identifing the current
|
104
|
+
# storage backend. This will be printed when nuking a storage
|
105
|
+
def human_readable_description
|
106
|
+
return "S3 Bucket [#{s3_bucket}] on region #{s3_region}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def upload_files(files_to_upload: [], custom_message: nil)
|
110
|
+
# `files_to_upload` is an array of files that need to be uploaded to S3
|
111
|
+
# Those doesn't mean they're new, it might just be they're changed
|
112
|
+
# Either way, we'll upload them using the same technique
|
113
|
+
|
114
|
+
files_to_upload.each do |file_name|
|
115
|
+
# Go from
|
116
|
+
# "/var/folders/px/bz2kts9n69g8crgv4jpjh6b40000gn/T/d20181026-96528-1av4gge/profiles/development/Development_me.mobileprovision"
|
117
|
+
# to
|
118
|
+
# "profiles/development/Development_me.mobileprovision"
|
119
|
+
#
|
120
|
+
|
121
|
+
target_path = sanitize_file_name(file_name)
|
122
|
+
UI.verbose("Uploading '#{target_path}' to S3 Storage...")
|
123
|
+
|
124
|
+
body = File.read(file_name)
|
125
|
+
acl = 'private'
|
126
|
+
s3_url = s3_client.upload_file(s3_bucket, target_path, body, acl)
|
127
|
+
UI.verbose("Uploaded '#{s3_url}' to S3 Storage.")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def delete_files(files_to_delete: [], custom_message: nil)
|
132
|
+
files_to_delete.each do |file_name|
|
133
|
+
target_path = sanitize_file_name(file_name)
|
134
|
+
s3_client.delete_file(s3_bucket, target_path)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def skip_docs
|
139
|
+
false
|
140
|
+
end
|
141
|
+
|
142
|
+
# Implement this for the `fastlane match init` command
|
143
|
+
# This method must return the content of the Matchfile
|
144
|
+
# that should be generated
|
145
|
+
def generate_matchfile_content(template: nil)
|
146
|
+
return "s3_bucket(\"#{self.s3_bucket}\")"
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def sanitize_file_name(file_name)
|
152
|
+
file_name.gsub(self.working_directory + "/", "")
|
153
|
+
end
|
154
|
+
|
155
|
+
def currently_used_team_id
|
156
|
+
if self.readonly
|
157
|
+
# In readonly mode, we still want to see if the user provided a team_id
|
158
|
+
# see `prefixed_working_directory` comments for more details
|
159
|
+
return self.team_id
|
160
|
+
else
|
161
|
+
spaceship = SpaceshipEnsure.new(self.username, self.team_id, self.team_name)
|
162
|
+
return spaceship.team_id
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|