Class: Fastlane::Runner
- Inherits:
-
Object
- Object
- Fastlane::Runner
- Defined in:
- fastlane/lib/fastlane/runner.rb
Defined Under Namespace
Classes: LaneNotAvailableError
Instance Attribute Summary collapse
-
#current_lane ⇒ Object
Symbol for the current lane.
-
#current_platform ⇒ Object
Symbol for the current platform.
-
#lanes ⇒ Hash
All the lanes available, first the platform, then the lane.
Instance Method Summary collapse
- #action_completed(action_name, status: nil, exception: nil) ⇒ Object
- #add_lane(lane, override = false) ⇒ Object
- #after_all_blocks ⇒ Object
- #after_each_blocks ⇒ Object
-
#available_lanes(filter_platform = nil) ⇒ Object
An array of lanes (platform lane_name) to print them out to the user.
- #before_all_blocks ⇒ Object
- #before_each_blocks ⇒ Object
-
#class_reference_from_action_alias(method_sym) ⇒ Object
Pass a action alias symbol (e.g. :enable_automatic_code_signing) and this method will return a reference to the action class if it exists.
-
#class_reference_from_action_name(method_sym) ⇒ Object
Pass a action symbol (e.g. :deliver or :commit_version_bump) and this method will return a reference to the action class if it exists.
- #did_finish ⇒ Object
- #error_blocks ⇒ Object
-
#execute(lane, platform = nil, parameters = nil) ⇒ Object
This will take care of executing one lane.
- #execute_action(method_sym, class_ref, arguments, custom_dir: nil, from_action: false) ⇒ Object
- #execute_flow_block(block, current_platform, lane, parameters) ⇒ Object
-
#find_alias(action_name) ⇒ Object
lookup if an alias exists.
- #full_lane_name ⇒ Object
- #set_after_all(platform, block) ⇒ Object
- #set_after_each(platform, block) ⇒ Object
- #set_before_all(platform, block) ⇒ Object
- #set_before_each(platform, block) ⇒ Object
- #set_error(platform, block) ⇒ Object
-
#trigger_action_by_name(method_sym, custom_dir, from_action, *arguments) ⇒ Object
This is being called from ‘method_missing` from the Fastfile It’s also used when an action is called from another action.
- #try_switch_to_lane(new_lane, parameters) ⇒ Object
- #verify_supported_os(name, class_ref) ⇒ Object
Instance Attribute Details
#current_lane ⇒ Object
Symbol for the current lane
4 5 6 |
# File 'fastlane/lib/fastlane/runner.rb', line 4 def current_lane @current_lane end |
#current_platform ⇒ Object
Symbol for the current platform
7 8 9 |
# File 'fastlane/lib/fastlane/runner.rb', line 7 def current_platform @current_platform end |
#lanes ⇒ Hash
Returns All the lanes available, first the platform, then the lane.
10 11 12 |
# File 'fastlane/lib/fastlane/runner.rb', line 10 def lanes @lanes end |
Instance Method Details
#action_completed(action_name, status: nil, exception: nil) ⇒ Object
281 282 283 284 285 286 287 |
# File 'fastlane/lib/fastlane/runner.rb', line 281 def action_completed(action_name, status: nil, exception: nil) # https://github.com/fastlane/fastlane/issues/11913 # if exception.nil? || exception.fastlane_should_report_metrics? # action_completion_context = FastlaneCore::ActionCompletionContext.context_for_action_name(action_name, args: ARGV, status: status) # FastlaneCore.session.action_completed(completion_context: action_completion_context) # end end |
#add_lane(lane, override = false) ⇒ Object
311 312 313 314 315 316 317 318 319 |
# File 'fastlane/lib/fastlane/runner.rb', line 311 def add_lane(lane, override = false) lanes[lane.platform] ||= {} if !override && lanes[lane.platform][lane.name] UI.user_error!("Lane '#{lane.name}' was defined multiple times!") end lanes[lane.platform][lane.name] = lane end |
#after_all_blocks ⇒ Object
370 371 372 |
# File 'fastlane/lib/fastlane/runner.rb', line 370 def after_all_blocks @after_all ||= {} end |
#after_each_blocks ⇒ Object
362 363 364 |
# File 'fastlane/lib/fastlane/runner.rb', line 362 def after_each_blocks @after_each ||= {} end |
#available_lanes(filter_platform = nil) ⇒ Object
Returns an array of lanes (platform lane_name) to print them out to the user.
77 78 79 80 81 82 83 84 85 86 87 |
# File 'fastlane/lib/fastlane/runner.rb', line 77 def available_lanes(filter_platform = nil) all = [] lanes.each do |platform, platform_lanes| next if filter_platform && filter_platform.to_s != platform.to_s # skip actions that don't match platform_lanes.each do |lane_name, lane| all << [platform, lane_name].reject(&:nil?).join(' ') unless lane.is_private end end all end |
#before_all_blocks ⇒ Object
366 367 368 |
# File 'fastlane/lib/fastlane/runner.rb', line 366 def before_all_blocks @before_all ||= {} end |
#before_each_blocks ⇒ Object
358 359 360 |
# File 'fastlane/lib/fastlane/runner.rb', line 358 def before_each_blocks @before_each ||= {} end |
#class_reference_from_action_alias(method_sym) ⇒ Object
Pass a action alias symbol (e.g. :enable_automatic_code_signing) and this method will return a reference to the action class if it exists. In case the action with this alias can’t be found this method will return nil.
108 109 110 111 112 113 |
# File 'fastlane/lib/fastlane/runner.rb', line 108 def class_reference_from_action_alias(method_sym) alias_found = find_alias(method_sym.to_s) return nil unless alias_found class_reference_from_action_name(alias_found.to_sym) end |
#class_reference_from_action_name(method_sym) ⇒ Object
Pass a action symbol (e.g. :deliver or :commit_version_bump) and this method will return a reference to the action class if it exists. In case the action with this name can’t be found this method will return nil. This method is being called by ‘trigger_action_by_name` to see if a given action is available (either built-in or loaded from a plugin) and is also being called from the fastlane docs generator
96 97 98 99 100 101 102 |
# File 'fastlane/lib/fastlane/runner.rb', line 96 def class_reference_from_action_name(method_sym) method_str = method_sym.to_s.delete("?") # as a `?` could be at the end of the method name class_ref = Actions.action_class_ref(method_str) return class_ref if class_ref && class_ref.respond_to?(:run) nil end |
#did_finish ⇒ Object
354 355 356 |
# File 'fastlane/lib/fastlane/runner.rb', line 354 def did_finish # to maintain compatibility with other sibling classes that have this API end |
#error_blocks ⇒ Object
374 375 376 |
# File 'fastlane/lib/fastlane/runner.rb', line 374 def error_blocks @error_blocks ||= {} end |
#execute(lane, platform = nil, parameters = nil) ⇒ Object
This will take care of executing one lane. That’s when the user triggers a lane from the CLI for example This method is not executed when switching a lane
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'fastlane/lib/fastlane/runner.rb', line 21 def execute(lane, platform = nil, parameters = nil) UI.crash!("No lane given") unless lane self.current_lane = lane.to_sym self.current_platform = (platform ? platform.to_sym : nil) lane_obj = lanes.fetch(current_platform, {}).fetch(current_lane, nil) UI.user_error!("Could not find lane '#{full_lane_name}'. Available lanes: #{available_lanes.join(', ')}") unless lane_obj UI.user_error!("You can't call the private lane '#{lane}' directly") if lane_obj.is_private ENV["FASTLANE_LANE_NAME"] = current_lane.to_s ENV["FASTLANE_PLATFORM_NAME"] = (current_platform ? current_platform.to_s : nil) Actions.lane_context[Actions::SharedValues::PLATFORM_NAME] = current_platform Actions.lane_context[Actions::SharedValues::LANE_NAME] = full_lane_name UI.success("Driving the lane '#{full_lane_name}' 🚀") return_val = nil path_to_use = FastlaneCore::FastlaneFolder.path || Dir.pwd parameters ||= {} # by default no parameters begin Dir.chdir(path_to_use) do # the file is located in the fastlane folder execute_flow_block(before_all_blocks, current_platform, current_lane, parameters) execute_flow_block(before_each_blocks, current_platform, current_lane, parameters) return_val = lane_obj.call(parameters) # after blocks are only called if no exception was raised before # Call the platform specific after block and then the general one execute_flow_block(after_each_blocks, current_platform, current_lane, parameters) execute_flow_block(after_all_blocks, current_platform, current_lane, parameters) end return return_val rescue => ex Dir.chdir(path_to_use) do # Provide error block exception without color code begin error_blocks[current_platform].call(current_lane, ex, parameters) if current_platform && error_blocks[current_platform] error_blocks[nil].call(current_lane, ex, parameters) if error_blocks[nil] rescue => error_block_exception UI.error("An error occurred while executing the `error` block:") UI.error(error_block_exception.to_s) raise ex # raise the original error message end end raise ex end end |
#execute_action(method_sym, class_ref, arguments, custom_dir: nil, from_action: false) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'fastlane/lib/fastlane/runner.rb', line 218 def execute_action(method_sym, class_ref, arguments, custom_dir: nil, from_action: false) if from_action == true custom_dir = "." # We preserve the directory from where the previous action was called from elsif custom_dir.nil? custom_dir ||= "." if Helper.test? custom_dir ||= ".." end verify_supported_os(method_sym, class_ref) begin Dir.chdir(custom_dir) do # go up from the fastlane folder, to the project folder # Removing step_name before its parsed into configurations args = arguments.kind_of?(Array) && arguments.first.kind_of?(Hash) ? arguments.first : {} step_name = args.delete(:step_name) # arguments is an array by default, containing an hash with the actual parameters # Since we usually just need the passed hash, we'll just use the first object if there is only one if arguments.count == 0 configurations = ConfigurationHelper.parse(class_ref, {}) # no parameters => empty hash elsif arguments.count == 1 && arguments.first.kind_of?(Hash) configurations = ConfigurationHelper.parse(class_ref, arguments.first) # Correct configuration passed elsif !class_ref. # This action does not use the new action format # Just passing the arguments to this method configurations = arguments else UI.user_error!("You have to call the integration like `#{method_sym}(key: \"value\")`. Run `fastlane action #{method_sym}` for all available keys. Please check out the current documentation on GitHub.") end # If another action is calling this action, we shouldn't show it in the summary # A nil value for action_name will hide it from the summary unless from_action action_name = step_name action_name ||= class_ref.method(:step_text).arity == 1 ? class_ref.step_text(configurations) : class_ref.step_text end Actions.execute_action(action_name) do if Fastlane::Actions.is_deprecated?(class_ref) puts("==========================================".deprecated) puts("This action (#{method_sym}) is deprecated".deprecated) puts(class_ref.deprecated_notes.to_s.remove_markdown.deprecated) if class_ref.deprecated_notes puts("==========================================\n".deprecated) end class_ref.runner = self # needed to call another action from an action return class_ref.run(configurations) end end rescue Interrupt => e raise e # reraise the interruption to avoid logging this as a crash rescue FastlaneCore::Interface::FastlaneCommonException => e # these are exceptions that we don't count as crashes raise e rescue FastlaneCore::Interface::FastlaneError => e # user_error! action_completed(method_sym.to_s, status: FastlaneCore::ActionCompletionStatus::USER_ERROR, exception: e) raise e rescue Exception => e # rubocop:disable Lint/RescueException # high chance this is actually FastlaneCore::Interface::FastlaneCrash, but can be anything else # Catches all exceptions, since some plugins might use system exits to get out action_completed(method_sym.to_s, status: FastlaneCore::ActionCompletionStatus::FAILED, exception: e) raise e end end |
#execute_flow_block(block, current_platform, lane, parameters) ⇒ Object
289 290 291 292 293 |
# File 'fastlane/lib/fastlane/runner.rb', line 289 def execute_flow_block(block, current_platform, lane, parameters) # Call the platform specific block and default back to the general one block[current_platform].call(lane, parameters) if block[current_platform] && current_platform block[nil].call(lane, parameters) if block[nil] end |
#find_alias(action_name) ⇒ Object
lookup if an alias exists
116 117 118 119 120 121 122 123 |
# File 'fastlane/lib/fastlane/runner.rb', line 116 def find_alias(action_name) Actions.alias_actions.each do |key, v| next unless Actions.alias_actions[key] next unless Actions.alias_actions[key].include?(action_name) return key end nil end |
#full_lane_name ⇒ Object
12 13 14 |
# File 'fastlane/lib/fastlane/runner.rb', line 12 def full_lane_name [current_platform, current_lane].reject(&:nil?).join(' ') end |
#set_after_all(platform, block) ⇒ Object
336 337 338 339 340 341 |
# File 'fastlane/lib/fastlane/runner.rb', line 336 def set_after_all(platform, block) unless after_all_blocks[platform].nil? UI.error("You defined multiple `after_all` blocks in your `Fastfile`. The last one being set will be used.") end after_all_blocks[platform] = block end |
#set_after_each(platform, block) ⇒ Object
325 326 327 |
# File 'fastlane/lib/fastlane/runner.rb', line 325 def set_after_each(platform, block) after_each_blocks[platform] = block end |
#set_before_all(platform, block) ⇒ Object
329 330 331 332 333 334 |
# File 'fastlane/lib/fastlane/runner.rb', line 329 def set_before_all(platform, block) unless before_all_blocks[platform].nil? UI.error("You defined multiple `before_all` blocks in your `Fastfile`. The last one being set will be used.") end before_all_blocks[platform] = block end |
#set_before_each(platform, block) ⇒ Object
321 322 323 |
# File 'fastlane/lib/fastlane/runner.rb', line 321 def set_before_each(platform, block) before_each_blocks[platform] = block end |
#set_error(platform, block) ⇒ Object
343 344 345 346 347 348 |
# File 'fastlane/lib/fastlane/runner.rb', line 343 def set_error(platform, block) unless error_blocks[platform].nil? UI.error("You defined multiple `error` blocks in your `Fastfile`. The last one being set will be used.") end error_blocks[platform] = block end |
#trigger_action_by_name(method_sym, custom_dir, from_action, *arguments) ⇒ Object
This is being called from ‘method_missing` from the Fastfile It’s also used when an action is called from another action
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'fastlane/lib/fastlane/runner.rb', line 129 def trigger_action_by_name(method_sym, custom_dir, from_action, *arguments) # First, check if there is a predefined method in the actions folder class_ref = class_reference_from_action_name(method_sym) unless class_ref class_ref = class_reference_from_action_alias(method_sym) # notify action that it has been used by alias if class_ref.respond_to?(:alias_used) orig_action = method_sym.to_s arguments = [{}] if arguments.empty? class_ref.alias_used(orig_action, arguments.first) end end # It's important to *not* have this code inside the rescue block # otherwise all NameErrors will be caught and the error message is # confusing begin return self.try_switch_to_lane(method_sym, arguments) rescue LaneNotAvailableError # We don't actually handle this here yet # We just try to use a user configured lane first # and only if there is none, we're gonna check for the # built-in actions end if class_ref if class_ref.respond_to?(:run) # Action is available, now execute it return self.execute_action(method_sym, class_ref, arguments, custom_dir: custom_dir, from_action: from_action) else UI.user_error!("Action '#{method_sym}' of class '#{class_name}' was found, but has no `run` method.") end end # No lane, no action, let's at least show the correct error message if Fastlane.plugin_manager.plugin_is_added_as_dependency?(PluginManager.plugin_prefix + method_sym.to_s) # That's a plugin, but for some reason we can't find it UI.user_error!("Plugin '#{method_sym}' was not properly loaded, make sure to follow the plugin docs for troubleshooting: #{PluginManager::TROUBLESHOOTING_URL}") elsif Fastlane::Actions.formerly_bundled_actions.include?(method_sym.to_s) # This was a formerly bundled action which is now a plugin. UI.verbose(caller.join("\n")) UI.user_error!("The action '#{method_sym}' is no longer bundled with fastlane. You can install it using `fastlane add_plugin #{method_sym}`") else # So there is no plugin under that name, so just show the error message generated by the lane switch UI.verbose(caller.join("\n")) UI.user_error!("Could not find action, lane or variable '#{method_sym}'. Check out the documentation for more details: https://docs.fastlane.tools/actions") end end |
#try_switch_to_lane(new_lane, parameters) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'fastlane/lib/fastlane/runner.rb', line 185 def try_switch_to_lane(new_lane, parameters) block = lanes.fetch(current_platform, {}).fetch(new_lane, nil) block ||= lanes.fetch(nil, {}).fetch(new_lane, nil) # fallback to general lane for multiple platforms if block original_full = full_lane_name original_lane = current_lane UI.user_error!("Parameters for a lane must always be a hash") unless (parameters.first || {}).kind_of?(Hash) execute_flow_block(before_each_blocks, current_platform, new_lane, parameters) pretty = [new_lane] pretty = [current_platform, new_lane] if current_platform Actions.execute_action("Switch to #{pretty.join(' ')} lane") {} # log the action UI.("Cruising over to lane '#{pretty.join(' ')}' 🚖") # Actually switch lane now self.current_lane = new_lane result = block.call(parameters.first || {}) # to always pass a hash self.current_lane = original_lane # after blocks are only called if no exception was raised before # Call the platform specific after block and then the general one execute_flow_block(after_each_blocks, current_platform, new_lane, parameters) UI.("Cruising back to lane '#{original_full}' 🚘") return result else raise LaneNotAvailableError.new, "Lane not found" end end |
#verify_supported_os(name, class_ref) ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 |
# File 'fastlane/lib/fastlane/runner.rb', line 295 def verify_supported_os(name, class_ref) if class_ref.respond_to?(:is_supported?) # This value is filled in based on the executed platform block. Might be nil when lane is in root of Fastfile platform = Actions.lane_context[Actions::SharedValues::PLATFORM_NAME] if platform unless class_ref.is_supported?(platform) UI.important("Action '#{name}' isn't known to support operating system '#{platform}'.") end end end end |