N°9134 Validate extension codes before installation and refine progress message styling (#909)

* N°9134 Validate extension codes before installation and refine progress message styling

* Add test for compile failure when extension code is missing
This commit is contained in:
Lenaick
2026-05-18 10:11:37 +02:00
committed by GitHub
parent b29a3b5df8
commit fb7a38c83f
4 changed files with 110 additions and 8 deletions

File diff suppressed because one or more lines are too long

View File

@@ -699,14 +699,10 @@ body {
}
}
#progress_content {
min-height: 200px;
overflow: auto;
text-align: center;
*:not(.message) + .message {
#progress_content *:not(.message) + .message {
margin-top: 1.5rem;
}
}
#fresh_content{
border: 0;
min-height: 300px;

View File

@@ -1467,6 +1467,14 @@ class RunTimeEnvironment
// Removed modules are stored as static for FindModules()
$oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes);
// Check that all the extensions have a code
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
if (empty($oExtension->sCode)) {
$sExtensionLabel = !empty($oExtension->sLabel) ? $oExtension->sLabel : $oExtension->sSourceDir;
throw new Exception(sprintf('Extension "%s" cannot be installed: Missing extension code', $sExtensionLabel));
}
}
$oFactory = new ModelFactory($aDirsToScan);
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
@@ -1566,7 +1574,7 @@ class RunTimeEnvironment
public function ExitMaintenanceMode(): void
{
if (SetupUtils::IsInMaintenanceMode()){
if (SetupUtils::IsInMaintenanceMode()) {
SetupUtils::ExitMaintenanceMode();
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Combodo\iTop\Test\UnitTest\Setup;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
use Exception;
use RunTimeEnvironment;
class RunTimeEnvironmentTest extends ItopTestCase
{
private ?string $sFixtureRootDir = null;
private ?string $sBuildDirToCleanup = null;
protected function setUp(): void
{
parent::setUp();
$this->RequireOnceItopFile('/setup/runtimeenv.class.inc.php');
}
protected function tearDown(): void
{
if (($this->sFixtureRootDir !== null) && is_dir($this->sFixtureRootDir)) {
self::RecurseRmdir($this->sFixtureRootDir);
}
if (($this->sBuildDirToCleanup !== null) && is_dir($this->sBuildDirToCleanup)) {
self::RecurseRmdir($this->sBuildDirToCleanup);
}
parent::tearDown();
}
public function testDoCompileThrowsWhenExtensionCodeIsMissing(): void
{
[$sToken, $sSourceDirRelative, $sExtensionsDirRelative] = $this->CreateFixtureContext('runtimeenv-missing-code-');
$sInvalidExtensionXml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<extension format="1.0">
<label>Broken extension</label>
<description>Test extension without code</description>
<version>1.0.0</version>
<mandatory>false</mandatory>
<more_info_url></more_info_url>
</extension>
XML;
file_put_contents(APPROOT.$sExtensionsDirRelative.'/extension.xml', $sInvalidExtensionXml);
$oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sToken);
$this->expectException(Exception::class);
$this->expectExceptionMessage('Extension "Broken extension" cannot be installed: Missing extension code');
$oRunTimeEnvironment->DoCompile([], [], $sSourceDirRelative, $sExtensionsDirRelative, false);
}
public function testDoCompileThrowsWhenExtensionCodeAndLabelAreMissing(): void
{
[$sToken, $sSourceDirRelative, $sExtensionsDirRelative] = $this->CreateFixtureContext('runtimeenv-missing-label-');
$sInvalidExtensionXml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<extension format="1.0">
<description>Test extension without code and label</description>
<version>1.0.0</version>
<mandatory>false</mandatory>
<more_info_url></more_info_url>
</extension>
XML;
$sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative;
file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml);
$oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sToken);
$this->expectException(Exception::class);
$this->expectExceptionMessage(sprintf('Extension "%s" cannot be installed: Missing extension code', $sExtensionsDirAbsolute));
$oRunTimeEnvironment->DoCompile([], [], $sSourceDirRelative, $sExtensionsDirRelative, false);
}
private function CreateFixtureContext(string $sTokenPrefix): array
{
$sToken = str_replace('.', '-', uniqid($sTokenPrefix, true));
$this->sFixtureRootDir = APPROOT.'data/'.$sToken;
$sSourceDirRelative = 'data/'.$sToken.'/source';
$sExtensionsDirRelative = 'data/'.$sToken.'/extensions';
mkdir(APPROOT.$sSourceDirRelative, 0777, true);
mkdir(APPROOT.$sExtensionsDirRelative, 0777, true);
return [$sToken, $sSourceDirRelative, $sExtensionsDirRelative];
}
private function CreateRunTimeEnvironment(string $sToken): RunTimeEnvironment
{
$oRunTimeEnvironment = new RunTimeEnvironment('test-'.$sToken, false);
$this->sBuildDirToCleanup = $oRunTimeEnvironment->GetBuildDir();
return $oRunTimeEnvironment;
}
}