fastlane 2.69.0.beta.20171212010004 → 2.69.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/deliver/lib/assets/DeliverfileDefault.swift +13 -0
- data/deliver/lib/deliver/commands_generator.rb +2 -1
- data/deliver/lib/deliver/options.rb +8 -3
- data/deliver/lib/deliver/setup.rb +19 -3
- data/fastlane/lib/assets/AppfileTemplate.swift +8 -0
- data/fastlane/lib/assets/DefaultFastfileTemplate.swift +72 -0
- data/fastlane/lib/fastlane.rb +6 -0
- data/fastlane/lib/fastlane/.DS_Store +0 -0
- data/fastlane/lib/fastlane/action.rb +13 -0
- data/fastlane/lib/fastlane/actions/adb.rb +4 -0
- data/fastlane/lib/fastlane/actions/appium.rb +2 -0
- data/fastlane/lib/fastlane/actions/bundle_install.rb +2 -0
- data/fastlane/lib/fastlane/actions/carthage.rb +12 -24
- data/fastlane/lib/fastlane/actions/changelog_from_git_commits.rb +5 -0
- data/fastlane/lib/fastlane/actions/cocoapods.rb +2 -1
- data/fastlane/lib/fastlane/actions/commit_github_file.rb +4 -0
- data/fastlane/lib/fastlane/actions/environment_variable.rb +73 -0
- data/fastlane/lib/fastlane/actions/get_version_number.rb +4 -4
- data/fastlane/lib/fastlane/actions/increment_build_number.rb +4 -0
- data/fastlane/lib/fastlane/actions/increment_version_number.rb +4 -0
- data/fastlane/lib/fastlane/actions/is_ci.rb +4 -0
- data/fastlane/lib/fastlane/actions/last_git_commit.rb +4 -0
- data/fastlane/lib/fastlane/actions/last_git_tag.rb +4 -0
- data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +4 -0
- data/fastlane/lib/fastlane/actions/modify_services.rb +1 -0
- data/fastlane/lib/fastlane/actions/number_of_commits.rb +4 -0
- data/fastlane/lib/fastlane/actions/podio_item.rb +1 -0
- data/fastlane/lib/fastlane/actions/prompt.rb +4 -0
- data/fastlane/lib/fastlane/actions/read_podspec.rb +4 -0
- data/fastlane/lib/fastlane/actions/register_device.rb +4 -0
- data/fastlane/lib/fastlane/actions/register_devices.rb +1 -0
- data/fastlane/lib/fastlane/actions/rocket.rb +4 -0
- data/fastlane/lib/fastlane/actions/set_github_release.rb +4 -0
- data/fastlane/lib/fastlane/actions/sh.rb +5 -0
- data/fastlane/lib/fastlane/actions/slather.rb +14 -0
- data/fastlane/lib/fastlane/actions/update_urban_airship_configuration.rb +1 -0
- data/fastlane/lib/fastlane/actions/xcode_install.rb +4 -0
- data/fastlane/lib/fastlane/actions/xcode_server_get_assets.rb +4 -0
- data/fastlane/lib/fastlane/actions/zip.rb +4 -0
- data/fastlane/lib/fastlane/boolean.rb +5 -0
- data/fastlane/lib/fastlane/command_line_handler.rb +6 -1
- data/fastlane/lib/fastlane/commands_generator.rb +40 -1
- data/fastlane/lib/fastlane/fast_file.rb +5 -1
- data/fastlane/lib/fastlane/lane_list.rb +67 -4
- data/fastlane/lib/fastlane/lane_manager.rb +3 -69
- data/fastlane/lib/fastlane/lane_manager_base.rb +124 -0
- data/fastlane/lib/fastlane/runner.rb +2 -2
- data/fastlane/lib/fastlane/server/command.rb +70 -0
- data/fastlane/lib/fastlane/server/command_executor.rb +9 -0
- data/fastlane/lib/fastlane/server/socket_server.rb +212 -0
- data/fastlane/lib/fastlane/server/socket_server_action_command_executor.rb +100 -0
- data/fastlane/lib/fastlane/setup/setup.rb +7 -2
- data/fastlane/lib/fastlane/setup/setup_ios.rb +72 -15
- data/fastlane/lib/fastlane/swift_fastlane_api_generator.rb +265 -0
- data/fastlane/lib/fastlane/swift_fastlane_function.rb +342 -0
- data/fastlane/lib/fastlane/swift_lane_manager.rb +246 -0
- data/fastlane/lib/fastlane/tools.rb +13 -0
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane_core/lib/fastlane_core.rb +3 -0
- data/fastlane_core/lib/fastlane_core/analytics/action_launch_context.rb +6 -3
- data/fastlane_core/lib/fastlane_core/analytics/analytics_session.rb +7 -0
- data/fastlane_core/lib/fastlane_core/configuration/commander_generator.rb +13 -0
- data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +33 -2
- data/fastlane_core/lib/fastlane_core/fastlane_folder.rb +32 -0
- data/gym/lib/assets/GymfileTemplate.swift +13 -0
- data/gym/lib/gym/commands_generator.rb +14 -2
- data/gym/lib/gym/generators/build_command_generator.rb +2 -2
- data/gym/lib/gym/options.rb +11 -0
- data/match/lib/assets/MatchfileTemplate.swift +9 -0
- data/match/lib/match/commands_generator.rb +9 -3
- data/match/lib/match/options.rb +1 -0
- data/match/lib/match/setup.rb +6 -2
- data/precheck/lib/.DS_Store +0 -0
- data/precheck/lib/assets/PrecheckfileTemplate +1 -1
- data/precheck/lib/assets/PrecheckfileTemplate.swift +19 -0
- data/precheck/lib/precheck/commands_generator.rb +13 -2
- data/scan/lib/assets/ScanfileTemplate.swift +13 -0
- data/scan/lib/scan/commands_generator.rb +14 -2
- data/scan/lib/scan/options.rb +6 -0
- data/screengrab/lib/assets/ScreengrabfileTemplate.swift +15 -0
- data/screengrab/lib/screengrab/commands_generator.rb +2 -1
- data/screengrab/lib/screengrab/setup.rb +9 -3
- data/snapshot/lib/assets/SnapfileTemplate.swift +41 -0
- data/snapshot/lib/snapshot/commands_generator.rb +2 -1
- data/snapshot/lib/snapshot/setup.rb +9 -3
- data/spaceship/lib/spaceship/client.rb +4 -1
- metadata +38 -16
@@ -0,0 +1,342 @@
|
|
1
|
+
module Fastlane
|
2
|
+
class SwiftFunction
|
3
|
+
attr_accessor :function_name
|
4
|
+
attr_accessor :return_type
|
5
|
+
attr_accessor :param_names
|
6
|
+
attr_accessor :param_descriptions
|
7
|
+
attr_accessor :param_default_values
|
8
|
+
attr_accessor :param_optionality_values
|
9
|
+
attr_accessor :param_type_overrides
|
10
|
+
attr_accessor :reserved_words
|
11
|
+
attr_accessor :default_values_to_ignore
|
12
|
+
|
13
|
+
def initialize(action_name: nil, keys: nil, key_descriptions: nil, key_default_values: nil, key_optionality_values: nil, key_type_overrides: nil, return_type: nil)
|
14
|
+
@function_name = action_name
|
15
|
+
@param_names = keys
|
16
|
+
@param_descriptions = key_descriptions
|
17
|
+
@param_default_values = key_default_values
|
18
|
+
@param_optionality_values = key_optionality_values
|
19
|
+
@return_type = return_type
|
20
|
+
@param_type_overrides = key_type_overrides
|
21
|
+
|
22
|
+
# rubocop:disable LineLength
|
23
|
+
# class instance?
|
24
|
+
@reserved_words = %w[associativity break case catch class continue convenience default deinit didSet do else enum extension fallthrough false final for func get guard if in infix init inout internal lazy let mutating nil operator override postfix precedence prefix private public repeat required return self set static struct subscript super switch throws true try var weak where while willSet].to_set
|
25
|
+
# rubocop:enable LineLength
|
26
|
+
|
27
|
+
@default_values_to_ignore = {
|
28
|
+
"cert" => ["keychain_path"].to_set,
|
29
|
+
"set_github_release" => ["api_token"].to_set,
|
30
|
+
"github_api" => ["api_token"].to_set,
|
31
|
+
"create_pull_request" => ["api_token", "head", "api_url"].to_set,
|
32
|
+
"commit_github_file" => ["api_token"].to_set,
|
33
|
+
"verify_xcode" => ["xcode_path"].to_set,
|
34
|
+
"produce" => ["sku"].to_set,
|
35
|
+
"create_app_online" => ["sku"].to_set,
|
36
|
+
"screengrab" => ["android_home"].to_set
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def ignore_default_value?(function_name: nil, param_name: nil)
|
41
|
+
action_set = @default_values_to_ignore[function_name]
|
42
|
+
unless action_set
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
|
46
|
+
return action_set.include?(param_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sanitize_reserved_word(word: nil)
|
50
|
+
unless @reserved_words.include?(word)
|
51
|
+
return word
|
52
|
+
end
|
53
|
+
return "`#{word}`"
|
54
|
+
end
|
55
|
+
|
56
|
+
def return_declaration
|
57
|
+
expected_type = swift_type_for_return_type
|
58
|
+
unless expected_type.to_s.length > 0
|
59
|
+
return ""
|
60
|
+
end
|
61
|
+
|
62
|
+
return " -> #{expected_type}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def swift_type_for_return_type
|
66
|
+
unless @return_type
|
67
|
+
return ""
|
68
|
+
end
|
69
|
+
|
70
|
+
case @return_type
|
71
|
+
when :string
|
72
|
+
return "String"
|
73
|
+
when :array_of_strings
|
74
|
+
return "[String]"
|
75
|
+
when :hash_of_strings
|
76
|
+
return "[String : String]"
|
77
|
+
when :bool
|
78
|
+
return "Bool"
|
79
|
+
when :int
|
80
|
+
return "Int"
|
81
|
+
else
|
82
|
+
return ""
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def camel_case_lower(string: nil)
|
87
|
+
string.split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
|
88
|
+
end
|
89
|
+
|
90
|
+
def determine_type_from_override(type_override: nil, default_type: nil)
|
91
|
+
if type_override == Array
|
92
|
+
return "[String]"
|
93
|
+
elsif type_override == Hash
|
94
|
+
return "[String : Any]"
|
95
|
+
elsif type_override == Integer
|
96
|
+
return "Int"
|
97
|
+
elsif type_override == Boolean
|
98
|
+
return "Bool"
|
99
|
+
elsif type_override == :string_callback
|
100
|
+
return "((String) -> Void)"
|
101
|
+
else
|
102
|
+
return default_type
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def override_default_value_if_not_correct_type(param_name: nil, param_type: nil, default_value: nil)
|
107
|
+
default_value = nil if ignore_default_value?(function_name: @function_name, param_name: param_name)
|
108
|
+
|
109
|
+
return "[]" if param_type == "[String]" && default_value == ""
|
110
|
+
return "{_ in }" if param_type == "((String) -> Void)"
|
111
|
+
|
112
|
+
return default_value
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_type(param: nil, default_value: nil, optional: nil, param_type_override: nil)
|
116
|
+
unless param_type_override.nil?
|
117
|
+
type = determine_type_from_override(type_override: param_type_override)
|
118
|
+
end
|
119
|
+
type ||= "String"
|
120
|
+
|
121
|
+
optional_specifier = ""
|
122
|
+
# if we are optional and don't have a default value, we'll need to use ?
|
123
|
+
optional_specifier = "?" if (optional && default_value.nil?) && type != "((String) -> Void)"
|
124
|
+
|
125
|
+
if optional && ignore_default_value?(function_name: @function_name, param_name: param)
|
126
|
+
optional_specifier = "?"
|
127
|
+
end
|
128
|
+
|
129
|
+
# If we have a default value of true or false, we can infer it is a Bool
|
130
|
+
if default_value.class == FalseClass
|
131
|
+
type = "Bool"
|
132
|
+
elsif default_value.class == TrueClass
|
133
|
+
type = "Bool"
|
134
|
+
elsif default_value.kind_of?(Array)
|
135
|
+
type = "[String]"
|
136
|
+
end
|
137
|
+
return "#{type}#{optional_specifier}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def parameters
|
141
|
+
unless @param_names
|
142
|
+
return ""
|
143
|
+
end
|
144
|
+
|
145
|
+
param_names_and_types = @param_names.zip(param_default_values, param_optionality_values, param_type_overrides).map do |param, default_value, optional, param_type_override|
|
146
|
+
type = get_type(param: param, default_value: default_value, optional: optional, param_type_override: param_type_override)
|
147
|
+
|
148
|
+
unless default_value.nil?
|
149
|
+
if type == "[String : Any]"
|
150
|
+
# we can't handle default values for Hashes, yet
|
151
|
+
default_value = "[:]"
|
152
|
+
elsif type != "Bool" && type != "[String]" && type != "Int" && type != "((String) -> Void)"
|
153
|
+
default_value = "\"#{default_value}\""
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# if we don't have a default value, but the param is optional, set a default value in Swift to be nil
|
158
|
+
if optional && default_value.nil?
|
159
|
+
default_value = "nil"
|
160
|
+
end
|
161
|
+
|
162
|
+
# sometimes we get to the point where we have a default value but its type is wrong
|
163
|
+
# so we need to correct that because [String] = "" is not valid swift
|
164
|
+
default_value = override_default_value_if_not_correct_type(param_type: type, param_name: param, default_value: default_value)
|
165
|
+
|
166
|
+
param = camel_case_lower(string: param)
|
167
|
+
param = sanitize_reserved_word(word: param)
|
168
|
+
|
169
|
+
if default_value.nil?
|
170
|
+
"#{param}: #{type}"
|
171
|
+
else
|
172
|
+
"#{param}: #{type} = #{default_value}"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
return param_names_and_types
|
177
|
+
end
|
178
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
179
|
+
|
180
|
+
def swift_code
|
181
|
+
function_name = camel_case_lower(string: self.function_name)
|
182
|
+
function_return_declaration = self.return_declaration
|
183
|
+
discardable_result = function_return_declaration.length > 0 ? "@discardableResult " : ''
|
184
|
+
|
185
|
+
# Calculate the necessary indent to line up parameter names on new lines
|
186
|
+
# with the first parameter after the opening paren following the function name.
|
187
|
+
# i.e.: @discardableResult func someFunctionName(firstParameter: T
|
188
|
+
# secondParameter: T)
|
189
|
+
# This just creates a string with as many spaces are necessary given whether or not
|
190
|
+
# the function has a 'discardableResult' annotation, the 'func' keyword, function name
|
191
|
+
# and the opening paren.
|
192
|
+
function_keyword_definition = 'func '
|
193
|
+
open_paren = '('
|
194
|
+
closed_paren = ')'
|
195
|
+
indent = ' ' * (discardable_result.length + function_name.length + function_keyword_definition.length + open_paren.length)
|
196
|
+
params = self.parameters.join(",\n#{indent}")
|
197
|
+
|
198
|
+
return "#{discardable_result}#{function_keyword_definition}#{function_name}#{open_paren}#{params}#{closed_paren}#{function_return_declaration} {\n#{self.implementation}\n}"
|
199
|
+
end
|
200
|
+
|
201
|
+
def build_argument_list
|
202
|
+
unless @param_names
|
203
|
+
return "[]" # return empty list for argument
|
204
|
+
end
|
205
|
+
|
206
|
+
argument_object_strings = @param_names.zip(param_type_overrides).map do |name, type_override|
|
207
|
+
sanitized_name = camel_case_lower(string: name)
|
208
|
+
sanitized_name = sanitize_reserved_word(word: sanitized_name)
|
209
|
+
type_string = type_override == :string_callback ? ", type: .stringClosure" : nil
|
210
|
+
|
211
|
+
"RubyCommand.Argument(name: \"#{name}\", value: #{sanitized_name}#{type_string})"
|
212
|
+
end
|
213
|
+
return argument_object_strings
|
214
|
+
end
|
215
|
+
|
216
|
+
def return_statement
|
217
|
+
returned_object = "runner.executeCommand(command)"
|
218
|
+
case @return_type
|
219
|
+
when :array_of_strings
|
220
|
+
returned_object = "parseArray(fromString: #{returned_object})"
|
221
|
+
when :hash_of_strings
|
222
|
+
returned_object = "parseDictionary(fromString: #{returned_object})"
|
223
|
+
when :bool
|
224
|
+
returned_object = "parseBool(fromString: #{returned_object})"
|
225
|
+
when :int
|
226
|
+
returned_object = "parseInt(fromString: #{returned_object})"
|
227
|
+
end
|
228
|
+
|
229
|
+
expected_type = swift_type_for_return_type
|
230
|
+
|
231
|
+
return_string = "_ = "
|
232
|
+
if expected_type.length > 0
|
233
|
+
return_string = "return "
|
234
|
+
end
|
235
|
+
return "#{return_string}#{returned_object}"
|
236
|
+
end
|
237
|
+
|
238
|
+
def implementation
|
239
|
+
args = build_argument_list
|
240
|
+
|
241
|
+
implm = " let command = RubyCommand(commandID: \"\", methodName: \"#{@function_name}\", className: nil, args: ["
|
242
|
+
# Get the indent of the first argument in the list to give each
|
243
|
+
# subsequent argument it's own line with proper indenting
|
244
|
+
indent = ' ' * implm.length
|
245
|
+
implm += args.join(",\n#{indent}")
|
246
|
+
implm += "])\n"
|
247
|
+
return implm + " #{return_statement}"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
class ToolSwiftFunction < SwiftFunction
|
252
|
+
def protocol_name
|
253
|
+
function_name = camel_case_lower(string: self.function_name)
|
254
|
+
return function_name.capitalize + "fileProtocol"
|
255
|
+
end
|
256
|
+
|
257
|
+
def class_name
|
258
|
+
function_name = camel_case_lower(string: self.function_name)
|
259
|
+
return function_name.capitalize + "file"
|
260
|
+
end
|
261
|
+
|
262
|
+
def swift_vars
|
263
|
+
unless @param_names
|
264
|
+
return []
|
265
|
+
end
|
266
|
+
swift_vars = @param_names.zip(param_default_values, param_optionality_values, param_type_overrides).map do |param, default_value, optional, param_type_override|
|
267
|
+
type = get_type(param: param, default_value: default_value, optional: optional, param_type_override: param_type_override)
|
268
|
+
|
269
|
+
param = camel_case_lower(string: param)
|
270
|
+
param = sanitize_reserved_word(word: param)
|
271
|
+
static_var_for_parameter_name = param
|
272
|
+
" var #{static_var_for_parameter_name}: #{type} { get }"
|
273
|
+
end
|
274
|
+
|
275
|
+
return swift_vars
|
276
|
+
end
|
277
|
+
|
278
|
+
def swift_default_implementations
|
279
|
+
unless @param_names
|
280
|
+
return []
|
281
|
+
end
|
282
|
+
|
283
|
+
swift_implementations = @param_names.zip(param_default_values, param_optionality_values, param_type_overrides).map do |param, default_value, optional, param_type_override|
|
284
|
+
type = get_type(param: param, default_value: default_value, optional: optional, param_type_override: param_type_override)
|
285
|
+
|
286
|
+
default_value = nil if ignore_default_value?(function_name: @function_name, param_name: param)
|
287
|
+
|
288
|
+
param = camel_case_lower(string: param)
|
289
|
+
param = sanitize_reserved_word(word: param)
|
290
|
+
var_for_parameter_name = param
|
291
|
+
|
292
|
+
unless default_value.nil?
|
293
|
+
if type == "Bool" || type == "[String]" || type == "Int" || default_value.kind_of?(Array)
|
294
|
+
default_value = default_value.to_s
|
295
|
+
else
|
296
|
+
default_value = "\"#{default_value}\""
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# if we don't have a default value, but the param is options, just set a default value to nil
|
301
|
+
if optional && default_value.nil?
|
302
|
+
default_value = "nil"
|
303
|
+
end
|
304
|
+
|
305
|
+
# if we don't have a default value still, we need to assign them based on type
|
306
|
+
if type == "String"
|
307
|
+
default_value ||= "\"\""
|
308
|
+
end
|
309
|
+
|
310
|
+
if type == "Bool"
|
311
|
+
default_value ||= "false"
|
312
|
+
end
|
313
|
+
|
314
|
+
if type == "[String]"
|
315
|
+
default_value ||= "[]"
|
316
|
+
end
|
317
|
+
|
318
|
+
" var #{var_for_parameter_name}: #{type} { return #{default_value} }"
|
319
|
+
end
|
320
|
+
|
321
|
+
return swift_implementations
|
322
|
+
end
|
323
|
+
|
324
|
+
def parameters
|
325
|
+
unless @param_names
|
326
|
+
return ""
|
327
|
+
end
|
328
|
+
|
329
|
+
param_names_and_types = @param_names.zip(param_default_values, param_optionality_values, param_type_overrides).map do |param, default_value, optional, param_type_override|
|
330
|
+
type = get_type(param: param, default_value: default_value, optional: optional, param_type_override: param_type_override)
|
331
|
+
|
332
|
+
param = camel_case_lower(string: param)
|
333
|
+
param = sanitize_reserved_word(word: param)
|
334
|
+
static_var_for_parameter_name = param
|
335
|
+
|
336
|
+
"#{param}: #{type} = #{self.class_name.downcase}.#{static_var_for_parameter_name}"
|
337
|
+
end
|
338
|
+
|
339
|
+
return param_names_and_types
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require_relative 'lane_manager_base.rb'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
class SwiftLaneManager < LaneManagerBase
|
5
|
+
# @param lane_name The name of the lane to execute
|
6
|
+
# @param parameters [Hash] The parameters passed from the command line to the lane
|
7
|
+
# @param env Dot Env Information
|
8
|
+
def self.cruise_lane(lane, parameters = nil, env = nil)
|
9
|
+
UI.user_error!("lane must be a string") unless lane.kind_of?(String) or lane.nil?
|
10
|
+
UI.user_error!("parameters must be a hash") unless parameters.kind_of?(Hash) or parameters.nil?
|
11
|
+
|
12
|
+
# xcodeproj has a bug in certain versions that causes it to change directories
|
13
|
+
# and not return to the original working directory
|
14
|
+
# https://github.com/CocoaPods/Xcodeproj/issues/426
|
15
|
+
# Setting this environment variable causes xcodeproj to work around the problem
|
16
|
+
ENV["FORK_XCODE_WRITING"] = "true"
|
17
|
+
|
18
|
+
FastlaneCore.session.is_fastfile = true
|
19
|
+
|
20
|
+
load_dot_env(env)
|
21
|
+
|
22
|
+
started = Time.now
|
23
|
+
e = nil
|
24
|
+
begin
|
25
|
+
self.ensure_runner_built!
|
26
|
+
socket_thread = self.start_socket_thread
|
27
|
+
sleep(0.250) while socket_thread[:ready].nil?
|
28
|
+
# wait on socket_thread to be in ready state, then start the runner thread
|
29
|
+
runner_thread = self.cruise_swift_lane_in_thread(lane, parameters)
|
30
|
+
|
31
|
+
runner_thread.join
|
32
|
+
socket_thread.join
|
33
|
+
rescue Exception => ex # rubocop:disable Lint/RescueException
|
34
|
+
# We also catch Exception, since the implemented action might send a SystemExit signal
|
35
|
+
# (or similar). We still want to catch that, since we want properly finish running fastlane
|
36
|
+
# Tested with `xcake`, which throws a `Xcake::Informative` object
|
37
|
+
|
38
|
+
print_lane_context
|
39
|
+
UI.error ex.to_s if ex.kind_of?(StandardError) # we don't want to print things like 'system exit'
|
40
|
+
e = ex
|
41
|
+
end
|
42
|
+
|
43
|
+
duration = ((Time.now - started) / 60.0).round
|
44
|
+
|
45
|
+
finish_fastlane(nil, duration, e)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.display_lanes
|
49
|
+
self.ensure_runner_built!
|
50
|
+
Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lanes))
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.cruise_swift_lane_in_thread(lane, parameters = nil)
|
54
|
+
if parameters.nil?
|
55
|
+
parameters = {}
|
56
|
+
end
|
57
|
+
|
58
|
+
parameter_string = ""
|
59
|
+
parameters.each do |key, value|
|
60
|
+
parameter_string += " #{key} #{value}"
|
61
|
+
end
|
62
|
+
|
63
|
+
if FastlaneCore::Globals.verbose?
|
64
|
+
parameter_string += " logMode verbose"
|
65
|
+
end
|
66
|
+
|
67
|
+
return Thread.new do
|
68
|
+
Actions.sh(%(#{FastlaneCore::FastlaneFolder.swift_runner_path} lane #{lane}#{parameter_string} > /dev/null))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.swap_paths_in_target(target: nil, file_refs_to_swap: nil, expected_path_to_replacement_path_tuples: nil)
|
73
|
+
made_project_updates = false
|
74
|
+
file_refs_to_swap.each do |file_ref|
|
75
|
+
expected_path_to_replacement_path_tuples.each do |preinstalled_config_relative_path, user_config_relative_path|
|
76
|
+
next unless file_ref.path == preinstalled_config_relative_path
|
77
|
+
|
78
|
+
file_ref.path = user_config_relative_path
|
79
|
+
made_project_updates = true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return made_project_updates
|
83
|
+
end
|
84
|
+
|
85
|
+
# Find all the config files we care about (Deliverfile, Gymfile, etc), and build tuples of what file we'll look for
|
86
|
+
# in the Xcode project, and what file paths we'll need to swap (since we have to inject the user's configs)
|
87
|
+
#
|
88
|
+
# Return a mapping of what file paths we're looking => new file pathes we'll need to inject
|
89
|
+
def self.collect_tool_paths_for_replacement(all_user_tool_file_paths: nil, look_for_new_configs: nil)
|
90
|
+
new_user_tool_file_paths = all_user_tool_file_paths.select do |user_config, preinstalled_config_relative_path, user_config_relative_path|
|
91
|
+
if look_for_new_configs
|
92
|
+
File.exist?(user_config)
|
93
|
+
else
|
94
|
+
!File.exist?(user_config)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Now strip out the fastlane-relative path and leave us with xcodeproj relative paths
|
99
|
+
new_user_tool_file_paths = new_user_tool_file_paths.map do |user_config, preinstalled_config_relative_path, user_config_relative_path|
|
100
|
+
if look_for_new_configs
|
101
|
+
[preinstalled_config_relative_path, user_config_relative_path]
|
102
|
+
else
|
103
|
+
[user_config_relative_path, preinstalled_config_relative_path]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return new_user_tool_file_paths
|
107
|
+
end
|
108
|
+
|
109
|
+
# open and return the swift project
|
110
|
+
def self.runner_project
|
111
|
+
runner_project_path = FastlaneCore::FastlaneFolder.swift_runner_project_path
|
112
|
+
require 'xcodeproj'
|
113
|
+
project = Xcodeproj::Project.open(runner_project_path)
|
114
|
+
return project
|
115
|
+
end
|
116
|
+
|
117
|
+
# return the FastlaneRunner build target
|
118
|
+
def self.target_for_fastlane_runner_project(runner_project: nil)
|
119
|
+
fastlane_runner_array = runner_project.targets.select do |target|
|
120
|
+
target.name == "FastlaneRunner"
|
121
|
+
end
|
122
|
+
|
123
|
+
# get runner target
|
124
|
+
runner_target = fastlane_runner_array.first
|
125
|
+
return runner_target
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.target_source_file_refs(target: nil)
|
129
|
+
return target.source_build_phase.files.to_a.map(&:file_ref)
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.first_time_setup
|
133
|
+
setup_message = ["fastlane is now configured to use a swift-based Fastfile (Fastfile.swift) 🦅"]
|
134
|
+
setup_message << "To edit your new Fastfile.swift, type: `open #{FastlaneCore::FastlaneFolder.swift_runner_project_path}`"
|
135
|
+
|
136
|
+
# Go through and link up whatever we generated during `fastlane init swift` so the user can edit them easily
|
137
|
+
self.link_user_configs_to_project(updated_message: setup_message.join("\n"))
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.link_user_configs_to_project(updated_message: nil)
|
141
|
+
tool_files_folder = FastlaneCore::FastlaneFolder.path
|
142
|
+
|
143
|
+
# All the tools that could have <tool name>file.swift their paths, and where we expect to find the user's tool files.
|
144
|
+
all_user_tool_file_paths = TOOL_CONFIG_FILES.map do |tool_name|
|
145
|
+
[
|
146
|
+
File.join(tool_files_folder, "#{tool_name}.swift"),
|
147
|
+
"../#{tool_name}.swift",
|
148
|
+
"../../#{tool_name}.swift"
|
149
|
+
]
|
150
|
+
end
|
151
|
+
|
152
|
+
# Tool files the user now provides
|
153
|
+
new_user_tool_file_paths = collect_tool_paths_for_replacement(all_user_tool_file_paths: all_user_tool_file_paths, look_for_new_configs: true)
|
154
|
+
|
155
|
+
# Tool files we provide AND the user doesn't provide
|
156
|
+
user_tool_files_possibly_removed = collect_tool_paths_for_replacement(all_user_tool_file_paths: all_user_tool_file_paths, look_for_new_configs: false)
|
157
|
+
|
158
|
+
fastlane_runner_project = self.runner_project
|
159
|
+
runner_target = target_for_fastlane_runner_project(runner_project: fastlane_runner_project)
|
160
|
+
target_file_refs = target_source_file_refs(target: runner_target)
|
161
|
+
|
162
|
+
# Swap in all new user supplied configs into the project
|
163
|
+
project_modified = swap_paths_in_target(
|
164
|
+
target: runner_target,
|
165
|
+
file_refs_to_swap: target_file_refs,
|
166
|
+
expected_path_to_replacement_path_tuples: new_user_tool_file_paths
|
167
|
+
)
|
168
|
+
|
169
|
+
# Swap out any configs the user has removed, inserting fastlane defaults
|
170
|
+
project_modified ||= swap_paths_in_target(
|
171
|
+
target: runner_target,
|
172
|
+
file_refs_to_swap: target_file_refs,
|
173
|
+
expected_path_to_replacement_path_tuples: user_tool_files_possibly_removed
|
174
|
+
)
|
175
|
+
|
176
|
+
if project_modified
|
177
|
+
fastlane_runner_project.save
|
178
|
+
updated_message ||= "Updated #{FastlaneCore::FastlaneFolder.swift_runner_project_path}"
|
179
|
+
UI.success(updated_message)
|
180
|
+
else
|
181
|
+
UI.success("FastlaneSwiftRunner project is up-to-date")
|
182
|
+
end
|
183
|
+
|
184
|
+
return project_modified
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.start_socket_thread
|
188
|
+
require 'fastlane/server/socket_server'
|
189
|
+
require 'fastlane/server/socket_server_action_command_executor'
|
190
|
+
|
191
|
+
return Thread.new do
|
192
|
+
command_executor = SocketServerActionCommandExecutor.new
|
193
|
+
server = Fastlane::SocketServer.new(command_executor: command_executor)
|
194
|
+
server.start
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.ensure_runner_built!
|
199
|
+
UI.verbose("Checking for new user-provided tool configuration files")
|
200
|
+
# if self.link_user_configs_to_project returns true, that means we need to rebuild the runner
|
201
|
+
runner_needs_building = self.link_user_configs_to_project
|
202
|
+
|
203
|
+
if FastlaneCore::FastlaneFolder.swift_runner_built?
|
204
|
+
runner_last_modified_age = File.mtime(FastlaneCore::FastlaneFolder.swift_runner_path).to_i
|
205
|
+
fastfile_last_modified_age = File.mtime(FastlaneCore::FastlaneFolder.fastfile_path).to_i
|
206
|
+
|
207
|
+
if runner_last_modified_age < fastfile_last_modified_age
|
208
|
+
# It's older than the Fastfile, so build it again
|
209
|
+
UI.verbose("Found changes to user's Fastfile.swift, setting re-build runner flag")
|
210
|
+
runner_needs_building = true
|
211
|
+
end
|
212
|
+
else
|
213
|
+
# Runner isn't built yet, so build it
|
214
|
+
UI.verbose("No runner found, setting re-build runner flag")
|
215
|
+
runner_needs_building = true
|
216
|
+
end
|
217
|
+
|
218
|
+
if runner_needs_building
|
219
|
+
self.build_runner!
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.build_runner!
|
224
|
+
UI.verbose("Building FastlaneSwiftRunner")
|
225
|
+
require 'fastlane_core'
|
226
|
+
require 'gym'
|
227
|
+
require 'gym/generators/build_command_generator'
|
228
|
+
|
229
|
+
project_options = {
|
230
|
+
project: FastlaneCore::FastlaneFolder.swift_runner_project_path,
|
231
|
+
skip_archive: true
|
232
|
+
}
|
233
|
+
Gym.config = FastlaneCore::Configuration.create(Gym::Options.available_options, project_options)
|
234
|
+
build_command = Gym::BuildCommandGenerator.generate
|
235
|
+
|
236
|
+
FastlaneCore::CommandExecutor.execute(
|
237
|
+
command: build_command,
|
238
|
+
print_all: false,
|
239
|
+
print_command: !Gym.config[:silent],
|
240
|
+
error: proc do |output|
|
241
|
+
ErrorHandler.handle_build_error(output)
|
242
|
+
end
|
243
|
+
)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|