From a6f035e1887833f00ba058c45b815bb25240040b Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Thu, 26 Apr 2018 15:07:07 -0400 Subject: [PATCH] Bug 20669: Add upgrade method to plugins It would be nice if plugins had an upgrade method to handle altering tables and such when a new version of a plugin is installed. Right now it must be done in a completely bespoke manner. Test Plan: 1) Apply this patch 2) Download the 2 most recent releases of the Kitchen Sink plugin https://github.com/bywatersolutions/koha-plugin-kitchen-sink/releases 3) Install the earlier release 4) Look at the configuration page, at the bottom it should say the plugin has never been upgraded 5) Install the newer release 6) Reload the configuration page, it should now say that the plugin was upgraded and give you the date and time of the upgrade Signed-off-by: Claire Gravely Signed-off-by: Tomas Cohen Arazi Signed-off-by: Nick Clemens (cherry picked from commit 100385196ecadb34669190caa241ed73ea2a5a1c) Signed-off-by: Martin Renvoize (cherry picked from commit b3f2a13a4368d9f8bec74a6da920649d56732b71) Signed-off-by: Fridolin Somers --- Koha/Plugins/Base.pm | 51 ++++++++++++++++++++++++++++++++++++++++ t/Koha/Plugin/Test.pm | 5 ++++ t/db_dependent/Plugins.t | 17 ++++++++++++-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/Koha/Plugins/Base.pm b/Koha/Plugins/Base.pm index c39a8c91bf..ed87253a02 100644 --- a/Koha/Plugins/Base.pm +++ b/Koha/Plugins/Base.pm @@ -21,6 +21,7 @@ use Modern::Perl; use Module::Pluggable require => 1; use Cwd qw(abs_path); +use List::Util qw(max); use base qw{Module::Bundled::Files}; @@ -43,13 +44,26 @@ sub new { my $self = bless( $args, $class ); + my $plugin_version = $self->get_metadata->{version}; + my $database_version = $self->retrieve_data('__INSTALLED_VERSION__'); + ## Run the installation method if it exists and hasn't been run before if ( $self->can('install') && !$self->retrieve_data('__INSTALLED__') ) { if ( $self->install() ) { $self->store_data( { '__INSTALLED__' => 1 } ); + if ( my $version = $plugin_version ) { + $self->store_data({ '__INSTALLED_VERSION__' => $version }); + } } else { warn "Plugin $class failed during installation!"; } + } elsif ( $self->can('upgrade') && $plugin_version && $database_version ) { + if ( _version_compare( $plugin_version, $database_version ) == 1 ) { + if ( $self->upgrade() ) { + $self->store_data({ '__INSTALLED_VERSION__' => $plugin_version }); + warn "Plugin $class failed during upgrade!"; + } + } } return $self; @@ -218,6 +232,43 @@ sub output { output_with_http_headers( $self->{cgi}, undef, $data, $content_type, $status, $extra_options ); } +=head2 _version_compare + +Utility method to compare two version numbers. +Returns 1 if the first argument is the higher version +Returns -1 if the first argument is the lower version +Returns 0 if both versions are equal + +if ( _version_compare( '2.6.26', '2.6.0' ) == 1 ) { + print "2.6.26 is greater than 2.6.0\n"; +} + +=cut + +sub _version_compare { + my $ver1 = shift || 0; + my $ver2 = shift || 0; + + my @v1 = split /[.+:~-]/, $ver1; + my @v2 = split /[.+:~-]/, $ver2; + + for ( my $i = 0 ; $i < max( scalar(@v1), scalar(@v2) ) ; $i++ ) { + + # Add missing version parts if one string is shorter than the other + # i.e. 0 should be lt 0.2.1 and not equal, so we append .0 + # 0.0.0 <=> 0.2.1 = -1 + push( @v1, 0 ) unless defined( $v1[$i] ); + push( @v2, 0 ) unless defined( $v2[$i] ); + if ( int( $v1[$i] ) > int( $v2[$i] ) ) { + return 1; + } + elsif ( int( $v1[$i] ) < int( $v2[$i] ) ) { + return -1; + } + } + return 0; +} + 1; __END__ diff --git a/t/Koha/Plugin/Test.pm b/t/Koha/Plugin/Test.pm index 0f51f73a6b..a3969bf06d 100644 --- a/t/Koha/Plugin/Test.pm +++ b/t/Koha/Plugin/Test.pm @@ -68,6 +68,11 @@ sub install { return "Koha::Plugin::Test::install"; } +sub upgrade { + my ( $self, $args ) = @_; + return "Koha::Plugin::Test::upgrade"; +} + sub uninstall { my ( $self, $args ) = @_; return "Koha::Plugin::Test::uninstall"; diff --git a/t/db_dependent/Plugins.t b/t/db_dependent/Plugins.t index 106eb9148e..8a1c26e8fd 100755 --- a/t/db_dependent/Plugins.t +++ b/t/db_dependent/Plugins.t @@ -2,15 +2,15 @@ use Modern::Perl; -use Test::More tests => 33; +use Archive::Extract; use CGI; use File::Basename; use File::Spec; use File::Temp qw( tempdir tempfile ); use FindBin qw($Bin); -use Archive::Extract; use Module::Load::Conditional qw(can_load); use Test::MockModule; +use Test::More tests => 35; use C4::Context; use t::lib::Mocks; @@ -47,6 +47,7 @@ ok( $plugin->can('opac_online_payment_begin'), 'Test plugin can opac_online_paym ok( $plugin->can('opac_online_payment_end'), 'Test plugin can opac_online_payment_end' ); ok( $plugin->can('configure'), 'Test plugin can configure' ); ok( $plugin->can('install'), 'Test plugin can install' ); +ok( $plugin->can('upgrade'), 'Test plugin can upgrade' ); ok( $plugin->can('uninstall'), 'Test plugin can install' ); is( Koha::Plugins::Handler->run({ class => "Koha::Plugin::Test", method => 'report', enable_plugins => 1 }), "Koha::Plugin::Test::report", 'Test run plugin report method' ); @@ -149,3 +150,15 @@ subtest 'output and output_html tests' => sub { like($stdout, qr{Content-Type: text/html; charset=UTF-8}, 'Correct content-type'); like($stdout, qr{¡Hola output_html!}, 'Correct data'); }; + +subtest 'Test _version_compare' => sub { + + plan tests => 6; + + is( Koha::Plugins::Base::_version_compare( '1.1.1', '2.2.2' ), -1, "1.1.1 is less then 2.2.2" ); + is( Koha::Plugins::Base::_version_compare( '2.2.2', '1.1.1' ), 1, "1.1.1 is greater then 2.2.2" ); + is( Koha::Plugins::Base::_version_compare( '1.1.1', '1.1.1' ), 0, "1.1.1 is equal to 1.1.1" ); + is( Koha::Plugins::Base::_version_compare( '1.01.001', '1.1.1' ), 0, "1.01.001 is equal to 1.1.1" ); + is( Koha::Plugins::Base::_version_compare( '1', '1.0.0' ), 0, "1 is equal to 1.0.0" ); + is( Koha::Plugins::Base::_version_compare( '1.0', '1.0.0' ), 0, "1.0 is equal to 1.0.0" ); +}; -- 2.39.5