fastlane 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|