Allow multiline changelog messages, preserve correct order of updates (#4083)
Credit to @GinoPane
This commit is contained in:
parent
cb981eb82d
commit
9581b23d1e
|
|
@ -94,6 +94,7 @@ class VersionManager
|
|||
}
|
||||
|
||||
$newUpdates = $this->getNewFileVersions($code, $databaseVersion);
|
||||
|
||||
foreach ($newUpdates as $version => $details) {
|
||||
$this->applyPluginUpdate($code, $version, $details);
|
||||
|
||||
|
|
@ -125,14 +126,7 @@ class VersionManager
|
|||
*/
|
||||
protected function applyPluginUpdate($code, $version, $details)
|
||||
{
|
||||
if (is_array($details)) {
|
||||
$comment = array_shift($details);
|
||||
$scripts = $details;
|
||||
}
|
||||
else {
|
||||
$comment = $details;
|
||||
$scripts = [];
|
||||
}
|
||||
list($comments, $scripts) = $this->extractScriptsAndComments($details);
|
||||
|
||||
/*
|
||||
* Apply scripts, if any
|
||||
|
|
@ -149,12 +143,14 @@ class VersionManager
|
|||
* Register the comment and update the version
|
||||
*/
|
||||
if (!$this->hasDatabaseHistory($code, $version)) {
|
||||
$this->applyDatabaseComment($code, $version, $comment);
|
||||
foreach ($comments as $comment) {
|
||||
$this->applyDatabaseComment($code, $version, $comment);
|
||||
|
||||
$this->note(sprintf('- <info>v%s: </info> %s', $version, $comment));
|
||||
}
|
||||
}
|
||||
|
||||
$this->setDatabaseVersion($code, $version);
|
||||
|
||||
$this->note(sprintf('- <info>v%s: </info> %s', $version, $comment));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -393,6 +389,7 @@ class VersionManager
|
|||
|
||||
if (!File::isFile($updateFile)) {
|
||||
$this->note('- <error>v' . $version . ': Migration file "' . $script . '" not found</error>');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->updater->setUp($updateFile);
|
||||
|
|
@ -524,4 +521,29 @@ class VersionManager
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $details
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function extractScriptsAndComments($details)
|
||||
{
|
||||
if (is_array($details)) {
|
||||
$fileNamePattern = '/^[a-z_\-0-9]*\.php$/i';
|
||||
|
||||
$comments = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
|
||||
return !preg_match($fileNamePattern, $detail);
|
||||
}));
|
||||
|
||||
$scripts = array_values(array_filter($details, function ($detail) use ($fileNamePattern) {
|
||||
return preg_match($fileNamePattern, $detail);
|
||||
}));
|
||||
} else {
|
||||
$comments = (array)$details;
|
||||
$scripts = [];
|
||||
}
|
||||
|
||||
return array($comments, $scripts);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,17 +181,27 @@ class Updates extends Controller
|
|||
$contents = [];
|
||||
|
||||
try {
|
||||
$updates = Yaml::parseFile($path.'/'.$filename);
|
||||
$updates = is_array($updates) ? array_reverse($updates) : [];
|
||||
$updates = (array) Yaml::parseFile($path.'/'.$filename);
|
||||
|
||||
foreach ($updates as $version => $details) {
|
||||
$contents[$version] = is_array($details)
|
||||
? array_shift($details)
|
||||
: $details;
|
||||
if (!is_array($details)) {
|
||||
$details = (array)$details;
|
||||
}
|
||||
|
||||
//Filter out update scripts
|
||||
$details = array_filter($details, function($string) use ($path) {
|
||||
return !preg_match('/^[a-z_\-0-9]*\.php$/i', $string) || !File::exists($path . '/updates/' . $string);
|
||||
});
|
||||
|
||||
$contents[$version] = $details;
|
||||
}
|
||||
}
|
||||
catch (Exception $ex) {}
|
||||
|
||||
uksort($contents, function ($a, $b) {
|
||||
return version_compare($b, $a);
|
||||
});
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,10 +76,12 @@
|
|||
<div class="plugin-details-content">
|
||||
<?php if ($changelog): ?>
|
||||
<dl>
|
||||
<?php foreach ($changelog as $version => $comment): ?>
|
||||
<dt><?= e($version) ?></dt>
|
||||
<dd><?= e($comment) ?></dd>
|
||||
<?php endforeach ?>
|
||||
<?php foreach ($changelog as $version => $comments): ?>
|
||||
<?php foreach ($comments as $index => $comment): ?>
|
||||
<dt><?= !$index ? e($version): '' ?></dt>
|
||||
<dd><?= e($comment) ?></dd>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</dl>
|
||||
<?php else: ?>
|
||||
<p><?= e(trans('system::lang.updates.details_changelog_missing')) ?></p>
|
||||
|
|
|
|||
|
|
@ -19,4 +19,34 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
|||
return $app;
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
1.0.5:
|
||||
- Create blog settings table
|
||||
- Another update message
|
||||
- Yet one more update message
|
||||
- create_blog_settings_table.php
|
||||
1.0.4: Another fix
|
||||
1.0.3: Bug fix update that uses no scripts
|
||||
1.0.2:
|
||||
- Create blog post comments table
|
||||
- Multiple update messages are allowed
|
||||
- create_comments_table.php
|
||||
1.0.1:
|
||||
- Added some upgrade file and some seeding
|
||||
- some_upgrade_file.php
|
||||
- some_seeding_file.php
|
||||
1.0.2:
|
||||
- Create blog post comments table
|
||||
- create_comments_table.php
|
||||
1.0.3: Bug fix update that uses no scripts
|
||||
1.0.4: Another fix
|
||||
1.0.5:
|
||||
- Create blog settings table
|
||||
- create_blog_settings_table.php
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,19 +26,6 @@ class ExampleExportModel extends ExportModel
|
|||
class ExportModelTest extends TestCase
|
||||
{
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
|
|
@ -17,19 +17,6 @@ class ExampleImportModel extends ImportModel
|
|||
class ImportModelTest extends TestCase
|
||||
{
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
|
|
@ -11,37 +11,6 @@ use October\Rain\Exception\SystemException;
|
|||
|
||||
class CmsExceptionTest extends TestCase
|
||||
{
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
|
|
@ -12,37 +12,6 @@ class CombineAssetsTest extends TestCase
|
|||
CombineAssets::resetCache();
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
|
|
@ -12,37 +12,6 @@ class MarkupManagerTest extends TestCase
|
|||
include_once base_path().'/tests/fixtures/plugins/october/tester/Plugin.php';
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
|
|
@ -12,37 +12,6 @@ class PluginManagerTest extends TestCase
|
|||
include_once base_path().'/tests/fixtures/plugins/october/tester/Plugin.php';
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
use System\Controllers\Updates;
|
||||
|
||||
class UpdatesControllerTest extends TestCase
|
||||
{
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
public function testGetPluginVersionFile()
|
||||
{
|
||||
$controller = $this->getMockBuilder(Updates::class)->disableOriginalConstructor()->getMock();
|
||||
|
||||
$expectedVersions = [
|
||||
'1.0.5' => [
|
||||
'Create blog settings table',
|
||||
'Another update message',
|
||||
'Yet one more update message'
|
||||
],
|
||||
'1.0.4' => [
|
||||
'Another fix'
|
||||
],
|
||||
'1.0.3' => [
|
||||
'Bug fix update that uses no scripts'
|
||||
],
|
||||
'1.0.2' => [
|
||||
'Create blog post comments table',
|
||||
'Multiple update messages are allowed'
|
||||
],
|
||||
'1.0.1' => [
|
||||
'Added some upgrade file and some seeding',
|
||||
'some_upgrade_file.php', //does not exist
|
||||
'some_seeding_file.php' //does not exist
|
||||
]
|
||||
];
|
||||
|
||||
$versions = self::callProtectedMethod(
|
||||
$controller,
|
||||
'getPluginVersionFile',
|
||||
[
|
||||
base_path().'/tests/fixtures/plugins/october/tester/',
|
||||
'updates/version.yaml'
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertNotNull($versions);
|
||||
$this->assertEquals($expectedVersions, $versions);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,37 +14,6 @@ class VersionManagerTest extends TestCase
|
|||
include_once base_path().'/tests/fixtures/plugins/october/noupdates/Plugin.php';
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
public static function getProtectedProperty($object, $name)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
public static function setProtectedProperty($object, $name, $value)
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$property = $class->getProperty($name);
|
||||
$property->setAccessible(true);
|
||||
return $property->setValue($object, $value);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
@ -119,4 +88,89 @@ class VersionManagerTest extends TestCase
|
|||
$this->assertArrayHasKey('1.0.5', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider versionInfoProvider
|
||||
*
|
||||
* @param $versionInfo
|
||||
* @param $expectedComments
|
||||
* @param $expectedScripts
|
||||
*/
|
||||
public function testExtractScriptsAndComments($versionInfo, $expectedComments, $expectedScripts)
|
||||
{
|
||||
$manager = VersionManager::instance();
|
||||
list($comments, $scripts) = self::callProtectedMethod($manager, 'extractScriptsAndComments', [$versionInfo]);
|
||||
|
||||
$this->assertInternalType('array', $comments);
|
||||
$this->assertInternalType('array', $scripts);
|
||||
|
||||
$this->assertEquals($expectedComments, $comments);
|
||||
$this->assertEquals($expectedScripts, $scripts);
|
||||
}
|
||||
|
||||
public function versionInfoProvider()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'A single update comment string',
|
||||
[
|
||||
'A single update comment string'
|
||||
],
|
||||
[]
|
||||
],
|
||||
[
|
||||
[
|
||||
'A classic update comment string followed by script',
|
||||
'update_script.php'
|
||||
],
|
||||
[
|
||||
'A classic update comment string followed by script'
|
||||
],
|
||||
[
|
||||
'update_script.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'An update comment string after the script',
|
||||
],
|
||||
[
|
||||
'An update comment string after the script'
|
||||
],
|
||||
[
|
||||
'scripts_can_go_first.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'An update comment string after the script',
|
||||
'scripts_can_go_anywhere.php',
|
||||
],
|
||||
[
|
||||
'An update comment string after the script'
|
||||
],
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'scripts_can_go_anywhere.php'
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'The first update comment',
|
||||
'scripts_can_go_anywhere.php',
|
||||
'The second update comment',
|
||||
],
|
||||
[
|
||||
'The first update comment',
|
||||
'The second update comment'
|
||||
],
|
||||
[
|
||||
'scripts_can_go_first.php',
|
||||
'scripts_can_go_anywhere.php'
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,19 +16,6 @@ class AssetMakerTest extends TestCase
|
|||
$this->stub = new AssetMakerStub();
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
protected static function callProtectedMethod($object, $name, $params = [])
|
||||
{
|
||||
$className = get_class($object);
|
||||
$class = new ReflectionClass($className);
|
||||
$method = $class->getMethod($name);
|
||||
$method->setAccessible(true);
|
||||
return $method->invokeArgs($object, $params);
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue