diff --git a/.rubocop.yml b/.rubocop.yml index b55e282..c365e01 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,3 +11,6 @@ Style/StringLiteralsInInterpolation: Style/RedundantReturn: Enabled: false + +Style/StderrPuts: + Enabled: false diff --git a/lib/psdk/cli.rb b/lib/psdk/cli.rb index 946df13..f8fc1a3 100644 --- a/lib/psdk/cli.rb +++ b/lib/psdk/cli.rb @@ -20,6 +20,12 @@ def version Version.run(options[:no_psdk_version]) end + desc 'update', 'update the psdk-cli' + def update + require_relative 'helpers/version_update' + VersionUpdate.check_and_update + end + desc 'plugin', 'manage PSDK plugins' subcommand 'plugin', Plugin end diff --git a/lib/psdk/cli/configuration.rb b/lib/psdk/cli/configuration.rb index e5a876a..ae0064b 100644 --- a/lib/psdk/cli/configuration.rb +++ b/lib/psdk/cli/configuration.rb @@ -10,10 +10,10 @@ class Configuration PROJECT_CONFIGURATION_FILENAME = '.psdk-cli.yml' # Path where all the global configuration are stored - PATH = ENV.fetch('PSDK_CLI_DIR', Dir.home || ENV['USERPROFILE'] || '~') + PATH = File.join(ENV.fetch('PSDK_CLI_DIR', Dir.home || ENV['USERPROFILE'] || '~'), '.psdk-cli') # Filename of the global configuration - GLOBAL_CONFIGURATION_FILENAME = File.join(PATH, '.psdk-cli/config.yml') + GLOBAL_CONFIGURATION_FILENAME = File.join(PATH, 'config.yml') # Create a new configuration # @param hash [Hash] configuration hash diff --git a/lib/psdk/helpers/version_update.rb b/lib/psdk/helpers/version_update.rb new file mode 100644 index 0000000..0508c72 --- /dev/null +++ b/lib/psdk/helpers/version_update.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require_relative '../cli/version' + +module Psdk + module Cli + # Module holding the logic to update the psdk-cli gem + module VersionUpdate + module_function + + # Check if the psdk-cli gem is up-to-date and update it if needed + def check_and_update + puts 'Checking for updates...' + local_version = Psdk::Cli::VERSION + remote_version = fetch_remote_version + + compare_and_update_versions(local_version, remote_version) + rescue StandardError => e + $stderr.puts "Failed to update: #{e.message}" + exit(1) + end + + # Compare local and remote versions and update if necessary + # @param local_version [String] The currently installed version + # @param remote_version [String] The latest version available + def compare_and_update_versions(local_version, remote_version) + if Gem::Version.new(remote_version) > Gem::Version.new(local_version) + puts "New version available: #{remote_version} (current: #{local_version})" + update_gem + else + puts 'psdk-cli is up-to-date.' + end + end + + # Fetch the latest version of psdk-cli from rubygems + # @return [String] + def fetch_remote_version + output = `gem search -r psdk-cli` + match = output.match(/psdk-cli \(([\d.]+)\)/) + return match[1] if match + + raise 'Could not find psdk-cli in remote gems' + end + + # Update the psdk-cli gem + def update_gem + print 'Do you want to update psdk-cli? [Y/n] ' + response = $stdin.gets.chomp + return unless response.empty? || response.casecmp('y').zero? + + puts 'Updating psdk-cli...' + result = system('gem install psdk-cli') + raise 'gem install psdk-cli failed' unless result + + puts 'Update complete.' + exit + end + end + end +end diff --git a/spec/psdk/helpers/version_update_spec.rb b/spec/psdk/helpers/version_update_spec.rb new file mode 100644 index 0000000..a473f17 --- /dev/null +++ b/spec/psdk/helpers/version_update_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'spec_helper' +require 'psdk/helpers/version_update' + +# rubocop:disable Metrics/BlockLength +RSpec.describe Psdk::Cli::VersionUpdate do + describe '.check_and_update' do + let(:local_version) { '1.0.0' } + let(:remote_version) { '1.0.1' } + let(:gem_search_output) { "psdk-cli (#{remote_version})\n" } + + before do + stub_const('Psdk::Cli::VERSION', local_version) + allow(Psdk::Cli::VersionUpdate).to receive(:`).with('gem search -r psdk-cli').and_return(gem_search_output) + allow(Psdk::Cli::VersionUpdate).to receive(:puts) + allow(Psdk::Cli::VersionUpdate).to receive(:system) + allow(Psdk::Cli::VersionUpdate).to receive(:exit) + end + + context 'when a new version is available' do + before do + allow($stdin).to receive(:gets).and_return("y\n") + allow(Psdk::Cli::VersionUpdate).to receive(:system).and_return(true) + end + + it 'updates the gem' do + expect(Psdk::Cli::VersionUpdate).to receive(:print).with('Do you want to update psdk-cli? [Y/n] ') + expect(Psdk::Cli::VersionUpdate).to receive(:system).with('gem install psdk-cli') + Psdk::Cli::VersionUpdate.check_and_update + end + + it 'logs an error and exits if update fails' do + expect(Psdk::Cli::VersionUpdate).to receive(:print).with('Do you want to update psdk-cli? [Y/n] ') + expect(Psdk::Cli::VersionUpdate).to receive(:system).with('gem install psdk-cli').and_return(false) + expect(Psdk::Cli::VersionUpdate).to receive(:exit).with(1) + expect($stderr).to receive(:puts).with('Failed to update: gem install psdk-cli failed') + Psdk::Cli::VersionUpdate.check_and_update + end + + it 'exits after update' do + expect(Psdk::Cli::VersionUpdate).to receive(:exit) + Psdk::Cli::VersionUpdate.check_and_update + end + + context 'when user declines update' do + before do + allow($stdin).to receive(:gets).and_return("n\n") + end + + it 'does not update the gem' do + expect(Psdk::Cli::VersionUpdate).not_to receive(:system) + Psdk::Cli::VersionUpdate.check_and_update + end + end + end + + context 'when the local version is up-to-date' do + let(:remote_version) { '1.0.0' } + + it 'does not update the gem' do + expect(Psdk::Cli::VersionUpdate).not_to receive(:system) + Psdk::Cli::VersionUpdate.check_and_update + end + end + + context 'when the local version is newer than remote' do + let(:remote_version) { '0.9.9' } + + it 'does not update the gem' do + expect(Psdk::Cli::VersionUpdate).not_to receive(:system) + Psdk::Cli::VersionUpdate.check_and_update + end + end + + context 'when gem search fails to find the gem' do + let(:gem_search_output) { "No match found\n" } + + it 'rescues the error and prints a message' do + expect($stderr).to receive(:puts).with( + 'Failed to update: Could not find psdk-cli in remote gems' + ) + Psdk::Cli::VersionUpdate.check_and_update + end + end + end +end +# rubocop:enable Metrics/BlockLength