lib/gdk/diagnostic/tool_version_manager.rb (110 lines of code) (raw):

# frozen_string_literal: true require 'json' module GDK module Diagnostic # Notifies users about the supported tool version manager and suggests migrating from asdf to mise. class ToolVersionManager < Base TITLE = 'Tool Version Manager' BROKEN_ASDF_VERSION_REGEX = /v0\.16\.\d+/ def correctable? using_asdf? || (mise_update_command && mise_update_required?) end def correct! migrate_to_mise! if using_asdf? update_mise! if mise_update_command && mise_update_required? end def success? !using_asdf? && !mise_update_required? end def detail(context = nil) return if success? messages = [] messages << <<~MESSAGE if broken_asdf_version? ERROR: Your installed version of asdf (`#{current_asdf_version}`) has a bug that makes it incompatible with GDK. Please downgrade to `v0.15.0` or switch to `mise`. MESSAGE if using_asdf? messages << <<~MESSAGE We're dropping support for asdf in GDK. You can still use asdf if you need to, for example outside of GDK. But it's no longer supported in GDK and won't be maintained going forward. Mise provides better supply chain security while running faster and avoiding the dependency installation problems that we had to manually fix with asdf. MESSAGE unless context == :update messages << <<~MESSAGE To migrate, run: gdk update MESSAGE end return messages.join("\n") end if mise_update_required? messages << <<~MESSAGE WARNING: Your installed version of mise (#{current_mise_version}) is out of date. The latest available version is #{mise_latest_version}. MESSAGE if mise_update_command messages << <<~MESSAGE To update to the latest version, run: `#{mise_update_command}` MESSAGE end end messages.join("\n") end private def using_mise? GDK.config.asdf.opt_out? && GDK.config.mise.enabled? end def using_asdf? !GDK.config.asdf.opt_out? end def broken_asdf_version? return false unless using_asdf? BROKEN_ASDF_VERSION_REGEX.match?(current_asdf_version) end def current_asdf_version @current_asdf_version ||= begin GDK::Shellout.new('asdf version').readlines.first&.strip rescue Errno::ENOENT nil end end def mise_version_output @mise_version_output ||= begin output = GDK::Shellout.new('mise version --json').execute(display_output: false).read_stdout JSON.parse(output) rescue Errno::ENOENT, JSON::ParserError {} end end def current_mise_version mise_version_output['version']&.split&.first end def mise_latest_version mise_version_output['latest'] end def mise_update_command if GDK::Machine.macos? 'brew update && brew upgrade mise' elsif GDK::Machine.linux? 'apt update && apt upgrade mise' end end def mise_update_required? return false unless using_mise? return false unless current_mise_version && mise_latest_version begin current_version = Gem::Version.new(current_mise_version) latest_version = Gem::Version.new(mise_latest_version) current_version < latest_version rescue ArgumentError false end end def update_mise! GDK::Shellout.new(mise_update_command).execute(display_output: false) true rescue StandardError => e GDK::Output.warn("Failed to update mise: #{e.message}") false end def migrate_to_mise! GDK::Execute::Rake.new('mise:migrate').execute_in_gdk end end end end