require 'rubygems/spec_fetcher' require 'rubygems/command_manager' module Fastlane module Actions # Makes sure fastlane tools are up-to-date when running fastlane class UpdateFastlaneAction < Action ALL_TOOLS = [ "fastlane", "fastlane_core", "deliver", "snapshot", "frameit", "pem", "sigh", "produce", "cert", "codes", "credentials_manager" ] def self.run(options) if options[:no_update] return end tools_to_update = options[:tools].split ',' unless options[:tools].nil? tools_to_update ||= all_installed_tools if tools_to_update.count == 0 Helper.log.error "No tools specified or couldn't find any installed fastlane.tools".red return end updater = Gem::CommandManager.instance[:update] cleaner = Gem::CommandManager.instance[:cleanup] sudo_needed = !File.writable?(Gem.dir) if sudo_needed Helper.log.warn "It seems that your Gem directory is not writable by your current User." Helper.log.warn "Fastlane would need sudo rights to update itself, however, running 'sudo fastlane' is not recommended." Helper.log.warn "If you still want to use this action, please read the Actions.md documentation on a guide how to set this up." return end highest_versions = updater.highest_installed_gems.keep_if {|key| tools_to_update.include? key } update_needed = updater.which_to_update(highest_versions, tools_to_update) if update_needed.count == 0 Helper.log.info "Nothing to update ✅".yellow return end # suppress updater output - very noisy Gem::DefaultUserInteraction.ui = Gem::SilentUI.new update_needed.each do |tool_info| tool = tool_info[0] local_version = Gem::Version.new(highest_versions[tool].version) latest_version = FastlaneCore::UpdateChecker.fetch_latest(tool) Helper.log.info "Updating #{tool} from #{local_version} to #{latest_version} ... 🚀" # Approximate_recommendation will create a string like "~> 0.10" from a version 0.10.0, e.g. one that is valid for versions >= 0.10 and <1.0 updater.update_gem tool, Gem::Requirement.new(local_version.approximate_recommendation) Helper.log.info "Finished updating #{tool}" end all_updated_tools = updater.installer.installed_gems.select do |updated_tool| updated_tool.version > highest_versions[updated_tool.name].version end unless all_updated_tools.empty? Helper.log.info "Cleaning up old versions..." cleaner.options[:args] = all_updated_tools.map {|t| t.name } cleaner.execute Helper.log.info "fastlane.tools succesfully updated! I will now restart myself... 😴" # Set no_update to true so we don't try to update again exec "FL_NO_UPDATE=true #{$PROGRAM_NAME} #{ARGV.join ' '}" else Helper.log.info "All fastlane tools are up-to-date!" end end def self.all_installed_tools Gem::Specification.select { |s| ALL_TOOLS.include? s.name }.map {|s| s.name}.uniq end def self.description "Makes sure fastlane-tools are up-to-date when running fastlane" end def self.available_options [ FastlaneCore::ConfigItem.new(key: :tools, env_name: "FL_TOOLS_TO_UPDATE", description: "Comma separated list of fastlane tools to update (e.g. fastlane,deliver,sigh). If not specified, all currently installed fastlane-tools will be updated", optional: true), FastlaneCore::ConfigItem.new(key: :no_update, env_name: "FL_NO_UPDATE", description: "Don't update during this run. Defaults to false", is_string: false, default_value: false), ] end def self.author "milch" end def self.is_supported?(platform) true end end end end