mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°8760 - setupaudit and dry removal API review with Romain - avoid file deletion
N°8760 - be able to simulate extension removal by oerriding GetExtensionMap be able to simulate SetupAudit errors in Setups for integration tests fix rebase
This commit is contained in:
@@ -135,7 +135,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
|
||||
$aAvailableModules[$oModule->GetName()] = $oModule;
|
||||
}
|
||||
// TODO check the auto-selected modules here
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
if ($oExtension->bMarkedAsChosen) {
|
||||
foreach ($oExtension->aModules as $sModuleName) {
|
||||
if (!isset($aRet[$sModuleName]) && isset($aAvailableModules[$sModuleName])) {
|
||||
|
||||
@@ -477,7 +477,7 @@ class MFCompiler
|
||||
$sClass = $oClass->getAttribute("id");
|
||||
$aAllClasses[] = $sClass;
|
||||
try {
|
||||
$sCompiledCode .= $this->CompileClass($oClass, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
|
||||
$sCompiledCode .= $this->CompileClass($oClass, $sModuleName, $sTempTargetDir, $sFinalTargetDir, $sRelativeDir);
|
||||
} catch (DOMFormatException $e) {
|
||||
$sMessage = "Failed to process class '$sClass', ";
|
||||
if (!empty($sModuleRootDir)) {
|
||||
|
||||
@@ -148,14 +148,12 @@ class iTopExtensionsMap
|
||||
{
|
||||
/**
|
||||
* The list of all discovered extensions
|
||||
* @param string $sFromEnvironment The environment to scan
|
||||
* @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format
|
||||
* @return void
|
||||
* @var array $aExtensions
|
||||
*/
|
||||
protected $aExtensions;
|
||||
/**
|
||||
* The list of all currently installed extensions
|
||||
* @var array
|
||||
* @var array $aInstalledExtensions
|
||||
*/
|
||||
protected array $aInstalledExtensions;
|
||||
|
||||
@@ -166,6 +164,12 @@ class iTopExtensionsMap
|
||||
*/
|
||||
protected $aScannedDirs;
|
||||
|
||||
/**
|
||||
* The list of all discovered extensions
|
||||
* @param string $sFromEnvironment The environment to scan
|
||||
* @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($sFromEnvironment = 'production', $aExtraDirs = [])
|
||||
{
|
||||
$this->aExtensions = [];
|
||||
@@ -276,6 +280,21 @@ class iTopExtensionsMap
|
||||
$this->aExtensionsByCode[$oNewExtension->sCode] = $oNewExtension;
|
||||
}
|
||||
|
||||
public function RemoveExtension(string $sCode): void
|
||||
{
|
||||
$oExtension = $this->Get($sCode);
|
||||
if (is_null($oExtension)) {
|
||||
\IssueLog::Error(__METHOD__.": cannot find extension to remove", null, [$sCode]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
\IssueLog::Debug(__METHOD__.": remove extension from map", null, [$oExtension->sCode => $oExtension->sSourceDir]);
|
||||
|
||||
unset($this->aExtensions[$oExtension->sCode.'/'.$oExtension->sVersion]);
|
||||
unset($this->aExtensionsByCode[$sCode]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.3.0
|
||||
* @param string $sExtensionCode
|
||||
@@ -287,7 +306,7 @@ class iTopExtensionsMap
|
||||
return $this->aExtensionsByCode[$sExtensionCode] ?? null;
|
||||
}
|
||||
|
||||
public function GetMissingExtensions(array $aSelectedExtensions)
|
||||
/*public function GetMissingExtensions(array $aSelectedExtensions)
|
||||
{
|
||||
\SetupLog::Info(__METHOD__, null, ['selected' => $aSelectedExtensions]);
|
||||
$aExtensionsFromDb = array_keys($this->aExtensionsByCode);
|
||||
@@ -308,8 +327,7 @@ class iTopExtensionsMap
|
||||
\SetupLog::Info(__METHOD__, null, $aRes);
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Read (recursively) a directory to find if it contains extensions (or modules)
|
||||
@@ -494,7 +512,6 @@ class iTopExtensionsMap
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function MarkAsUninstallable($sExtensionCode, $bMark = true)
|
||||
{
|
||||
$oExtension = $this->Get($sExtensionCode);
|
||||
@@ -624,4 +641,4 @@ class iTopExtensionsMap
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
66
setup/feature_removal/DryRemovalRuntimeEnvironment.php
Normal file
66
setup/feature_removal/DryRemovalRuntimeEnvironment.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use iTopExtensionsMap;
|
||||
use RunTimeEnvironment;
|
||||
use SetupUtils;
|
||||
|
||||
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
const DRY_REMOVAL_AUDIT_ENV = "extension-removal";
|
||||
|
||||
protected array $aExtensionsByCode;
|
||||
private bool $bExtensionMapModified = false;
|
||||
|
||||
/**
|
||||
* Toolset for building a run-time environment
|
||||
*
|
||||
* @param string $sEnvironment (e.g. 'test')
|
||||
* @param bool $bAutoCommit (make the target environment directly, or build a temporary one)
|
||||
*/
|
||||
public function __construct($sEnvironment = self::DRY_REMOVAL_AUDIT_ENV, $bAutoCommit = true)
|
||||
{
|
||||
parent::__construct($sEnvironment, $bAutoCommit);
|
||||
$this->aExtensionsByCode = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sSourceEnv
|
||||
* @param array $aExtensionCodesToRemove
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function Prepare(string $sSourceEnv, array $aExtensionCodesToRemove)
|
||||
{
|
||||
|
||||
$sEnv = $this->sFinalEnv;
|
||||
$this->aExtensionsByCode = $aExtensionCodesToRemove;
|
||||
SetupUtils::rrmdir(APPROOT."/data/$sEnv-modules");
|
||||
SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/".$this->sFinalEnv."-modules");
|
||||
|
||||
/*$oDryRemovalConfig = clone(MetaModel::GetConfig());
|
||||
$oDryRemovalConfig->ChangeModulesPath($sSourceEnv, $this->sFinalEnv);
|
||||
$this->WriteConfigFileSafe($oDryRemovalConfig);*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \iTopExtensionsMap|null
|
||||
*/
|
||||
protected function GetExtensionMap(): ?iTopExtensionsMap
|
||||
{
|
||||
if (is_null(parent::GetExtensionMap())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->bExtensionMapModified) {
|
||||
$this->bExtensionMapModified = true;
|
||||
foreach ($this->aExtensionsByCode as $sCode) {
|
||||
parent::GetExtensionMap()->RemoveExtension($sCode);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::GetExtensionMap();
|
||||
}
|
||||
}
|
||||
55
setup/feature_removal/ModelReflectionSerializer.php
Normal file
55
setup/feature_removal/ModelReflectionSerializer.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use CoreException;
|
||||
use Exception;
|
||||
|
||||
class ModelReflectionSerializer
|
||||
{
|
||||
private static ModelReflectionSerializer $oInstance;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
final public static function GetInstance(): ModelReflectionSerializer
|
||||
{
|
||||
if (!isset(self::$oInstance)) {
|
||||
self::$oInstance = new ModelReflectionSerializer();
|
||||
}
|
||||
|
||||
return self::$oInstance;
|
||||
}
|
||||
|
||||
final public static function SetInstance(?ModelReflectionSerializer $oInstance): void
|
||||
{
|
||||
self::$oInstance = $oInstance;
|
||||
}
|
||||
|
||||
public function GetModelFromEnvironment(string $sEnv): array
|
||||
{
|
||||
\IssueLog::Info(__METHOD__, null, ['env' => $sEnv]);
|
||||
$sPHPExec = trim(\MetaModel::GetConfig()->Get('php_path'));
|
||||
$sOutput = "";
|
||||
$iRes = 0;
|
||||
exec(sprintf("$sPHPExec %s/get_model_reflection.php --env='%s'", __DIR__, $sEnv), $sOutput, $iRes);
|
||||
if ($iRes != 0) {
|
||||
\IssueLog::Error("Cannot get classes", null, ['code' => $iRes, "output" => $sOutput]);
|
||||
throw new CoreException("Cannot get classes");
|
||||
}
|
||||
|
||||
$aClasses = json_decode($sOutput[0] ?? null, true);
|
||||
if (false === $aClasses) {
|
||||
\IssueLog::Error("Invalid JSON", null, ["output" => $sOutput]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
if (!is_array($aClasses)) {
|
||||
\IssueLog::Error("not an array", null, ["classes" => $aClasses]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
return $aClasses;
|
||||
}
|
||||
}
|
||||
@@ -2,35 +2,48 @@
|
||||
|
||||
namespace Combodo\iTop\Setup\FeatureRemoval;
|
||||
|
||||
use Config;
|
||||
use CoreException;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use RunTimeEnvironment;
|
||||
use SetupUtils;
|
||||
|
||||
require_once APPROOT.'setup/feature_removal/ModelReflectionSerializer.php';
|
||||
|
||||
class SetupAudit
|
||||
{
|
||||
const DRY_REMOVAL_AUDIT_ENV = "extension-removal";
|
||||
//file used when present to trigger audit exception when testing specific setups
|
||||
const GETISSUE_ERROR_MSG_FILE_FORTESTONLY = '.setup_audit_error_msg.txt';
|
||||
|
||||
private string $sEnvBeforeExtensionRemoval;
|
||||
private string $sEnvAfterExtensionRemoval;
|
||||
|
||||
private array $aClassesBeforeRemoval;
|
||||
private array $aClassesAfterRemoval;
|
||||
private array $aExtensionToRemove;
|
||||
private array $aRemovedClasses;
|
||||
private array $aFinalClassesRemoved;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(string $sEnvBeforeExtensionRemoval, string $sEnvAfterExtensionRemoval = DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV)
|
||||
{
|
||||
$this->aExtensionToRemove = [];
|
||||
$this->aClassesBeforeRemoval = [];
|
||||
$this->aClassesAfterRemoval = [];
|
||||
$this->sEnvBeforeExtensionRemoval = $sEnvBeforeExtensionRemoval;
|
||||
$this->sEnvAfterExtensionRemoval = $sEnvAfterExtensionRemoval;
|
||||
|
||||
$sCurrentEnvt = MetaModel::GetEnvironment();
|
||||
if ($sCurrentEnvt === $this->sEnvBeforeExtensionRemoval) {
|
||||
$this->aClassesBeforeRemoval = MetaModel::GetClasses();
|
||||
} else {
|
||||
$this->aClassesBeforeRemoval = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvBeforeExtensionRemoval);
|
||||
}
|
||||
|
||||
if ($sCurrentEnvt === $this->sEnvAfterExtensionRemoval) {
|
||||
$this->aClassesAfterRemoval = MetaModel::GetClasses();
|
||||
} else {
|
||||
$this->aClassesAfterRemoval = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfterExtensionRemoval);
|
||||
}
|
||||
|
||||
$this->aRemovedClasses = [];
|
||||
$this->aFinalClassesRemoved = [];
|
||||
}
|
||||
|
||||
public function SetSelectedExtensions(Config $oConfig, array $aSelectedExtensions)
|
||||
/*public function SetSelectedExtensions(Config $oConfig, array $aSelectedExtensions)
|
||||
{
|
||||
$oExtensionsMap = new \iTopExtensionsMap();
|
||||
$oExtensionsMap->LoadChoicesFromDatabase($oConfig);
|
||||
@@ -39,103 +52,7 @@ class SetupAudit
|
||||
$this->aExtensionToRemove = $oExtensionsMap->GetMissingExtensions($aSelectedExtensions);
|
||||
sort($this->aExtensionToRemove);
|
||||
\SetupLog::Info(__METHOD__, null, ['aExtensionToRemove' => $this->aExtensionToRemove]);
|
||||
}
|
||||
|
||||
public function ComputeClassesBeforeRemoval(string $sTargetEnv)
|
||||
{
|
||||
$this->aClassesBeforeRemoval = $this->GetModelFromEnvironment($sTargetEnv);
|
||||
}
|
||||
|
||||
public function SetClassesAfterRemovalFromCurrentEnv()
|
||||
{
|
||||
$this->aClassesAfterRemoval = MetaModel::GetClasses();
|
||||
}
|
||||
|
||||
public function SetClassesBeforeRemovalFromCurrentEnv()
|
||||
{
|
||||
$this->aClassesBeforeRemoval = MetaModel::GetClasses();
|
||||
}
|
||||
|
||||
public function ComputeDryExtensionRemoval(array $aExtensionToRemove): void
|
||||
{
|
||||
$this->aExtensionToRemove = $aExtensionToRemove;
|
||||
|
||||
if (count($this->aExtensionToRemove) == 0) {
|
||||
//avoid time consuming setup audit when no extension removed
|
||||
return;
|
||||
}
|
||||
|
||||
$sDryRemovalEnv = self::DRY_REMOVAL_AUDIT_ENV;
|
||||
self::Cleanup($sDryRemovalEnv);
|
||||
|
||||
$sSourceEnvt = MetaModel::GetEnvironment();
|
||||
|
||||
$oDryRemovalRuntimeEnvt = new RunTimeEnvironment($sDryRemovalEnv);
|
||||
$oDryRemovalConfig = clone(MetaModel::GetConfig());
|
||||
$oDryRemovalConfig->ChangeModulesPath($sSourceEnvt, $sDryRemovalEnv);
|
||||
|
||||
$oDryRemovalRuntimeEnvt->WriteConfigFileSafe($oDryRemovalConfig);
|
||||
SetupUtils::copydir(APPROOT."/data/$sSourceEnvt-modules", APPROOT."/data/$sDryRemovalEnv-modules");
|
||||
$this->RemoveExtensionsLocally($sDryRemovalEnv, $this->aExtensionToRemove);
|
||||
|
||||
$oDryRemovalRuntimeEnvt->CompileFrom($sSourceEnvt);
|
||||
|
||||
$this->aClassesAfterRemoval = $this->GetModelFromEnvironment($sDryRemovalEnv);
|
||||
|
||||
$oDryRemovalRuntimeEnvt->Rollback();
|
||||
self::Cleanup($sDryRemovalEnv);
|
||||
}
|
||||
|
||||
public static function Cleanup(string $sEnv)
|
||||
{
|
||||
SetupUtils::rrmdir(APPROOT."/data/$sEnv-modules");
|
||||
SetupUtils::rrmdir(APPROOT."/data/cache-$sEnv");
|
||||
SetupUtils::rrmdir(APPROOT."/env-$sEnv");
|
||||
SetupUtils::rrmdir(APPROOT."/conf/$sEnv");
|
||||
@unlink(APPROOT."/data/datamodel-$sEnv.xml");
|
||||
}
|
||||
|
||||
public function GetModelFromEnvironment(string $sEnv): array
|
||||
{
|
||||
$sPHPExec = trim(\MetaModel::GetConfig()->Get('php_path'));
|
||||
$sOutput = "";
|
||||
$iRes = 0;
|
||||
exec(sprintf("$sPHPExec %s/get_model_reflection.php --env='%s'", __DIR__, $sEnv), $sOutput, $iRes);
|
||||
if ($iRes != 0) {
|
||||
\IssueLog::Error("Cannot get classes", null, ['code' => $iRes, "output" => $sOutput]);
|
||||
throw new CoreException("Cannot get classes");
|
||||
}
|
||||
|
||||
$aClasses = json_decode($sOutput[0] ?? null, true);
|
||||
if (false === $aClasses) {
|
||||
\IssueLog::Error("Invalid JSON", null, ["output" => $sOutput]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
if (!is_array($aClasses)) {
|
||||
\IssueLog::Error("not an array", null, ["classes" => $aClasses]);
|
||||
throw new Exception("cannot get classes");
|
||||
}
|
||||
|
||||
return $aClasses;
|
||||
}
|
||||
|
||||
private function RemoveExtensionsLocally(string $sTargetEnv, array $aExtensionCodes): void
|
||||
{
|
||||
$oExtensionsMap = new \iTopExtensionsMap($sTargetEnv);
|
||||
|
||||
foreach ($aExtensionCodes as $sCode) {
|
||||
/** @var \iTopExtension $oExtension */
|
||||
$oExtension = $oExtensionsMap->Get($sCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$sDir = $oExtension->sSourceDir;
|
||||
\IssueLog::Info(__METHOD__.": remove extension locally", null, [$oExtension->sCode => $sDir]);
|
||||
SetupUtils::rrmdir($sDir);
|
||||
} else {
|
||||
\IssueLog::Warning(__METHOD__." cannot find extensions", null, ['env' => $sTargetEnv, 'code' => $sCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
public function GetRemovedClasses(): array
|
||||
{
|
||||
@@ -161,8 +78,23 @@ class SetupAudit
|
||||
return $this->aRemovedClasses;
|
||||
}
|
||||
|
||||
public function AuditExtensionsCleanupRules(bool $bStopAtFirstIssue = false): array
|
||||
/** test only: return file path that force audit error being raised
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetErrorMessageFilePathForTestOnly(): string
|
||||
{
|
||||
return APPROOT."/data/".self::GETISSUE_ERROR_MSG_FILE_FORTESTONLY;
|
||||
}
|
||||
|
||||
public function GetIssues(bool $bThrowExceptionAtFirstIssue = false): array
|
||||
{
|
||||
$sErrorMessageFilePath = self::GetErrorMessageFilePathForTestOnly();
|
||||
if ($bThrowExceptionAtFirstIssue && is_file($sErrorMessageFilePath)) {
|
||||
$sMsg = file_get_contents($sErrorMessageFilePath);
|
||||
throw new \Exception($sMsg);
|
||||
}
|
||||
|
||||
$this->aFinalClassesRemoved = [];
|
||||
|
||||
foreach ($this->GetRemovedClasses() as $sClass) {
|
||||
@@ -173,7 +105,7 @@ class SetupAudit
|
||||
if (!MetaModel::IsStandaloneClass($sClass)) {
|
||||
$iCount = $this->Count($sClass);
|
||||
$this->aFinalClassesRemoved[$sClass] = $iCount;
|
||||
if ($bStopAtFirstIssue && $iCount > 0) {
|
||||
if ($bThrowExceptionAtFirstIssue && $iCount > 0) {
|
||||
//setup envt: should raise issue ASAP
|
||||
throw new \Exception($sClass);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ try {
|
||||
MetaModel::Startup($sConfFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv);
|
||||
}
|
||||
catch (\Throwable $e) {
|
||||
\IssueLog::Error("Cannot read model from provided environment", null,
|
||||
echo $e->getMessage();
|
||||
echo $e->getTraceAsString();
|
||||
\SetupLog::Error("Cannot read model from provided environment", null,
|
||||
[
|
||||
'env' => $sEnv,
|
||||
'error' => $e->getMessage(),
|
||||
|
||||
@@ -62,7 +62,23 @@ class RunTimeEnvironment
|
||||
* Extensions map of the source environment
|
||||
* @var iTopExtensionsMap
|
||||
*/
|
||||
protected $oExtensionsMap;
|
||||
protected ?iTopExtensionsMap $oExtensionsMap;
|
||||
|
||||
protected function GetExtensionMap(): ?iTopExtensionsMap
|
||||
{
|
||||
return $this->oExtensionsMap;
|
||||
}
|
||||
|
||||
public function InitExtensionMap($aExtraDirs, $oSourceConfig)
|
||||
{
|
||||
// Actually read the modules available for the target environment,
|
||||
// but get the selection from the source environment and finally
|
||||
// mark as (automatically) chosen alll the "remote" modules present in the
|
||||
// target environment (data/<target-env>-modules)
|
||||
// The actual choices will be recorded by RecordInstallation below
|
||||
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv, true, $aExtraDirs);
|
||||
$this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolset for building a run-time environment
|
||||
@@ -241,20 +257,22 @@ class RunTimeEnvironment
|
||||
|
||||
// Actually read the modules available for the target environment,
|
||||
// but get the selection from the source environment and finally
|
||||
// mark as (automatically) chosen alll the "remote" modules present in the
|
||||
// mark as (automatically) chosen all the "remote" modules present in the
|
||||
// target environment (data/<target-env>-modules)
|
||||
// The actual choices will be recorded by RecordInstallation below
|
||||
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv, $aExtraDirs);
|
||||
$this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig);
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
$this->InitExtensionMap($aExtraDirs, $oSourceConfig);
|
||||
$this->GetExtensionMap()->LoadChoicesFromDatabase($oSourceConfig);
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
if ($this->IsExtensionSelected($oExtension)) {
|
||||
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
$this->GetExtensionMap()->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Do load the required modules
|
||||
//
|
||||
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
|
||||
|
||||
$aRet = [];
|
||||
$aRet[$oDictModule->GetName()] = $oDictModule;
|
||||
|
||||
$oFactory = new ModelFactory($aDirsToCompile);
|
||||
@@ -273,7 +291,7 @@ class RunTimeEnvironment
|
||||
foreach ($aModules as $oModule) {
|
||||
$sModule = $oModule->GetName();
|
||||
$sModuleRootDir = $oModule->GetRootDir();
|
||||
$bIsExtra = $this->oExtensionsMap->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE);
|
||||
$bIsExtra = $this->GetExtensionMap()->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE);
|
||||
if (array_key_exists($sModule, $aAvailableModules)) {
|
||||
if (($aAvailableModules[$sModule]['installed_version'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect'
|
||||
$aRet[$oModule->GetName()] = $oModule;
|
||||
@@ -532,7 +550,6 @@ class RunTimeEnvironment
|
||||
|
||||
// Record installed modules and extensions
|
||||
//
|
||||
$aAvailableExtensions = [];
|
||||
$aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir());
|
||||
foreach ($aSelectedModuleCodes as $sModuleId) {
|
||||
if (!array_key_exists($sModuleId, $aAvailableModules)) {
|
||||
@@ -573,16 +590,17 @@ class RunTimeEnvironment
|
||||
$oInstallRec->DBInsertNoReload();
|
||||
}
|
||||
|
||||
if ($this->oExtensionsMap) {
|
||||
if ($this->GetExtensionMap()) {
|
||||
// Mark as chosen the selected extensions code passed to us
|
||||
|
||||
// Note: some other extensions may already be marked as chosen
|
||||
foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) {
|
||||
if (in_array($oExtension->sCode, $aSelectedExtensionCodes)) {
|
||||
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
|
||||
$this->GetExtensionMap()->MarkAsChosen($oExtension->sCode);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->oExtensionsMap->GetChoices() as $oExtension) {
|
||||
foreach ($this->GetExtensionMap()->GetChoices() as $oExtension) {
|
||||
$oInstallRec = new ExtensionInstallation();
|
||||
$oInstallRec->Set('code', $oExtension->sCode);
|
||||
$oInstallRec->Set('label', $oExtension->sLabel);
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException;
|
||||
|
||||
require_once(APPROOT.'setup/setuputils.class.inc.php');
|
||||
@@ -2117,8 +2116,8 @@ class WizStepSummary extends WizardStep
|
||||
try {
|
||||
SetupUtils::AnalyzeInstallation($this->oWizard, true, $aSelectedModules);
|
||||
|
||||
$sInstallMode = utils::ReadParam('install_mode');
|
||||
\SetupLog::Info(__METHOD__, null, ['install_mode' => $sInstallMode]);
|
||||
/*$sInstallMode = utils::ReadParam('install_mode');
|
||||
\SetupLog::Info(__METHOD__, null, ['$sInstallMode' => $sInstallMode]);
|
||||
//if ($sInstallMode === "upgrade") {
|
||||
$aExtensions = json_decode($this->oWizard->GetParameter('selected_extensions'), true);
|
||||
$oSetupAudit = new SetupAudit([]);
|
||||
@@ -2127,7 +2126,7 @@ class WizStepSummary extends WizardStep
|
||||
$oSetupAudit->SetSelectedExtensions($oConfig, $aExtensions);
|
||||
//$oSetupAudit->AuditExtensionsCleanupRules(true);
|
||||
//}
|
||||
|
||||
*/
|
||||
}
|
||||
catch(MissingDependencyException $e)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup\FeatureRemoval;
|
||||
|
||||
use Combodo\iTop\Setup\FeatureRemoval\ModelReflectionSerializer;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
|
||||
class ModelSerializationTest extends ItopDataTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php');
|
||||
}
|
||||
|
||||
public function testGetModelFromEnvironment()
|
||||
{
|
||||
$aModel = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->GetTestEnvironment());
|
||||
$this->assertEqualsCanonicalizing(MetaModel::GetClasses(), $aModel);
|
||||
}
|
||||
|
||||
public function testGetModelFromEnvironmentFailure()
|
||||
{
|
||||
$this->expectException(\CoreException::class);
|
||||
$this->expectExceptionMessage("Cannot get classes");
|
||||
ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment('gabuzomeu');
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Setup\FeatureRemoval;
|
||||
|
||||
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
|
||||
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
|
||||
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||
use Combodo\iTop\Test\UnitTest\Service\UnitTestRunTimeEnvironment;
|
||||
@@ -11,48 +12,6 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
|
||||
{
|
||||
const ENVT = 'php-unit-extensionremoval-tests';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
static::LoadRequiredItopFiles();
|
||||
$this->oEnvironment = new UnitTestRunTimeEnvironment(self::ENVT);
|
||||
$this->oEnvironment->bUseDelta = false;
|
||||
$this->oEnvironment->bUseAdditionalFeatures = true;
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/SetupAudit.php');
|
||||
}
|
||||
|
||||
public function GetTestEnvironment(): string
|
||||
{
|
||||
return self::ENVT;
|
||||
}
|
||||
|
||||
public function testGetModelFromEnvironment()
|
||||
{
|
||||
$oSetupAudit = new SetupAudit([]);
|
||||
|
||||
$aExpected = \MetaModel::GetClasses();
|
||||
sort($aExpected);
|
||||
|
||||
$aModel = $oSetupAudit->GetModelFromEnvironment($this->GetTestEnvironment());
|
||||
sort($aModel);
|
||||
$this->assertEquals($aExpected, $aModel);
|
||||
}
|
||||
|
||||
public function testGetModelFromEnvironmentFailure()
|
||||
{
|
||||
$oSetupAudit = new SetupAudit([]);
|
||||
|
||||
$aExpected = \MetaModel::GetClasses();
|
||||
sort($aExpected);
|
||||
|
||||
$this->expectException(\CoreException::class);
|
||||
$this->expectExceptionMessage("Cannot get classes");
|
||||
$aModel = $oSetupAudit->GetModelFromEnvironment('gabuzomeu');
|
||||
sort($aModel);
|
||||
$this->assertEquals($aExpected, $aModel);
|
||||
}
|
||||
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
//no delta: empty path provided
|
||||
@@ -70,51 +29,51 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
|
||||
return $aFeaturePaths;
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
static::LoadRequiredItopFiles();
|
||||
$this->oEnvironment = new UnitTestRunTimeEnvironment(self::ENVT);
|
||||
$this->oEnvironment->bUseDelta = false;
|
||||
$this->oEnvironment->bUseAdditionalFeatures = true;
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/SetupAudit.php');
|
||||
$this->RequireOnceItopFile('/setup/feature_removal/DryRemovalRuntimeEnvironment.php');
|
||||
}
|
||||
|
||||
public function GetTestEnvironment(): string
|
||||
{
|
||||
return self::ENVT;
|
||||
}
|
||||
|
||||
public function testComputeDryRemoval()
|
||||
{
|
||||
$oSetupAudit = new SetupAudit();
|
||||
$oSetupAudit->SetClassesBeforeRemovalFromCurrentEnv();
|
||||
$oSetupAudit->ComputeDryExtensionRemoval(['nominal_ext1', 'finalclass_ext2']);
|
||||
$aRemovedClasses = $oSetupAudit->GetRemovedClasses();
|
||||
sort($aRemovedClasses);
|
||||
$oDryRemovalRuntimeEnvt = new DryRemovalRuntimeEnvironment();
|
||||
$oDryRemovalRuntimeEnvt->Prepare($this->GetTestEnvironment(), ['nominal_ext1', 'finalclass_ext2']);
|
||||
$oDryRemovalRuntimeEnvt->CompileFrom($this->GetTestEnvironment());
|
||||
|
||||
$oSetupAudit = new SetupAudit(\MetaModel::GetEnvironment());
|
||||
|
||||
$expected = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature2Module1MyClass",
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation",
|
||||
];
|
||||
$this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetRemovedClasses());
|
||||
|
||||
sort($expected);
|
||||
$this->assertEquals($expected, $aRemovedClasses);
|
||||
}
|
||||
|
||||
public function testComputeMTPWay()
|
||||
{
|
||||
$oSetupAudit = new SetupAudit();
|
||||
$oSetupAudit->ComputeClassesBeforeRemoval('production');
|
||||
$oSetupAudit->SetClassesAfterRemovalFromCurrentEnv();
|
||||
$oSetupAudit->AuditExtensionsCleanupRules(true);
|
||||
|
||||
$oSetupAudit->SetClassesBeforeRemovalFromCurrentEnv();
|
||||
$oSetupAudit->ComputeDryExtensionRemoval(['nominal_ext1', 'finalclass_ext2']);
|
||||
$aRemovedClasses = $oSetupAudit->GetRemovedClasses();
|
||||
sort($aRemovedClasses);
|
||||
$expected = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature2Module1MyClass",
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation",
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation" => 0,
|
||||
];
|
||||
|
||||
sort($expected);
|
||||
$this->assertEquals($expected, $aRemovedClasses);
|
||||
$this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetIssues());
|
||||
}
|
||||
|
||||
public function testAuditExtensionsCleanupRules()
|
||||
public function testGetIssues()
|
||||
{
|
||||
$sUID = "AuditExtensionsCleanupRules_".uniqid();
|
||||
$oOrg = $this->CreateOrganization($sUID);
|
||||
$this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
|
||||
|
||||
$oSetupAudit = new SetupAudit();
|
||||
$oSetupAudit = new SetupAudit(\MetaModel::GetEnvironment());
|
||||
$aRemovedClasses = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature1Module1MyClass",
|
||||
@@ -126,16 +85,11 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
|
||||
//avoid setup dry computation
|
||||
$this->SetNonPublicProperty($oSetupAudit, 'aRemovedClasses', $aRemovedClasses);
|
||||
|
||||
$oRules = $oSetupAudit->AuditExtensionsCleanupRules();
|
||||
asort($oRules);
|
||||
|
||||
$expected = [
|
||||
"FinalClassFeature1Module1MyFinalClassFromLocation" => 1,
|
||||
"FinalClassFeature2Module1MyFinalClassFromLocation" => 0,
|
||||
];
|
||||
|
||||
asort($expected);
|
||||
$this->assertEquals($expected, $oRules);
|
||||
$this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetIssues());
|
||||
}
|
||||
|
||||
public function testAuditExtensionsCleanupRulesFailASAP()
|
||||
@@ -145,7 +99,7 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
|
||||
$this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
|
||||
$this->createObject('FinalClassFeature2Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
|
||||
|
||||
$oSetupAudit = new SetupAudit(['nominal_ext1', 'finalclass_ext1', 'finalclass_ext2']);
|
||||
$oSetupAudit = new SetupAudit(\MetaModel::GetEnvironment());
|
||||
$aRemovedClasses = [
|
||||
"Feature1Module1MyClass",
|
||||
"FinalClassFeature1Module1MyClass",
|
||||
@@ -159,6 +113,6 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
|
||||
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionMessage('FinalClassFeature1Module1MyFinalClassFromLocation');
|
||||
$oSetupAudit->AuditExtensionsCleanupRules(true);
|
||||
$oSetupAudit->GetIssues(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user