fastlane_core 0.15.1 → 0.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/fastlane_core.rb +0 -1
- data/lib/fastlane_core/cert_checker.rb +18 -8
- data/lib/fastlane_core/configuration/commander_generator.rb +3 -3
- data/lib/fastlane_core/configuration/config_item.rb +11 -12
- data/lib/fastlane_core/configuration/configuration.rb +32 -31
- data/lib/fastlane_core/configuration/configuration_file.rb +4 -2
- data/lib/fastlane_core/helper.rb +23 -22
- data/lib/fastlane_core/ipa_file_analyser.rb +15 -15
- data/lib/fastlane_core/itunes_connect/itunes_connect.rb +4 -5
- data/lib/fastlane_core/itunes_connect/itunes_connect_apple_id.rb +2 -2
- data/lib/fastlane_core/itunes_connect/itunes_connect_helper.rb +15 -12
- data/lib/fastlane_core/itunes_connect/itunes_connect_login.rb +10 -10
- data/lib/fastlane_core/itunes_search_api.rb +21 -20
- data/lib/fastlane_core/itunes_transporter.rb +92 -90
- data/lib/fastlane_core/languages.rb +1 -1
- data/lib/fastlane_core/provisioning_profile.rb +3 -3
- data/lib/fastlane_core/update_checker.rb +3 -3
- data/lib/fastlane_core/version.rb +1 -1
- 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: 0c1dc4d0e0d9f0f48fe5d64fde77445887be2e66
|
4
|
+
data.tar.gz: 0170691330d6ef38ade863094e66ff2c6416665f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c9d72203666a1f9b39d00fcfae0f60690cb495822e3ec1a4327ce8c3b66204ad8f080ca7ab4cff9b1c776178bb758d8b05d935d80a9fcf490974abe89b1a40b
|
7
|
+
data.tar.gz: b159acddf91ad141c70e7cd3da36d7fb2e9b326145220e56149a4d0c5b07e89d2554e13eb8470fbca3e868dd6e360fa773637547e7f7c6ac9a04d7ce589f5dd6
|
data/lib/fastlane_core.rb
CHANGED
@@ -1,21 +1,31 @@
|
|
1
1
|
module FastlaneCore
|
2
2
|
# This class checks if a specific certificate is installed on the current mac
|
3
3
|
class CertChecker
|
4
|
-
def self.
|
5
|
-
raise "Could not find file '#{path}'".red unless File.
|
4
|
+
def self.installed?(path)
|
5
|
+
raise "Could not find file '#{path}'".red unless File.exist?(path)
|
6
6
|
|
7
7
|
ids = installed_identies
|
8
8
|
finger_print = sha1_fingerprint(path)
|
9
9
|
|
10
|
-
return ids.include?finger_print
|
10
|
+
return ids.include? finger_print
|
11
|
+
end
|
12
|
+
|
13
|
+
# Legacy Method, use `installed?` instead
|
14
|
+
# rubocop:disable Style/PredicateName
|
15
|
+
def self.is_installed?(path)
|
16
|
+
installed?(path)
|
11
17
|
end
|
18
|
+
# rubocop:enable Style/PredicateName
|
12
19
|
|
13
20
|
def self.installed_identies
|
14
21
|
available = `security find-identity -v -p codesigning`
|
15
22
|
ids = []
|
16
23
|
available.split("\n").each do |current|
|
17
|
-
|
18
|
-
|
24
|
+
next if current.include? "REVOKED"
|
25
|
+
begin
|
26
|
+
(ids << current.match(/.*\) (.*) \".*/)[1])
|
27
|
+
rescue
|
28
|
+
# the last line does not match
|
19
29
|
end
|
20
30
|
end
|
21
31
|
|
@@ -26,12 +36,12 @@ module FastlaneCore
|
|
26
36
|
result = `openssl x509 -in "#{path}" -inform der -noout -sha1 -fingerprint`
|
27
37
|
begin
|
28
38
|
result = result.match(/SHA1 Fingerprint=(.*)/)[1]
|
29
|
-
result.
|
39
|
+
result.delete!(':')
|
30
40
|
return result
|
31
|
-
rescue
|
41
|
+
rescue
|
32
42
|
Helper.log.info result
|
33
43
|
raise "Error parsing certificate '#{path}'"
|
34
44
|
end
|
35
45
|
end
|
36
46
|
end
|
37
|
-
end
|
47
|
+
end
|
@@ -12,11 +12,11 @@ module FastlaneCore
|
|
12
12
|
type = (option.is_string ? String : nil)
|
13
13
|
short_option = option.short_option || "-#{option.key.to_s[0]}"
|
14
14
|
|
15
|
-
raise "Short option #{short_option} already taken for key #{option.key}".red if short_codes.include?short_option
|
15
|
+
raise "Short option #{short_option} already taken for key #{option.key}".red if short_codes.include? short_option
|
16
16
|
raise "-v is already used for the version (key #{option.key})".red if short_option == "-v"
|
17
17
|
raise "-h is already used for the help screen (key #{option.key})".red if short_option == "-h"
|
18
18
|
raise "-t is already used for the trace screen (key #{option.key})".red if short_option == "-t"
|
19
|
-
|
19
|
+
|
20
20
|
short_codes << short_option
|
21
21
|
|
22
22
|
# Example Call
|
@@ -29,4 +29,4 @@ module FastlaneCore
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
|
-
end
|
32
|
+
end
|
@@ -8,16 +8,16 @@ module FastlaneCore
|
|
8
8
|
# @param description (String) A description shown to the user
|
9
9
|
# @param short_option (String) A string of length 1 which is used for the command parameters (e.g. -f)
|
10
10
|
# @param default_value the value which is used if there was no given values and no environment values
|
11
|
-
# @param verify_block an optional block which is called when a new value is set.
|
11
|
+
# @param verify_block an optional block which is called when a new value is set.
|
12
12
|
# Check value is valid. This could be type checks or if a folder/file exists
|
13
13
|
# You have to raise a specific exception if something goes wrong. Append .red after the string
|
14
14
|
# @param is_string (String) is that parameter a string? Defaults to true. If it's true, the type string will be verified.
|
15
15
|
# @param optional (Boolean) is false by default. If set to true, also string values will not be asked to the user
|
16
16
|
def initialize(key: nil, env_name: nil, description: nil, short_option: nil, default_value: nil, verify_block: nil, is_string: true, optional: false)
|
17
|
-
raise "key must be a symbol" unless key.kind_of?Symbol
|
18
|
-
raise "env_name must be a String" unless (env_name || '').kind_of?String
|
17
|
+
raise "key must be a symbol" unless key.kind_of? Symbol
|
18
|
+
raise "env_name must be a String" unless (env_name || '').kind_of? String
|
19
19
|
if short_option
|
20
|
-
raise "short_option must be a String of length 1" unless
|
20
|
+
raise "short_option must be a String of length 1" unless short_option.kind_of? String and short_option.delete('-').length == 1
|
21
21
|
end
|
22
22
|
if description
|
23
23
|
raise "Do not let descriptions end with a '.', since it's used for user inputs as well".red if (description[-1] == '.')
|
@@ -33,26 +33,25 @@ module FastlaneCore
|
|
33
33
|
@optional = optional
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
36
|
# This will raise an exception if the value is not valid
|
38
37
|
def verify!(value)
|
39
|
-
raise "Invalid value '#{value}' for option '#{self}'".red unless
|
38
|
+
raise "Invalid value '#{value}' for option '#{self}'".red unless valid? value
|
40
39
|
true
|
41
40
|
end
|
42
41
|
|
43
42
|
# Make sure, the value is valid (based on the verify block)
|
44
43
|
# Returns false if that's not the case
|
45
|
-
def
|
46
|
-
# we also allow nil values, which do not have to be verified.
|
44
|
+
def valid?(value)
|
45
|
+
# we also allow nil values, which do not have to be verified.
|
47
46
|
if value
|
48
47
|
if @is_string
|
49
|
-
raise "'#{self.key}' value must be a String! Found #{value.class} instead.".red unless value.kind_of?String
|
48
|
+
raise "'#{self.key}' value must be a String! Found #{value.class} instead.".red unless value.kind_of? String
|
50
49
|
end
|
51
|
-
|
50
|
+
|
52
51
|
if @verify_block
|
53
52
|
begin
|
54
53
|
@verify_block.call(value)
|
55
|
-
rescue
|
54
|
+
rescue => ex
|
56
55
|
Helper.log.fatal "Error setting value '#{value}' for option '#{@key}'".red
|
57
56
|
raise ex
|
58
57
|
end
|
@@ -66,4 +65,4 @@ module FastlaneCore
|
|
66
65
|
[@key, @description].join(": ")
|
67
66
|
end
|
68
67
|
end
|
69
|
-
end
|
68
|
+
end
|
@@ -22,33 +22,35 @@ module FastlaneCore
|
|
22
22
|
#####################################################
|
23
23
|
# @!group Setting up the configuration
|
24
24
|
#####################################################
|
25
|
-
|
25
|
+
|
26
26
|
def initialize(available_options, values)
|
27
27
|
self.available_options = available_options || []
|
28
28
|
self.values = values || {}
|
29
29
|
|
30
|
-
verify_input_types
|
30
|
+
verify_input_types
|
31
31
|
verify_value_exists
|
32
32
|
verify_no_duplicates
|
33
33
|
verify_default_value_matches_verify_block
|
34
34
|
end
|
35
35
|
|
36
36
|
def verify_input_types
|
37
|
-
raise "available_options parameter must be an array of ConfigItems but is #{@available_options.class}".red unless @available_options.kind_of?Array
|
37
|
+
raise "available_options parameter must be an array of ConfigItems but is #{@available_options.class}".red unless @available_options.kind_of? Array
|
38
38
|
@available_options.each do |item|
|
39
|
-
raise "available_options parameter must be an array of ConfigItems. Found #{item.class}.".red unless item.kind_of?ConfigItem
|
39
|
+
raise "available_options parameter must be an array of ConfigItems. Found #{item.class}.".red unless item.kind_of? ConfigItem
|
40
40
|
end
|
41
|
-
raise "values parameter must be a hash".red unless @values.kind_of?Hash
|
41
|
+
raise "values parameter must be a hash".red unless @values.kind_of? Hash
|
42
42
|
end
|
43
43
|
|
44
44
|
def verify_value_exists
|
45
45
|
# Make sure the given value keys exist
|
46
46
|
@values.each do |key, value|
|
47
|
+
next if key == :trace # special treatment
|
48
|
+
|
47
49
|
option = option_for_key(key)
|
48
50
|
if option
|
49
51
|
option.verify!(value) # Call the verify block for it too
|
50
52
|
else
|
51
|
-
raise "Could not find option '#{key}' in the list of available options: #{@available_options.collect
|
53
|
+
raise "Could not find option '#{key}' in the list of available options: #{@available_options.collect(&:key).join(', ')}".red
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -56,11 +58,11 @@ module FastlaneCore
|
|
56
58
|
def verify_no_duplicates
|
57
59
|
# Make sure a key was not used multiple times
|
58
60
|
@available_options.each do |current|
|
59
|
-
count = @available_options.
|
61
|
+
count = @available_options.count { |option| option.key == current.key }
|
60
62
|
raise "Multiple entries for configuration key '#{current.key}' found!".red if count > 1
|
61
63
|
|
62
64
|
unless current.short_option.to_s.empty?
|
63
|
-
count = @available_options.
|
65
|
+
count = @available_options.count { |option| option.short_option == current.short_option }
|
64
66
|
raise "Multiple entries for short_option '#{current.short_option}' found!".red if count > 1
|
65
67
|
end
|
66
68
|
end
|
@@ -69,13 +71,13 @@ module FastlaneCore
|
|
69
71
|
# Verifies the default value is also valid
|
70
72
|
def verify_default_value_matches_verify_block
|
71
73
|
@available_options.each do |item|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
next unless item.verify_block && item.default_value
|
75
|
+
|
76
|
+
begin
|
77
|
+
item.verify_block.call(item.default_value)
|
78
|
+
rescue => ex
|
79
|
+
Helper.log.fatal ex
|
80
|
+
raise "Invalid default value for #{item.key}, doesn't match verify_block".red
|
79
81
|
end
|
80
82
|
end
|
81
83
|
end
|
@@ -83,7 +85,7 @@ module FastlaneCore
|
|
83
85
|
# This method takes care of parsing and using the configuration file as values
|
84
86
|
# Call this once you know where the config file might be located
|
85
87
|
# Take a look at how `gym` uses this method
|
86
|
-
#
|
88
|
+
#
|
87
89
|
# @param config_file_name [String] The name of the configuration file to use (optional)
|
88
90
|
# @param block_for_missing [Block] A ruby block that is called when there is an unkonwn method
|
89
91
|
# in the configuration file
|
@@ -93,7 +95,7 @@ module FastlaneCore
|
|
93
95
|
self.config_file_name = config_file_name
|
94
96
|
|
95
97
|
paths = Dir["./fastlane/#{self.config_file_name}"] + Dir["./#{self.config_file_name}"]
|
96
|
-
paths
|
98
|
+
paths += Dir["./spec/fixtures/#{self.config_file_name}"] if Helper.is_test?
|
97
99
|
return if paths.count == 0
|
98
100
|
|
99
101
|
path = paths.first
|
@@ -106,25 +108,24 @@ module FastlaneCore
|
|
106
108
|
|
107
109
|
# Returns the value for a certain key. fastlane_core tries to fetch the value from different sources
|
108
110
|
def fetch(key)
|
109
|
-
raise "Key '#{key}' must be a symbol. Example :app_id.".red unless key.kind_of?Symbol
|
111
|
+
raise "Key '#{key}' must be a symbol. Example :app_id.".red unless key.kind_of? Symbol
|
110
112
|
|
111
113
|
option = option_for_key(key)
|
112
|
-
raise "Could not find option for key :#{key}. Available keys: #{@available_options.collect
|
114
|
+
raise "Could not find option for key :#{key}. Available keys: #{@available_options.collect(&:key).join(', ')}".red unless option
|
113
115
|
|
114
116
|
value = @values[key]
|
115
|
-
|
117
|
+
|
116
118
|
# `if value == nil` instead of ||= because false is also a valid value
|
117
|
-
if value
|
119
|
+
if value.nil? and option.env_name and ENV[option.env_name]
|
118
120
|
value = ENV[option.env_name].dup
|
119
121
|
option.verify!(value) if value
|
120
122
|
end
|
121
123
|
|
122
|
-
value = option.default_value if value
|
123
|
-
value = nil if
|
124
|
+
value = option.default_value if value.nil?
|
125
|
+
value = nil if value.nil? and !option.is_string # by default boolean flags are false
|
124
126
|
|
125
127
|
return value unless value.nil? # we already have a value
|
126
128
|
return value if option.optional # as this value is not required, just return what we have
|
127
|
-
|
128
129
|
|
129
130
|
if Helper.is_test? or Helper.is_ci?
|
130
131
|
# Since we don't want to be asked on tests, we'll just call the verify block with no value
|
@@ -134,13 +135,13 @@ module FastlaneCore
|
|
134
135
|
raise "No value found for '#{key}'"
|
135
136
|
end
|
136
137
|
|
137
|
-
while value
|
138
|
+
while value.nil?
|
138
139
|
Helper.log.info "To not be asked about this value, you can specify it using '#{option.key}'".yellow
|
139
140
|
value = ask("#{option.description}: ")
|
140
141
|
# Also store this value to use it from now on
|
141
142
|
begin
|
142
143
|
set(key, value)
|
143
|
-
rescue
|
144
|
+
rescue => ex
|
144
145
|
puts ex
|
145
146
|
value = nil
|
146
147
|
end
|
@@ -152,11 +153,11 @@ module FastlaneCore
|
|
152
153
|
# Overwrites or sets a new value for a given key
|
153
154
|
# @param key [Symbol] Must be a symbol
|
154
155
|
def set(key, value)
|
155
|
-
raise "Key '#{key}' must be a symbol. Example :#{key}.".red unless key.kind_of?Symbol
|
156
|
+
raise "Key '#{key}' must be a symbol. Example :#{key}.".red unless key.kind_of? Symbol
|
156
157
|
option = option_for_key(key)
|
157
|
-
|
158
|
+
|
158
159
|
unless option
|
159
|
-
raise "Could not find option '#{key}' in the list of available options: #{@available_options.collect
|
160
|
+
raise "Could not find option '#{key}' in the list of available options: #{@available_options.collect(&:key).join(', ')}".red
|
160
161
|
end
|
161
162
|
|
162
163
|
option.verify!(value)
|
@@ -174,7 +175,7 @@ module FastlaneCore
|
|
174
175
|
end
|
175
176
|
|
176
177
|
def all_keys
|
177
|
-
@available_options.collect
|
178
|
+
@available_options.collect(&:key)
|
178
179
|
end
|
179
180
|
|
180
181
|
# Returns the config_item object for a given key
|
@@ -186,4 +187,4 @@ module FastlaneCore
|
|
186
187
|
alias_method :[], :fetch
|
187
188
|
alias_method :[]=, :set
|
188
189
|
end
|
189
|
-
end
|
190
|
+
end
|
@@ -10,12 +10,14 @@ module FastlaneCore
|
|
10
10
|
self.config = config
|
11
11
|
@block_for_missing = block_for_missing
|
12
12
|
|
13
|
+
# rubocop:disable Lint/Eval
|
13
14
|
eval(File.read(path))
|
15
|
+
# rubocop:enable Lint/Eval
|
14
16
|
end
|
15
17
|
|
16
18
|
def method_missing(method_sym, *arguments, &block)
|
17
19
|
# First, check if the key is actually available
|
18
|
-
if self.config.all_keys.include?method_sym
|
20
|
+
if self.config.all_keys.include? method_sym
|
19
21
|
value = arguments.first || (block.call if block_given?) # this is either a block or a value
|
20
22
|
if value
|
21
23
|
self.config[method_sym] = value
|
@@ -32,4 +34,4 @@ module FastlaneCore
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
|
-
end
|
37
|
+
end
|
data/lib/fastlane_core/helper.rb
CHANGED
@@ -2,7 +2,6 @@ require 'logger'
|
|
2
2
|
|
3
3
|
module FastlaneCore
|
4
4
|
module Helper
|
5
|
-
|
6
5
|
# Logging happens using this method
|
7
6
|
def self.log
|
8
7
|
if is_test?
|
@@ -49,38 +48,40 @@ module FastlaneCore
|
|
49
48
|
defined?SpecHelper
|
50
49
|
end
|
51
50
|
|
52
|
-
# Use Helper.test? instead
|
53
|
-
def self.is_test?
|
54
|
-
self.test?
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.is_ci?
|
58
|
-
ci?
|
59
|
-
end
|
60
|
-
|
61
51
|
# @return [boolean] true if building in a known CI environment
|
62
52
|
def self.ci?
|
63
53
|
# Check for Jenkins, Travis CI, ... environment variables
|
64
54
|
['JENKINS_URL', 'TRAVIS', 'CIRCLECI', 'CI'].each do |current|
|
65
|
-
return true if ENV.
|
55
|
+
return true if ENV.key?(current)
|
66
56
|
end
|
67
57
|
return false
|
68
58
|
end
|
69
59
|
|
70
|
-
#
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
60
|
+
# Is the currently running computer a Mac?
|
61
|
+
def self.mac?
|
62
|
+
(/darwin/ =~ RUBY_PLATFORM) != nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# Use Helper.test? and Helper.ci? instead (legacy calls)
|
66
|
+
# rubocop:disable Style/PredicateName
|
67
|
+
def self.is_test?
|
68
|
+
self.test?
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.is_ci?
|
72
|
+
ci?
|
75
73
|
end
|
76
74
|
|
77
75
|
def self.is_mac?
|
78
76
|
self.mac?
|
79
77
|
end
|
78
|
+
# rubocop:enable Style/PredicateName
|
80
79
|
|
81
|
-
#
|
82
|
-
|
83
|
-
|
80
|
+
# @return the full path to the Xcode developer tools of the currently
|
81
|
+
# running system
|
82
|
+
def self.xcode_path
|
83
|
+
return "" if self.is_test? and !self.is_mac?
|
84
|
+
`xcode-select -p`.delete("\n") + "/"
|
84
85
|
end
|
85
86
|
|
86
87
|
# @return the full path to the iTMSTransporter executable
|
@@ -92,19 +93,19 @@ module FastlaneCore
|
|
92
93
|
"../Applications/Application Loader.app/Contents/itms/bin/iTMSTransporter"
|
93
94
|
].each do |path|
|
94
95
|
result = File.join(self.xcode_path, path)
|
95
|
-
return result if File.
|
96
|
+
return result if File.exist?(result)
|
96
97
|
end
|
97
98
|
raise "Could not find transporter at #{self.xcode_path}. Please make sure you set the correct path to your Xcode installation.".red
|
98
99
|
end
|
99
100
|
|
100
101
|
def self.fastlane_enabled?
|
101
102
|
# This is called from the root context on the first start
|
102
|
-
@@enabled ||= File.directory?"./fastlane"
|
103
|
+
@@enabled ||= File.directory? "./fastlane"
|
103
104
|
end
|
104
105
|
|
105
106
|
# Path to the installed gem to load resources (e.g. resign.sh)
|
106
107
|
def self.gem_path(gem_name)
|
107
|
-
if
|
108
|
+
if !Helper.is_test? and Gem::Specification.find_all_by_name(gem_name).any?
|
108
109
|
return Gem::Specification.find_by_name(gem_name).gem_dir
|
109
110
|
else
|
110
111
|
return './'
|
@@ -20,22 +20,22 @@ module FastlaneCore
|
|
20
20
|
def self.fetch_info_plist_file(path)
|
21
21
|
Zip::File.open(path) do |zipfile|
|
22
22
|
zipfile.each do |file|
|
23
|
-
|
24
|
-
# We can not be completely sure, that's the correct plist file, so we have to try
|
25
|
-
begin
|
26
|
-
# The XML file has to be properly unpacked first
|
27
|
-
tmp_path = "/tmp/deploytmp.plist"
|
28
|
-
File.write(tmp_path, zipfile.read(file))
|
29
|
-
system("plutil -convert xml1 #{tmp_path}")
|
30
|
-
result = Plist::parse_xml(tmp_path)
|
31
|
-
File.delete(tmp_path)
|
23
|
+
next unless file.name.include? '.plist' and !['.bundle', '.framework'].any? { |a| file.name.include? a }
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
25
|
+
# We can not be completely sure, that's the correct plist file, so we have to try
|
26
|
+
begin
|
27
|
+
# The XML file has to be properly unpacked first
|
28
|
+
tmp_path = "/tmp/deploytmp.plist"
|
29
|
+
File.write(tmp_path, zipfile.read(file))
|
30
|
+
system("plutil -convert xml1 #{tmp_path}")
|
31
|
+
result = Plist.parse_xml(tmp_path)
|
32
|
+
File.delete(tmp_path)
|
33
|
+
|
34
|
+
if result['CFBundleIdentifier'] or result['CFBundleVersion']
|
35
|
+
return result
|
38
36
|
end
|
37
|
+
rescue
|
38
|
+
# We don't really care, look for another XML file
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -43,4 +43,4 @@ module FastlaneCore
|
|
43
43
|
nil
|
44
44
|
end
|
45
45
|
end
|
46
|
-
end
|
46
|
+
end
|
@@ -3,7 +3,6 @@ require 'capybara/poltergeist'
|
|
3
3
|
require 'credentials_manager/password_manager'
|
4
4
|
require 'phantomjs/poltergeist' # this will download and store phantomjs
|
5
5
|
|
6
|
-
|
7
6
|
require 'fastlane_core/itunes_connect/itunes_connect_helper.rb'
|
8
7
|
require 'fastlane_core/itunes_connect/itunes_connect_login.rb'
|
9
8
|
require 'fastlane_core/itunes_connect/itunes_connect_apple_id.rb'
|
@@ -11,11 +10,11 @@ require 'fastlane_core/itunes_connect/itunes_connect_apple_id.rb'
|
|
11
10
|
module FastlaneCore
|
12
11
|
# Everything that can't be achived using the {FastlaneCore::ItunesTransporter}
|
13
12
|
# will be scripted using the iTunesConnect frontend.
|
14
|
-
#
|
13
|
+
#
|
15
14
|
# Every method you call here, might take a time
|
16
15
|
class ItunesConnect
|
17
16
|
# This error occurs only if there is something wrong with the given login data
|
18
|
-
class ItunesConnectLoginError < StandardError
|
17
|
+
class ItunesConnectLoginError < StandardError
|
19
18
|
end
|
20
19
|
|
21
20
|
# This error can occur for many reaons. It is
|
@@ -32,12 +31,12 @@ module FastlaneCore
|
|
32
31
|
BUTTON_STRING_SUBMIT_FOR_REVIEW = "Submit for Review"
|
33
32
|
|
34
33
|
WAITING_FOR_REVIEW = "Waiting For Review"
|
35
|
-
|
34
|
+
|
36
35
|
def initialize
|
37
36
|
super
|
38
37
|
|
39
38
|
return if Helper.is_test?
|
40
|
-
|
39
|
+
|
41
40
|
Capybara.run_server = false
|
42
41
|
Capybara.default_driver = :poltergeist
|
43
42
|
Capybara.javascript_driver = :poltergeist
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module FastlaneCore
|
1
|
+
module FastlaneCore
|
2
2
|
# Find the Apple ID based on the App Identifier
|
3
3
|
class ItunesConnect
|
4
4
|
LIST_APPLE_IDS_URL = "https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa/ra/apps/manageyourapps/summary"
|
@@ -12,4 +12,4 @@ module FastlaneCore
|
|
12
12
|
# Do nothing right now...
|
13
13
|
end
|
14
14
|
end
|
15
|
-
end
|
15
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
|
-
module FastlaneCore
|
1
|
+
module FastlaneCore
|
2
2
|
class ItunesConnect
|
3
3
|
# All the private helpers
|
4
|
+
|
4
5
|
private
|
6
|
+
|
5
7
|
# Opens the app details page of the given app.
|
6
8
|
# @param app (Deliver::App) the app that should be opened
|
7
9
|
# @return (bool) true if everything worked fine
|
8
|
-
# @raise [ItunesConnectGeneralError] General error while executing
|
10
|
+
# @raise [ItunesConnectGeneralError] General error while executing
|
9
11
|
# this action
|
10
12
|
# @raise [ItunesConnectLoginError] Login data is wrong
|
11
13
|
def open_app_page(app)
|
@@ -18,7 +20,7 @@ module FastlaneCore
|
|
18
20
|
wait_for_elements('.page-subnav')
|
19
21
|
sleep 5
|
20
22
|
|
21
|
-
if current_url.include?"wa/defaultError" # app could not be found
|
23
|
+
if current_url.include? "wa/defaultError" # app could not be found
|
22
24
|
raise "Could not open app details for app '#{app}'. Make sure you're using the correct Apple ID and the correct Apple developer account (#{CredentialsManager::PasswordManager.shared_manager.username}).".red
|
23
25
|
end
|
24
26
|
|
@@ -27,9 +29,8 @@ module FastlaneCore
|
|
27
29
|
error_occured(ex)
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
32
|
def verify_app(app)
|
32
|
-
raise ItunesConnectGeneralError.new("No valid Deliver::App given") unless app.kind_of?Deliver::App
|
33
|
+
raise ItunesConnectGeneralError.new("No valid Deliver::App given") unless app.kind_of? Deliver::App
|
33
34
|
raise ItunesConnectGeneralError.new("App is missing information (apple_id not given)") unless (app.apple_id || '').to_s.length > 5
|
34
35
|
end
|
35
36
|
|
@@ -40,7 +41,9 @@ module FastlaneCore
|
|
40
41
|
|
41
42
|
def snap
|
42
43
|
path = File.expand_path("Error#{Time.now.to_i}.png")
|
43
|
-
|
44
|
+
# rubocop:disable Lint/Debugger
|
45
|
+
save_screenshot(path, full: true)
|
46
|
+
# rubocop:enable Lint/Debugger
|
44
47
|
system("open '#{path}'") unless ENV['SIGH_DISABLE_OPEN_ERROR']
|
45
48
|
end
|
46
49
|
|
@@ -49,11 +52,11 @@ module FastlaneCore
|
|
49
52
|
started = Time.now
|
50
53
|
|
51
54
|
# Wait, while iTunesConnect is processing the uploaded file
|
52
|
-
while
|
55
|
+
while page.has_content? "Uploaded"
|
53
56
|
# iTunesConnect is super slow... so we have to wait...
|
54
|
-
Helper.log.info("Sorry, we have to wait for iTunesConnect, since it's still processing the uploaded ipa file\n"
|
55
|
-
"If this takes longer than 45 minutes, you have to re-upload the ipa file again.\n"
|
56
|
-
"You can always open the browser page yourself: '#{current_url}'\n"
|
57
|
+
Helper.log.info("Sorry, we have to wait for iTunesConnect, since it's still processing the uploaded ipa file\n" \
|
58
|
+
"If this takes longer than 45 minutes, you have to re-upload the ipa file again.\n" \
|
59
|
+
"You can always open the browser page yourself: '#{current_url}'\n" \
|
57
60
|
"Passed time: ~#{((Time.now - started) / 60.0).to_i} minute(s)")
|
58
61
|
sleep 30
|
59
62
|
visit current_url
|
@@ -64,7 +67,7 @@ module FastlaneCore
|
|
64
67
|
def wait_for_elements(name)
|
65
68
|
counter = 0
|
66
69
|
results = all(name)
|
67
|
-
while results.count == 0
|
70
|
+
while results.count == 0
|
68
71
|
# Helper.log.debug "Waiting for #{name}"
|
69
72
|
sleep 0.2
|
70
73
|
|
@@ -79,4 +82,4 @@ module FastlaneCore
|
|
79
82
|
return results
|
80
83
|
end
|
81
84
|
end
|
82
|
-
end
|
85
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
module FastlaneCore
|
1
|
+
module FastlaneCore
|
2
2
|
# Login code
|
3
3
|
class ItunesConnect
|
4
4
|
# Loggs in a user with the given login data on the iTC Frontend.
|
5
5
|
# You don't need to pass a username and password. It will
|
6
6
|
# Automatically be fetched using the {CredentialsManager::PasswordManager}.
|
7
|
-
# This method will also automatically be called when triggering other
|
7
|
+
# This method will also automatically be called when triggering other
|
8
8
|
# actions like {#open_app_page}
|
9
9
|
# @param user (String) (optional) The username/email address
|
10
10
|
# @param password (String) (optional) The password
|
11
11
|
# @return (bool) true if everything worked fine
|
12
|
-
# @raise [ItunesConnectGeneralError] General error while executing
|
12
|
+
# @raise [ItunesConnectGeneralError] General error while executing
|
13
13
|
# this action
|
14
14
|
# @raise [ItunesConnectLoginError] Login data is wrong
|
15
15
|
def login(user = nil, password = nil)
|
@@ -22,15 +22,15 @@ module FastlaneCore
|
|
22
22
|
raise "Could not open iTunesConnect" unless result['status'] == 'success'
|
23
23
|
|
24
24
|
sleep 3
|
25
|
-
|
26
|
-
if page.has_content?"My Apps"
|
25
|
+
|
26
|
+
if page.has_content? "My Apps"
|
27
27
|
# Already logged in
|
28
28
|
return true
|
29
29
|
end
|
30
30
|
|
31
31
|
begin
|
32
32
|
wait_for_elements('#accountpassword')
|
33
|
-
rescue
|
33
|
+
rescue
|
34
34
|
# when the user is already logged in, this will raise an exception
|
35
35
|
end
|
36
36
|
|
@@ -40,13 +40,13 @@ module FastlaneCore
|
|
40
40
|
begin
|
41
41
|
page.evaluate_script "appleConnectForm.submit()"
|
42
42
|
sleep 7
|
43
|
-
|
44
|
-
if page.has_content?"My Apps"
|
43
|
+
|
44
|
+
if page.has_content? "My Apps"
|
45
45
|
# Everything looks good
|
46
46
|
else
|
47
47
|
visit current_url # iTC sometimes is super buggy, try reloading the site
|
48
48
|
sleep 3
|
49
|
-
unless page.has_content?"My Apps"
|
49
|
+
unless page.has_content? "My Apps"
|
50
50
|
raise ItunesConnectLoginError.new("Looks like your login data was correct, but you do not have access to the apps.".red)
|
51
51
|
end
|
52
52
|
end
|
@@ -62,4 +62,4 @@ module FastlaneCore
|
|
62
62
|
error_occured(ex)
|
63
63
|
end
|
64
64
|
end
|
65
|
-
end
|
65
|
+
end
|
@@ -7,25 +7,27 @@ module FastlaneCore
|
|
7
7
|
|
8
8
|
# Fetch all information you can get from a specific AppleID of an app
|
9
9
|
# @param id (int) The AppleID of the given app. This usually consists of 9 digits.
|
10
|
-
# @
|
11
|
-
# @
|
12
|
-
#
|
10
|
+
# @param country (string) The optional ISO-2A country code
|
11
|
+
# @return (Hash) the response of the first result from Apple (https://itunes.apple.com/lookup?id=284882215[&country=FR])
|
12
|
+
# @example Response of Facebook App: https://itunes.apple.com/lookup?id=284882215[&country=FR]
|
13
|
+
# {
|
13
14
|
# ...
|
14
15
|
# artistName: "Facebook, Inc.",
|
15
16
|
# price: 0,
|
16
17
|
# version: "14.9",
|
17
18
|
# ...
|
18
19
|
# }
|
19
|
-
def self.fetch(id)
|
20
|
-
# Example: https://itunes.apple.com/lookup?id=284882215
|
21
|
-
|
20
|
+
def self.fetch(id, country = nil)
|
21
|
+
# Example: https://itunes.apple.com/lookup?id=284882215[&country=FR]
|
22
|
+
suffix = country.nil? ? nil : "&country=#{country}"
|
23
|
+
fetch_url("https://itunes.apple.com/lookup?id=#{id}#{suffix}")
|
22
24
|
end
|
23
25
|
|
24
|
-
def self.fetch_by_identifier(app_identifier)
|
25
|
-
# Example: http://itunes.apple.com/lookup?bundleId=net.sunapps.1
|
26
|
-
|
26
|
+
def self.fetch_by_identifier(app_identifier, country = nil)
|
27
|
+
# Example: http://itunes.apple.com/lookup?bundleId=net.sunapps.1[&country=FR]
|
28
|
+
suffix = country.nil? ? nil : "&country=#{country}"
|
29
|
+
fetch_url("https://itunes.apple.com/lookup?bundleId=#{app_identifier}#{suffix}")
|
27
30
|
end
|
28
|
-
|
29
31
|
|
30
32
|
# This method only fetches the bundle identifier of a given app
|
31
33
|
# @param id (int) The AppleID of the given app. This usually consists of 9 digits.
|
@@ -34,15 +36,14 @@ module FastlaneCore
|
|
34
36
|
self.fetch(id)['bundleId']
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
return nil if response['resultCount'] == 0
|
39
|
+
def self.fetch_url(url)
|
40
|
+
response = JSON.parse(open(url).read)
|
41
|
+
return nil if response['resultCount'] == 0
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
return response['results'].first
|
44
|
+
rescue
|
45
|
+
Helper.log.error "Could not find object '#{url}' using the iTunes API"
|
46
|
+
nil
|
47
|
+
end
|
47
48
|
end
|
48
|
-
end
|
49
|
+
end
|
@@ -2,7 +2,6 @@ require 'pty'
|
|
2
2
|
require 'shellwords'
|
3
3
|
require 'credentials_manager/password_manager'
|
4
4
|
|
5
|
-
|
6
5
|
module FastlaneCore
|
7
6
|
# The TransporterInputError occurs when you passed wrong inputs to the {Deliver::ItunesTransporter}
|
8
7
|
class TransporterInputError < StandardError
|
@@ -18,7 +17,7 @@ module FastlaneCore
|
|
18
17
|
OUTPUT_REGEX = />\s+(.+)/
|
19
18
|
RETURN_VALUE_REGEX = />\sDBG-X:\sReturning\s+(\d+)/
|
20
19
|
|
21
|
-
SKIP_ERRORS = [
|
20
|
+
SKIP_ERRORS = ["ERROR: An exception has occurred: Scheduling automatic restart in 1 minute"]
|
22
21
|
|
23
22
|
private_constant :ERROR_REGEX, :WARNING_REGEX, :OUTPUT_REGEX, :RETURN_VALUE_REGEX, :SKIP_ERRORS
|
24
23
|
|
@@ -53,12 +52,14 @@ module FastlaneCore
|
|
53
52
|
result = execute_transporter(command)
|
54
53
|
|
55
54
|
itmsp_path = File.join(dir, "#{app_id}.itmsp")
|
56
|
-
if result and File.directory?itmsp_path
|
55
|
+
if result and File.directory? itmsp_path
|
57
56
|
Helper.log.info "Successfully downloaded the latest package from iTunesConnect.".green
|
58
57
|
else
|
58
|
+
# rubocop:disable Style/CaseEquality
|
59
59
|
unless /^[0-9a-zA-Z\.\$\_]*$/ === @password
|
60
60
|
Helper.log.error "Password contains special characters, which may not be handled properly by iTMSTransporter. If you experience problems uploading to iTunes Connect, please consider changing your password to something with only alphanumeric characters."
|
61
61
|
end
|
62
|
+
# rubocop:enable Style/CaseEquality
|
62
63
|
Helper.log.fatal "Could not download metadata from iTunes Connect! It's probably related to your password or your internet connection."
|
63
64
|
end
|
64
65
|
|
@@ -94,115 +95,116 @@ module FastlaneCore
|
|
94
95
|
end
|
95
96
|
|
96
97
|
private
|
97
|
-
def execute_transporter(command)
|
98
|
-
@errors = []
|
99
|
-
@warnings = []
|
100
|
-
|
101
|
-
if defined?@@hide_transporter_output
|
102
|
-
# Show a one time message instead
|
103
|
-
Helper.log.info "Waiting for iTunes Connect transporter to be finished.".green
|
104
|
-
Helper.log.info "iTunes Transporter progress... this might take a few minutes...".green
|
105
|
-
end
|
106
98
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
parse_line(line) # this is where the parsing happens
|
111
|
-
end
|
112
|
-
end
|
113
|
-
rescue => ex
|
114
|
-
Helper.log.fatal(ex.to_s)
|
115
|
-
@errors << ex.to_s
|
116
|
-
end
|
99
|
+
def execute_transporter(command)
|
100
|
+
@errors = []
|
101
|
+
@warnings = []
|
117
102
|
|
118
|
-
|
119
|
-
|
120
|
-
|
103
|
+
if defined?@@hide_transporter_output
|
104
|
+
# Show a one time message instead
|
105
|
+
Helper.log.info "Waiting for iTunes Connect transporter to be finished.".green
|
106
|
+
Helper.log.info "iTunes Transporter progress... this might take a few minutes...".green
|
107
|
+
end
|
121
108
|
|
122
|
-
|
123
|
-
|
124
|
-
|
109
|
+
begin
|
110
|
+
PTY.spawn(command) do |stdin, stdout, pid|
|
111
|
+
stdin.each do |line|
|
112
|
+
parse_line(line) # this is where the parsing happens
|
113
|
+
end
|
125
114
|
end
|
115
|
+
rescue => ex
|
116
|
+
Helper.log.fatal(ex.to_s)
|
117
|
+
@errors << ex.to_s
|
118
|
+
end
|
126
119
|
|
127
|
-
|
120
|
+
if @warnings.count > 0
|
121
|
+
Helper.log.warn(@warnings.join("\n"))
|
128
122
|
end
|
129
123
|
|
130
|
-
|
131
|
-
|
124
|
+
if @errors.count > 0
|
125
|
+
Helper.log.error(@errors.join("\n"))
|
126
|
+
return false
|
127
|
+
end
|
132
128
|
|
133
|
-
|
129
|
+
true
|
130
|
+
end
|
134
131
|
|
135
|
-
|
136
|
-
|
137
|
-
# Those lines will not be handle like errors or warnings
|
132
|
+
def parse_line(line)
|
133
|
+
# Taken from https://github.com/sshaw/itunes_store_transporter/blob/master/lib/itunes/store/transporter/output_parser.rb
|
138
134
|
|
139
|
-
|
140
|
-
@errors << $1
|
141
|
-
Helper.log.error "[Transporter Error Output]: #{$1}".red
|
135
|
+
output_done = false
|
142
136
|
|
143
|
-
|
144
|
-
|
145
|
-
|
137
|
+
re = Regexp.union(SKIP_ERRORS)
|
138
|
+
if line.match(re)
|
139
|
+
# Those lines will not be handle like errors or warnings
|
146
140
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
Helper.log.fatal "You have to change the build number of your app to upload your ipa file"
|
151
|
-
end
|
141
|
+
elsif line =~ ERROR_REGEX
|
142
|
+
@errors << $1
|
143
|
+
Helper.log.error "[Transporter Error Output]: #{$1}".red
|
152
144
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
Helper.log.warn "[Transporter Warning Output]: #{$1}".yellow
|
157
|
-
output_done = true
|
158
|
-
end
|
145
|
+
# Check if it's a login error
|
146
|
+
if $1.include? "Your Apple ID or password was entered incorrectly" or
|
147
|
+
$1.include? "This Apple ID has been locked for security reasons"
|
159
148
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
Helper.log.error(@errors.join("\n").red)
|
165
|
-
raise "Return status of iTunes Transporter was #{$1}: #{@errors.join('\n')}".red
|
166
|
-
else
|
167
|
-
Helper.log.info "iTunes Transporter successfully finished its job".green
|
168
|
-
end
|
149
|
+
CredentialsManager::PasswordManager.shared_manager.password_seems_wrong unless Helper.is_test?
|
150
|
+
elsif $1.include? "Redundant Binary Upload. There already exists a binary upload with build"
|
151
|
+
Helper.log.fatal $1
|
152
|
+
Helper.log.fatal "You have to change the build number of your app to upload your ipa file"
|
169
153
|
end
|
170
154
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
end
|
155
|
+
output_done = true
|
156
|
+
elsif line =~ WARNING_REGEX
|
157
|
+
@warnings << $1
|
158
|
+
Helper.log.warn "[Transporter Warning Output]: #{$1}".yellow
|
159
|
+
output_done = true
|
177
160
|
end
|
178
161
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
"
|
183
|
-
"
|
184
|
-
"
|
185
|
-
|
186
|
-
"
|
187
|
-
|
162
|
+
if line =~ RETURN_VALUE_REGEX
|
163
|
+
if $1.to_i != 0
|
164
|
+
Helper.log.fatal "Transporter transfer failed.".red
|
165
|
+
Helper.log.warn(@warnings.join("\n").yellow)
|
166
|
+
Helper.log.error(@errors.join("\n").red)
|
167
|
+
raise "Return status of iTunes Transporter was #{$1}: #{@errors.join('\n')}".red
|
168
|
+
else
|
169
|
+
Helper.log.info "iTunes Transporter successfully finished its job".green
|
170
|
+
end
|
188
171
|
end
|
189
172
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
"
|
194
|
-
|
195
|
-
"-p '#{escaped_password(password)}'",
|
196
|
-
"-f '#{source}'",
|
197
|
-
ENV["DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS"], # that's here, because the user might overwrite the -t option
|
198
|
-
"-t 'Signiant'",
|
199
|
-
"-k 100000"
|
200
|
-
].join(' ')
|
173
|
+
if !defined?@@hide_transporter_output and line =~ OUTPUT_REGEX
|
174
|
+
# General logging for debug purposes
|
175
|
+
unless output_done
|
176
|
+
Helper.log.debug "[Transporter]: #{$1}"
|
177
|
+
end
|
201
178
|
end
|
179
|
+
end
|
202
180
|
|
203
|
-
|
204
|
-
|
205
|
-
|
181
|
+
def build_download_command(username, password, apple_id, destination = "/tmp")
|
182
|
+
[
|
183
|
+
'"' + Helper.transporter_path + '"',
|
184
|
+
"-m lookupMetadata",
|
185
|
+
"-u \"#{username}\"",
|
186
|
+
"-p '#{escaped_password(password)}'",
|
187
|
+
"-apple_id #{apple_id}",
|
188
|
+
"-destination '#{destination}'"
|
189
|
+
].join(' ')
|
190
|
+
end
|
191
|
+
|
192
|
+
def build_upload_command(username, password, source = "/tmp")
|
193
|
+
[
|
194
|
+
'"' + Helper.transporter_path + '"',
|
195
|
+
"-m upload",
|
196
|
+
"-u \"#{username}\"",
|
197
|
+
"-p '#{escaped_password(password)}'",
|
198
|
+
"-f '#{source}'",
|
199
|
+
ENV["DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS"], # that's here, because the user might overwrite the -t option
|
200
|
+
"-t 'Signiant'",
|
201
|
+
"-k 100000"
|
202
|
+
].join(' ')
|
203
|
+
end
|
204
|
+
|
205
|
+
def escaped_password(password)
|
206
|
+
Shellwords.escape(password)
|
207
|
+
end
|
206
208
|
|
207
209
|
end
|
208
210
|
end
|
@@ -3,4 +3,4 @@ module FastlaneCore
|
|
3
3
|
# These are all the languages which are available to use to upload app metadata and screenshots
|
4
4
|
ALL_LANGUAGES = ["da-DK", "de-DE", "el-GR", "en-AU", "en-CA", "en-GB", "en-US", "es-ES", "es-MX", "fi-FI", "fr-CA", "fr-FR", "id-ID", "it-IT", "ja-JP", "ko-KR", "ms-MY", "nl-NL", "no-NO", "pt-BR", "pt-PT", "ru-RU", "sv-SE", "th-TH", "tr-TR", "vi-VI", "cmn-Hans", "cmn-Hant"]
|
5
5
|
end
|
6
|
-
end
|
6
|
+
end
|
@@ -24,7 +24,7 @@ module FastlaneCore
|
|
24
24
|
def parse(path)
|
25
25
|
require 'plist'
|
26
26
|
|
27
|
-
plist = Plist
|
27
|
+
plist = Plist.parse_xml(`security cms -D -i '#{path}'`)
|
28
28
|
if (plist || []).count > 5
|
29
29
|
plist
|
30
30
|
else
|
@@ -57,9 +57,9 @@ module FastlaneCore
|
|
57
57
|
raise "Failed installation of provisioning profile at location: '#{destination}'".red
|
58
58
|
end
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
true
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
|
-
end
|
65
|
+
end
|
@@ -11,7 +11,7 @@ module FastlaneCore
|
|
11
11
|
return if ENV["FASTLANE_SKIP_UPDATE_CHECK"]
|
12
12
|
|
13
13
|
@start_time = Time.now
|
14
|
-
|
14
|
+
|
15
15
|
Thread.new do
|
16
16
|
begin
|
17
17
|
server_results[gem_name] = fetch_latest(gem_name)
|
@@ -34,7 +34,7 @@ module FastlaneCore
|
|
34
34
|
begin
|
35
35
|
finished_running(gem_name)
|
36
36
|
rescue
|
37
|
-
|
37
|
+
# we don't want to show a stack trace if something goes wrong
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -69,4 +69,4 @@ module FastlaneCore
|
|
69
69
|
Excon.post(url)
|
70
70
|
end
|
71
71
|
end
|
72
|
-
end
|
72
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.15.
|
4
|
+
version: 0.15.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|