app/services/update_fastlane_ci_service.rb

Summary

Maintainability
A
1 hr
Test Coverage
require_relative "../shared/logging_module"
require_relative "../services/services"

require "rubygems/spec_fetcher"
require "rubygems/command_manager"

module FastlaneCI
  # Self-update fastlane.ci, this is called either on manual
  # user action, or through a background worker
  class UpdateFastlaneCIService
    include FastlaneCI::Logging

    GEM_NAME = "fastlane_ci"

    # Trigger an update for fastlane.ci
    # this method will automatically wait for all builds to finish
    def update_fastlane_ci
      loop do
        break if all_builds_complete? && all_workers_idle?
        logger.debug("Waiting for builds/workers to be complete to update fastlane.ci")
        sleep(5)
      end

      # TODO: Kill all workers here, as we're gonna restart the whole server
      logger.info("Starting update of fastlane.ci")

      execute_update
    end

    private

    def all_builds_complete?
      return true
      # TODO
    end

    def all_workers_idle?
      return true
      # TODO
    end

    def execute_update
      tools_to_update = [GEM_NAME]
      updater = Gem::CommandManager.instance[:update]
      cleaner = Gem::CommandManager.instance[:cleanup]

      gem_dir = ENV["GEM_HOME"] || Gem.dir
      sudo_needed = !File.writable?(gem_dir)

      if sudo_needed
        # TODO: update the instructions below
        logger.info("It seems that your Gem directory is not writable by your current user.")
        logger.info("fastlane would need sudo rights to update itself, however, running 'sudo' is not recommended.")
        logger.info("If you still want to use this action, please read the documentation how to set this up:")
        logger.info("https://docs.fastlane.tools/actions/#update_fastlane")
        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
        logger.info("Nothing to update for fastlane.ci")
        return
      end

      # suppress updater output - very noisy
      unless ENV["FASTLANE_CI_VERBOSE"]
        Gem::DefaultUserInteraction.ui = Gem::SilentUI.new
      end

      update_needed.each do |tool_info|
        tool = tool_info[0]
        local_version = Gem::Version.new(highest_versions[tool].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
        requirement_version = local_version.approximate_recommendation
        updater.update_gem(tool, Gem::Requirement.new(requirement_version))

        logger.info("Finished updating #{tool}")
      end

      logger.info("Cleaning up old versions...")
      cleaner.options[:args] = tools_to_update
      cleaner.execute

      logger.info("fastlane.ci successfully updated! I will now restart myself... 😴")

      # Set no_update to true so we don't try to update again
      # TODO: Use actual fastlane.ci launch command
      # exec("FL_NO_UPDATE=true #{$PROGRAM_NAME} #{ARGV.join(' ')}")
    end
  end
end