Offer the possibility to define version compatibility from plugins
This commit is contained in:
parent
17ac414d74
commit
07f9700179
|
|
@ -14,6 +14,7 @@ Improvements:
|
|||
* Display project analytics in modal box
|
||||
* Display project exports in modal box
|
||||
* Improve accordion component
|
||||
* Offer the possibility to define version compatibility from plugins
|
||||
|
||||
Version 1.0.36 (Dec 30, 2016)
|
||||
-----------------------------
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class PluginController extends BaseController
|
|||
{
|
||||
$this->response->html($this->helper->layout->plugin('plugin/show', array(
|
||||
'plugins' => $this->pluginLoader->getPlugins(),
|
||||
'incompatible_plugins' => $this->pluginLoader->getIncompatiblePlugins(),
|
||||
'title' => t('Installed Plugins'),
|
||||
'is_configured' => Installer::isConfigured(),
|
||||
)));
|
||||
|
|
|
|||
|
|
@ -131,4 +131,17 @@ abstract class Base extends \Kanboard\Core\Base
|
|||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get application compatibility version
|
||||
*
|
||||
* Examples: >=1.0.36, 1.0.37, APP_VERSION
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getCompatibleVersion()
|
||||
{
|
||||
return APP_VERSION;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,18 +36,7 @@ class Directory extends BaseCore
|
|||
*/
|
||||
public function isCompatible(array $plugin, $appVersion = APP_VERSION)
|
||||
{
|
||||
if (strpos($appVersion, 'master') !== false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (array('>=', '>') as $operator) {
|
||||
if (strpos($plugin['compatible_version'], $operator) === 0) {
|
||||
$pluginVersion = substr($plugin['compatible_version'], strlen($operator));
|
||||
return version_compare($appVersion, $pluginVersion, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
return $plugin['compatible_version'] === $appVersion;
|
||||
return Version::isCompatible($plugin['compatible_version'], $appVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace Kanboard\Core\Plugin;
|
|||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use DirectoryIterator;
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use Kanboard\Core\Tool;
|
||||
|
||||
|
|
@ -22,6 +23,7 @@ class Loader extends \Kanboard\Core\Base
|
|||
* @var array
|
||||
*/
|
||||
protected $plugins = array();
|
||||
protected $incompatiblePlugins = array();
|
||||
|
||||
/**
|
||||
* Get list of loaded plugins
|
||||
|
|
@ -34,6 +36,17 @@ class Loader extends \Kanboard\Core\Base
|
|||
return $this->plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of not compatible plugins
|
||||
*
|
||||
* @access public
|
||||
* @return Base[]
|
||||
*/
|
||||
public function getIncompatiblePlugins()
|
||||
{
|
||||
return $this->incompatiblePlugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan plugin folder and load plugins
|
||||
*
|
||||
|
|
@ -51,8 +64,7 @@ class Loader extends \Kanboard\Core\Base
|
|||
foreach ($dir as $fileInfo) {
|
||||
if ($fileInfo->isDir() && substr($fileInfo->getFilename(), 0, 1) !== '.') {
|
||||
$pluginName = $fileInfo->getFilename();
|
||||
$this->loadSchema($pluginName);
|
||||
$this->initializePlugin($pluginName, $this->loadPlugin($pluginName));
|
||||
$this->initializePlugin($pluginName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +97,7 @@ class Loader extends \Kanboard\Core\Base
|
|||
$className = '\Kanboard\Plugin\\'.$pluginName.'\\Plugin';
|
||||
|
||||
if (! class_exists($className)) {
|
||||
throw new LogicException('Unable to load this plugin class '.$className);
|
||||
throw new LogicException('Unable to load this plugin class: '.$className);
|
||||
}
|
||||
|
||||
return new $className($this->container);
|
||||
|
|
@ -96,18 +108,30 @@ class Loader extends \Kanboard\Core\Base
|
|||
*
|
||||
* @access public
|
||||
* @param string $pluginName
|
||||
* @param Base $plugin
|
||||
*/
|
||||
public function initializePlugin($pluginName, Base $plugin)
|
||||
public function initializePlugin($pluginName)
|
||||
{
|
||||
if (method_exists($plugin, 'onStartup')) {
|
||||
$this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
|
||||
try {
|
||||
$plugin = $this->loadPlugin($pluginName);
|
||||
|
||||
if (Version::isCompatible($plugin->getCompatibleVersion(), APP_VERSION)) {
|
||||
$this->loadSchema($pluginName);
|
||||
|
||||
if (method_exists($plugin, 'onStartup')) {
|
||||
$this->dispatcher->addListener('app.bootstrap', array($plugin, 'onStartup'));
|
||||
}
|
||||
|
||||
Tool::buildDIC($this->container, $plugin->getClasses());
|
||||
Tool::buildDICHelpers($this->container, $plugin->getHelpers());
|
||||
|
||||
$plugin->initialize();
|
||||
$this->plugins[$pluginName] = $plugin;
|
||||
} else {
|
||||
$this->incompatiblePlugins[$pluginName] = $plugin;
|
||||
$this->logger->error($pluginName.' is not compatible with this version');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->logger->critical($pluginName.': '.$e->getMessage());
|
||||
}
|
||||
|
||||
Tool::buildDIC($this->container, $plugin->getClasses());
|
||||
Tool::buildDICHelpers($this->container, $plugin->getHelpers());
|
||||
|
||||
$plugin->initialize();
|
||||
$this->plugins[$pluginName] = $plugin;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class PluginException
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class PluginException extends Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -2,14 +2,12 @@
|
|||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class PluginInstallerException
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class PluginInstallerException extends Exception
|
||||
class PluginInstallerException extends PluginException
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Kanboard\Core\Plugin;
|
||||
|
||||
/**
|
||||
* Class Version
|
||||
*
|
||||
* @package Kanboard\Core\Plugin
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
/**
|
||||
* Check plugin version compatibility with application version
|
||||
*
|
||||
* @param string $pluginCompatibleVersion
|
||||
* @param string $appVersion
|
||||
* @return bool
|
||||
*/
|
||||
public static function isCompatible($pluginCompatibleVersion, $appVersion = APP_VERSION)
|
||||
{
|
||||
if (strpos($appVersion, 'master') !== false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$appVersion = str_replace('v', '', $appVersion);
|
||||
$pluginCompatibleVersion = str_replace('v', '', $pluginCompatibleVersion);
|
||||
|
||||
foreach (array('>=', '>', '<=', '<') as $operator) {
|
||||
if (strpos($pluginCompatibleVersion, $operator) === 0) {
|
||||
$pluginVersion = substr($pluginCompatibleVersion, strlen($operator));
|
||||
return version_compare($appVersion, $pluginVersion, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
return $pluginCompatibleVersion === $appVersion;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,43 @@
|
|||
<?php if (! empty($incompatible_plugins)): ?>
|
||||
<div class="page-header">
|
||||
<h2><?= t('Incompatible Plugins') ?></h2>
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th class="column-35"><?= t('Name') ?></th>
|
||||
<th class="column-25"><?= t('Author') ?></th>
|
||||
<th class="column-10"><?= t('Version') ?></th>
|
||||
<th class="column-12"><?= t('Compatibility') ?></th>
|
||||
<?php if ($is_configured): ?>
|
||||
<th><?= t('Action') ?></th>
|
||||
<?php endif ?>
|
||||
</tr>
|
||||
|
||||
<?php foreach ($incompatible_plugins as $pluginFolder => $plugin): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ($plugin->getPluginHomepage()): ?>
|
||||
<a href="<?= $plugin->getPluginHomepage() ?>" target="_blank" rel="noreferrer"><?= $this->text->e($plugin->getPluginName()) ?></a>
|
||||
<?php else: ?>
|
||||
<?= $this->text->e($plugin->getPluginName()) ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
<td><?= $this->text->e($plugin->getPluginAuthor()) ?></td>
|
||||
<td><?= $this->text->e($plugin->getPluginVersion()) ?></td>
|
||||
<td><?= $this->text->e($plugin->getCompatibleVersion()) ?></td>
|
||||
<?php if ($is_configured): ?>
|
||||
<td>
|
||||
<?= $this->modal->confirm('trash-o', t('Uninstall'), 'PluginController', 'confirm', array('pluginId' => $pluginFolder)) ?>
|
||||
</td>
|
||||
<?php endif ?>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="<?= $is_configured ? 6 : 5 ?>"><?= $this->text->e($plugin->getPluginDescription()) ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="page-header">
|
||||
<h2><?= t('Installed Plugins') ?></h2>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -71,6 +71,15 @@ class Plugin extends Base
|
|||
{
|
||||
$this->template->hook->attach('template:layout:head', 'theme:layout/head');
|
||||
}
|
||||
|
||||
public function getCompatibleVersion()
|
||||
{
|
||||
// Examples:
|
||||
// >=1.0.37
|
||||
// <1.0.37
|
||||
// <=1.0.37
|
||||
return '1.0.37';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -93,6 +102,7 @@ Available methods from `Kanboard\Core\Plugin\Base`:
|
|||
- `getPluginHomepage()`: Should return plugin Homepage (link)
|
||||
- `setContentSecurityPolicy(array $rules)`: Override default HTTP CSP rules
|
||||
- `onStartup()`: If present, this method is executed automatically when the event "app.bootstrap" is triggered
|
||||
- `getCompatibleVersion()`: You may want to specify the Kanboard version compatible with the plugin
|
||||
|
||||
Your plugin registration class can also inherit from Kanboard\Core\Base, that way you can access all classes and methods of Kanboard easily.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use Kanboard\Core\Plugin\Version;
|
||||
|
||||
require_once __DIR__.'/../../Base.php';
|
||||
|
||||
class VersionTest extends Base
|
||||
{
|
||||
public function testIsCompatible()
|
||||
{
|
||||
$this->assertFalse(Version::isCompatible('1.0.29', '1.0.28'));
|
||||
$this->assertTrue(Version::isCompatible('1.0.28', '1.0.28'));
|
||||
$this->assertTrue(Version::isCompatible('1.0.28', 'master.1234'));
|
||||
$this->assertTrue(Version::isCompatible('>=1.0.32', 'master'));
|
||||
$this->assertTrue(Version::isCompatible('>=1.0.32', '1.0.32'));
|
||||
$this->assertTrue(Version::isCompatible('>=1.0.32', '1.0.33'));
|
||||
$this->assertTrue(Version::isCompatible('>1.0.32', '1.0.33'));
|
||||
$this->assertFalse(Version::isCompatible('>1.0.32', '1.0.32'));
|
||||
$this->assertTrue(Version::isCompatible('1.0.32', 'v1.0.32'));
|
||||
$this->assertTrue(Version::isCompatible('>=v1.0.32', 'v1.0.32'));
|
||||
$this->assertTrue(Version::isCompatible('<=v1.0.36', 'v1.0.36'));
|
||||
$this->assertFalse(Version::isCompatible('<1.0.36', 'v1.0.36'));
|
||||
$this->assertTrue(Version::isCompatible('<1.0.40', '1.0.36'));
|
||||
$this->assertTrue(Version::isCompatible('<=1.0.40', '1.0.36'));
|
||||
$this->assertFalse(Version::isCompatible('<1.0.40', '1.0.40'));
|
||||
$this->assertFalse(Version::isCompatible('1.0.40', 'v1.0.36'));
|
||||
$this->assertTrue(Version::isCompatible('<1.1.0', 'v1.0.36'));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue