fastlane 2.4.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/fastlane +10 -0
- data/credentials_manager/lib/credentials_manager/account_manager.rb +33 -10
- data/deliver/lib/deliver/options.rb +1 -0
- data/deliver/lib/deliver/upload_metadata.rb +9 -0
- data/fastlane/lib/fastlane/commands_generator.rb +1 -1
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane_core/lib/fastlane_core/device_manager.rb +17 -8
- data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +34 -16
- data/fastlane_core/lib/fastlane_core/update_checker/update_checker.rb +16 -0
- data/spaceship/README.md +15 -1
- data/supply/lib/supply/client.rb +15 -0
- data/supply/lib/supply/options.rb +23 -1
- data/supply/lib/supply/uploader.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acbb31b6b342da9f2a15a22936808c0c93d68762
|
4
|
+
data.tar.gz: 21bd81ba701a4b11a2bf71d8cc8b41a20f4be78c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43b2ba4ba3613e9324522c76a6a081639d4ddb46d1a00d95c01c2a809e2d84c43525d09533102e7197fd4a4dedb288f40c1a90dcc5393def55ab3a15619d1317
|
7
|
+
data.tar.gz: e372a9675ae45e33aa649f620116ee257313679d692673ecc073f88fa134fdb382a787a4e430065a3a2d05847851532e2602b22d3db587c34795703ffb62e901
|
data/bin/fastlane
CHANGED
@@ -2,4 +2,14 @@
|
|
2
2
|
$LOAD_PATH.push File.expand_path("../../lib", __FILE__)
|
3
3
|
|
4
4
|
require "fastlane/cli_tools_distributor"
|
5
|
+
|
6
|
+
if Fastlane::CLIToolsDistributor.running_version_command?
|
7
|
+
# This will print out the fastlane binary path right above the
|
8
|
+
# version number. Very often, users are not aware they have
|
9
|
+
# e.g. bundled fastlane installed
|
10
|
+
puts "fastlane installation at path:"
|
11
|
+
puts File.expand_path(__FILE__)
|
12
|
+
puts "-----------------------------"
|
13
|
+
end
|
14
|
+
|
5
15
|
Fastlane::CLIToolsDistributor.take_off
|
@@ -3,19 +3,31 @@ require 'highline/import' # to hide the entered password
|
|
3
3
|
|
4
4
|
module CredentialsManager
|
5
5
|
class AccountManager
|
6
|
+
DEFAULT_PREFIX = "deliver"
|
6
7
|
# @param prefix [String] Very optional, is used for the
|
7
8
|
# iTunes Transporter which uses application specofic passwords
|
8
|
-
|
9
|
-
|
9
|
+
# @param note [String] An optional note that will be shown next
|
10
|
+
# to the password and username prompt
|
11
|
+
def initialize(user: nil, password: nil, prefix: nil, note: nil)
|
12
|
+
@prefix = prefix || DEFAULT_PREFIX
|
10
13
|
|
11
14
|
@user = user
|
12
15
|
@password = password
|
16
|
+
@note = note
|
17
|
+
end
|
18
|
+
|
19
|
+
# Is the that default prefix "deliver"
|
20
|
+
def default_prefix?
|
21
|
+
@prefix == DEFAULT_PREFIX
|
13
22
|
end
|
14
23
|
|
15
24
|
def user
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
if default_prefix?
|
26
|
+
@user ||= ENV["FASTLANE_USER"]
|
27
|
+
@user ||= ENV["DELIVER_USER"]
|
28
|
+
@user ||= AppfileConfig.try_fetch_value(:apple_id)
|
29
|
+
end
|
30
|
+
|
19
31
|
ask_for_login if @user.to_s.length == 0
|
20
32
|
return @user
|
21
33
|
end
|
@@ -25,7 +37,10 @@ module CredentialsManager
|
|
25
37
|
end
|
26
38
|
|
27
39
|
def password(ask_if_missing: true)
|
28
|
-
|
40
|
+
if default_prefix?
|
41
|
+
@password ||= fetch_password_from_env
|
42
|
+
end
|
43
|
+
|
29
44
|
unless @password
|
30
45
|
item = Security::InternetPassword.find(server: server_name)
|
31
46
|
@password ||= item.password if item
|
@@ -87,20 +102,28 @@ module CredentialsManager
|
|
87
102
|
def ask_for_login
|
88
103
|
puts "-------------------------------------------------------------------------------------".green
|
89
104
|
puts "The login information you enter will be stored in your Mac OS Keychain".green
|
90
|
-
|
91
|
-
|
105
|
+
if default_prefix?
|
106
|
+
# We don't want to show this message, if we ask for the application specific password
|
107
|
+
# which has a different prefix
|
108
|
+
puts "You can also pass the password using the `FASTLANE_PASSWORD` environment variable".green
|
109
|
+
puts "More information about it on GitHub: https://github.com/fastlane/fastlane/tree/master/credentials_manager".green
|
110
|
+
end
|
92
111
|
puts "-------------------------------------------------------------------------------------".green
|
93
112
|
|
94
113
|
if @user.to_s.length == 0
|
95
114
|
raise "Missing username, and running in non-interactive shell" if $stdout.isatty == false
|
96
|
-
|
115
|
+
prompt_text = "Username"
|
116
|
+
prompt_text += " (#{@note})" if @note
|
117
|
+
prompt_text += ": "
|
118
|
+
@user = ask(prompt_text) while @user.to_s.length == 0
|
97
119
|
# we return here, as only the username was asked for now, we'll get called for the pw again anyway
|
98
120
|
return
|
99
121
|
end
|
100
122
|
|
101
123
|
while @password.to_s.length == 0
|
102
124
|
raise "Missing password for user #{@user}, and running in non-interactive shell" if $stdout.isatty == false
|
103
|
-
|
125
|
+
note = @note + " " if @note
|
126
|
+
@password = ask("Password (#{note}for #{@user}): ") { |q| q.echo = "*" }
|
104
127
|
end
|
105
128
|
|
106
129
|
return true if ENV["FASTLANE_DONT_STORE_PASSWORD"]
|
@@ -27,6 +27,7 @@ module Deliver
|
|
27
27
|
FastlaneCore::ConfigItem.new(key: :edit_live,
|
28
28
|
short_option: "-o",
|
29
29
|
optional: true,
|
30
|
+
default_value: false,
|
30
31
|
env_name: "DELIVER_EDIT_LIVE",
|
31
32
|
description: "Modify live metadata, this option disables ipa upload and screenshot upload",
|
32
33
|
is_string: false),
|
@@ -37,6 +37,15 @@ module Deliver
|
|
37
37
|
v = app.live_version(platform: options[:platform])
|
38
38
|
localised_options = LOCALISED_LIVE_VALUES
|
39
39
|
non_localised_options = NON_LOCALISED_LIVE_VALUES
|
40
|
+
|
41
|
+
if v.nil?
|
42
|
+
UI.message("Couldn't find live version, editing the current version on iTunes Connect instead")
|
43
|
+
v = app.edit_version(platform: options[:platform])
|
44
|
+
# we don't want to update the localised_options and non_localised_options
|
45
|
+
# as we also check for `options[:edit_live]` at other areas in the code
|
46
|
+
# by not touching those 2 variables, deliver is more consistent with what the option says
|
47
|
+
# in the documentation
|
48
|
+
end
|
40
49
|
else
|
41
50
|
v = app.edit_version(platform: options[:platform])
|
42
51
|
localised_options = (LOCALISED_VERSION_VALUES + LOCALISED_APP_VALUES)
|
@@ -28,7 +28,7 @@ module Fastlane
|
|
28
28
|
FastlaneCore::UpdateChecker.start_looking_for_update('fastlane')
|
29
29
|
Fastlane.load_actions
|
30
30
|
# do not use "include" as it may be some where in the commandline where "env" is required, therefore explicit index->0
|
31
|
-
unless ARGV[0] == "env"
|
31
|
+
unless ARGV[0] == "env" || CLIToolsDistributor.running_version_command?
|
32
32
|
# *after* loading the plugins
|
33
33
|
Fastlane.plugin_manager.load_plugins
|
34
34
|
Fastlane::PluginUpdateManager.start_looking_for_updates
|
@@ -71,14 +71,8 @@ module FastlaneCore
|
|
71
71
|
|
72
72
|
device_uuids = []
|
73
73
|
result = Plist.parse_xml(usb_devices_output)
|
74
|
-
|
75
|
-
|
76
|
-
is_supported_device = device_types.any? { |device_type| usb_device['_name'] == device_type }
|
77
|
-
if is_supported_device && usb_device['serial_num'].length == 40
|
78
|
-
device_uuids.push(usb_device['serial_num'])
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
74
|
+
|
75
|
+
discover_devices(result[0], device_types, device_uuids) if result[0]
|
82
76
|
|
83
77
|
if device_uuids.count > 0 # instruments takes a little while to return so skip it if we have no devices
|
84
78
|
instruments_devices_output = ''
|
@@ -100,6 +94,21 @@ module FastlaneCore
|
|
100
94
|
return devices
|
101
95
|
end
|
102
96
|
|
97
|
+
# Recursively handle all USB items, discovering devices that match the
|
98
|
+
# desired types.
|
99
|
+
def discover_devices(usb_item, device_types, discovered_device_udids)
|
100
|
+
(usb_item['_items'] || []).each do |child_item|
|
101
|
+
discover_devices(child_item, device_types, discovered_device_udids)
|
102
|
+
end
|
103
|
+
|
104
|
+
is_supported_device = device_types.any? { |device_type| usb_item['_name'] == device_type }
|
105
|
+
has_serial_number = (usb_item['serial_num'] || '').length == 40
|
106
|
+
|
107
|
+
if is_supported_device && has_serial_number
|
108
|
+
discovered_device_udids << usb_item['serial_num']
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
103
112
|
# The code below works from Xcode 7 on
|
104
113
|
# def all
|
105
114
|
# UI.verbose("Fetching available devices")
|
@@ -294,20 +294,9 @@ module FastlaneCore
|
|
294
294
|
use_shell_script ||= Helper.is_mac? && Helper.xcode_version.start_with?('6.')
|
295
295
|
use_shell_script ||= Feature.enabled?('FASTLANE_ITUNES_TRANSPORTER_USE_SHELL_SCRIPT')
|
296
296
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
@user = data.user
|
301
|
-
@password ||= data.password(ask_if_missing: false)
|
302
|
-
|
303
|
-
if @password.to_s.length == 0
|
304
|
-
# No specific password found, just using the iTC/Dev Portal one
|
305
|
-
# default to the given password here
|
306
|
-
data = CredentialsManager::AccountManager.new(user: user,
|
307
|
-
password: password)
|
308
|
-
@user = data.user
|
309
|
-
@password ||= data.password
|
310
|
-
end
|
297
|
+
@user = user
|
298
|
+
@password = password || load_password_for_transporter
|
299
|
+
|
311
300
|
@transporter_executor = use_shell_script ? ShellScriptTransporterExecutor.new : JavaTransporterExecutor.new
|
312
301
|
@provider_short_name = provider_short_name
|
313
302
|
end
|
@@ -383,10 +372,36 @@ module FastlaneCore
|
|
383
372
|
|
384
373
|
private
|
385
374
|
|
375
|
+
TWO_FACTOR_ENV_VARIABLE = "FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD"
|
376
|
+
|
377
|
+
# Returns the password to be used with the transporter
|
378
|
+
def load_password_for_transporter
|
379
|
+
# 3 different sources for the password
|
380
|
+
# 1) ENV variable for application specific password
|
381
|
+
return ENV[TWO_FACTOR_ENV_VARIABLE] if ENV[TWO_FACTOR_ENV_VARIABLE].to_s.length > 0
|
382
|
+
# 2) TWO_STEP_HOST_PREFIX from keychain
|
383
|
+
account_manager = CredentialsManager::AccountManager.new(user: @user,
|
384
|
+
prefix: TWO_STEP_HOST_PREFIX,
|
385
|
+
note: "application-specific")
|
386
|
+
password = account_manager.password(ask_if_missing: false)
|
387
|
+
return password if password.to_s.length > 0
|
388
|
+
# 3) standard iTC password
|
389
|
+
account_manager = CredentialsManager::AccountManager.new(user: @user)
|
390
|
+
return account_manager.password(ask_if_missing: true)
|
391
|
+
end
|
392
|
+
|
386
393
|
# Tells the user how to get an application specific password
|
387
394
|
def handle_two_step_failure(ex)
|
395
|
+
if ENV[TWO_FACTOR_ENV_VARIABLE].to_s.length > 0
|
396
|
+
# Password provided, however we already used it
|
397
|
+
UI.error("Application specific password you provided using #{TWO_FACTOR_ENV_VARIABLE}")
|
398
|
+
UI.error("is invalid, please make sure it's correct")
|
399
|
+
UI.user_error!("Invalid application specific password provided")
|
400
|
+
end
|
401
|
+
|
388
402
|
a = CredentialsManager::AccountManager.new(user: @user,
|
389
|
-
prefix: TWO_STEP_HOST_PREFIX
|
403
|
+
prefix: TWO_STEP_HOST_PREFIX,
|
404
|
+
note: "application-specific")
|
390
405
|
if a.password(ask_if_missing: false).to_s.length > 0
|
391
406
|
# user already entered one.. delete the old one
|
392
407
|
UI.error("Application specific password seems wrong")
|
@@ -397,7 +412,10 @@ module FastlaneCore
|
|
397
412
|
UI.error("Please go to https://appleid.apple.com/account/manage")
|
398
413
|
UI.error("and generate an application specific password for")
|
399
414
|
UI.error("the iTunes Transporter, which is used to upload builds")
|
400
|
-
|
415
|
+
UI.error("To set the application specific password on a CI machine using")
|
416
|
+
UI.error("an environment variable, you can set the")
|
417
|
+
UI.error("#{TWO_FACTOR_ENV_VARIABLE} variable")
|
418
|
+
@password = a.password(ask_if_missing: true) # to ask the user for the missing value
|
401
419
|
|
402
420
|
return true
|
403
421
|
end
|
@@ -71,6 +71,8 @@ module FastlaneCore
|
|
71
71
|
end
|
72
72
|
puts '#######################################################################'.green
|
73
73
|
Changelog.show_changes(gem_name, current_version) unless FastlaneCore::Env.truthy?("FASTLANE_HIDE_CHANGELOG")
|
74
|
+
|
75
|
+
ensure_rubygems_source
|
74
76
|
end
|
75
77
|
|
76
78
|
# The command that the user should use to update their mac
|
@@ -84,6 +86,20 @@ module FastlaneCore
|
|
84
86
|
end
|
85
87
|
end
|
86
88
|
|
89
|
+
# Check if RubyGems is set as a gem source
|
90
|
+
# on some machines that might not be the case
|
91
|
+
# and then users can't find the update when
|
92
|
+
# running the specified command
|
93
|
+
def self.ensure_rubygems_source
|
94
|
+
return if Helper.contained_fastlane?
|
95
|
+
return if `gem sources`.include?("https://rubygems.org")
|
96
|
+
puts ""
|
97
|
+
UI.error("RubyGems is not listed as your Gem source")
|
98
|
+
UI.error("You can run `gem sources` to see all your sources")
|
99
|
+
UI.error("Please run the following command to fix this:")
|
100
|
+
UI.command("gem sources --add https://rubygems.org")
|
101
|
+
end
|
102
|
+
|
87
103
|
# Generate the URL on the main thread (since we're switching directory)
|
88
104
|
def self.generate_fetch_url(gem_name)
|
89
105
|
url = UPDATE_URL + gem_name
|
data/spaceship/README.md
CHANGED
@@ -112,7 +112,11 @@ This requires you to install `pry` using `sudo gem install pry`. `pry` is not in
|
|
112
112
|
|
113
113
|
When your Apple account has 2 factor verification enabled, you'll automatically be asked to verify your identity using your phone. The resulting session will be stored in `~/.spaceship/[email]/cookie`. The session should be valid for about one month, however there is no way to test this without actually waiting for over a month.
|
114
114
|
|
115
|
-
|
115
|
+
### Support for CI machines
|
116
|
+
|
117
|
+
#### Web sessions
|
118
|
+
|
119
|
+
To generate a web session for your CI machine, use
|
116
120
|
|
117
121
|
```sh
|
118
122
|
fastlane spaceauth -u apple@krausefx.com
|
@@ -126,6 +130,16 @@ export FASTLANE_SESSION='---\n- !ruby/object:HTTP::Cookie\n name: DES5c148586df
|
|
126
130
|
|
127
131
|
Copy everything from `---\n` to your CI server and provide it as environment variable named `FASTLANE_SESSION`.
|
128
132
|
|
133
|
+
#### Transporter
|
134
|
+
|
135
|
+
If you want to upload builds to TestFlight/iTunes Connect from your CI, you have to generate an application specific password:
|
136
|
+
|
137
|
+
1. Visit [appleid.apple.com/account/manage](https://appleid.apple.com/account/manage)
|
138
|
+
1. Generate a new application specific password
|
139
|
+
1. Provide the application specific password using an environment variable `FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD`.
|
140
|
+
|
141
|
+
Alternatively you can enter the password when you're asked the first time _fastlane_ uploads a build.
|
142
|
+
|
129
143
|
### _spaceship_ in use
|
130
144
|
|
131
145
|
All [fastlane tools](https://fastlane.tools) that communicate with Apple's web services in some way, use _spaceship_ to do so.
|
data/supply/lib/supply/client.rb
CHANGED
@@ -211,6 +211,21 @@ module Supply
|
|
211
211
|
return result_upload.version_code
|
212
212
|
end
|
213
213
|
|
214
|
+
def upload_mapping(path_to_mapping, apk_version_code)
|
215
|
+
ensure_active_edit!
|
216
|
+
|
217
|
+
call_google_api do
|
218
|
+
android_publisher.upload_edit_deobfuscationfile(
|
219
|
+
current_package_name,
|
220
|
+
current_edit.id,
|
221
|
+
apk_version_code,
|
222
|
+
"proguard",
|
223
|
+
upload_source: path_to_mapping,
|
224
|
+
content_type: "application/octet-stream"
|
225
|
+
)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
214
229
|
# Updates the track for the provided version code(s)
|
215
230
|
def update_track(track, rollout, apk_version_code)
|
216
231
|
ensure_active_edit!
|
@@ -127,7 +127,29 @@ module Supply
|
|
127
127
|
optional: true,
|
128
128
|
description: "Indicate that changes will only be validated with Google Play rather than actually published",
|
129
129
|
is_string: false,
|
130
|
-
default_value: false)
|
130
|
+
default_value: false),
|
131
|
+
FastlaneCore::ConfigItem.new(key: :mapping,
|
132
|
+
env_name: "SUPPLY_MAPPING",
|
133
|
+
description: "Path to the mapping file to upload",
|
134
|
+
short_option: "-d",
|
135
|
+
conflicting_options: [:mapping_paths],
|
136
|
+
optional: true,
|
137
|
+
verify_block: proc do |value|
|
138
|
+
UI.user_error! "Could not find mapping file at path '#{value}'" unless File.exist?(value)
|
139
|
+
end),
|
140
|
+
FastlaneCore::ConfigItem.new(key: :mapping_paths,
|
141
|
+
env_name: "SUPPLY_MAPPING_PATHS",
|
142
|
+
conflicting_options: [:mapping],
|
143
|
+
optional: true,
|
144
|
+
type: Array,
|
145
|
+
description: "An array of paths to mapping files to upload",
|
146
|
+
short_option: "-s",
|
147
|
+
verify_block: proc do |value|
|
148
|
+
UI.user_error!("Could not evaluate array from '#{value}'") unless value.kind_of?(Array)
|
149
|
+
value.each do |path|
|
150
|
+
UI.user_error! "Could not find mapping file at path '#{path}'" unless File.exist?(path)
|
151
|
+
end
|
152
|
+
end)
|
131
153
|
|
132
154
|
]
|
133
155
|
end
|
@@ -115,6 +115,13 @@ module Supply
|
|
115
115
|
apk_version_codes.push(upload_binary_data(apk_path))
|
116
116
|
end
|
117
117
|
|
118
|
+
mapping_paths = [Supply.config[:mapping]] unless (mapping_paths = Supply.config[:mapping_paths])
|
119
|
+
mapping_paths.zip(apk_version_codes).each do |mapping_path, version_code|
|
120
|
+
if mapping_path
|
121
|
+
client.upload_mapping(mapping_path, version_code)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
118
125
|
update_track(apk_version_codes)
|
119
126
|
end
|
120
127
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2017-01-
|
17
|
+
date: 2017-01-04 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: slack-notifier
|