Merge branch 'feature/9370-uninstallation' into feature/uninstallation

This commit is contained in:
Eric Espie
2026-03-18 10:14:40 +01:00
5 changed files with 75 additions and 51 deletions

View File

@@ -88,11 +88,10 @@ class DataFeatureRemovalController extends Controller
private function Analyze(): void private function Analyze(): void
{ {
$sSourceEnv = MetaModel::GetEnvironment(); $sSourceEnv = MetaModel::GetEnvironment();
$oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment(); $oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $this->aSelectedExtensionsForCheck);
$oDryRemovalRuntimeEnvironment->Prepare($sSourceEnv, $this->aSelectedExtensionsForCheck);
$oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnv); $oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnv);
$oSetupAudit = new SetupAudit($sSourceEnv, DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV); $oSetupAudit = new SetupAudit($sSourceEnv);
$aGetRemovedClasses = $oSetupAudit->GetIssues(); $aGetRemovedClasses = $oSetupAudit->GetIssues();
IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
$this->aCountClassesToCleanup = $aGetRemovedClasses; $this->aCountClassesToCleanup = $aGetRemovedClasses;

View File

@@ -14,45 +14,35 @@ use utils;
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
{ {
public const DRY_REMOVAL_AUDIT_ENV = "extension-removal";
protected array $aExtensionsByCode; protected array $aExtensionsByCode;
/** /**
* Toolset for building a run-time environment * Toolset for building a run-time environment
* *
* @param string $sEnvironment (e.g. 'test') * @param string $sSourceEnv: environment from which setup is inspired to simulate extension removal and usee CompileFrom...
* @param bool $bAutoCommit (make the target environment directly, or build a temporary one)
*/ */
public function __construct($sEnvironment = self::DRY_REMOVAL_AUDIT_ENV, $bAutoCommit = true) public function __construct($sSourceEnv = 'production', array $aExtensionCodesToRemove = [])
{ {
parent::__construct($sEnvironment, $bAutoCommit); parent::__construct($sSourceEnv, false);
$this->aExtensionsByCode = []; $this->aExtensionsByCode = $aExtensionCodesToRemove;
$this->Prepare($sSourceEnv, $this->sTargetEnv);
} }
/** /**
* @param string $sSourceEnv * @param string $sSourceEnv
* @param array $aExtensionCodesToRemove * @param string $sTargetEnv
* * @return void
* @return void * @throws \MissingDependencyException
* @throws \Exception
*/ */
public function Prepare(string $sSourceEnv, array $aExtensionCodesToRemove) private function Prepare(string $sSourceEnv, string $sTargetEnv)
{ {
$sEnv = $this->sFinalEnv;
$this->aExtensionsByCode = $aExtensionCodesToRemove;
$this->Cleanup(); $this->Cleanup();
SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sEnv-modules"); SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sTargetEnv-modules");
SetupUtils::copydir(APPROOT."/conf/$sSourceEnv", APPROOT."/conf/$sTargetEnv");
$this->DeclareExtensionAsRemoved($aExtensionCodesToRemove); $this->DeclareExtensionAsRemoved($this->aExtensionsByCode);
$oDryRemovalConfig = clone(MetaModel::GetConfig()); $sSourceDir = MetaModel::GetConfig()->Get('source_dir');
$oDryRemovalConfig->ChangeModulesPath($sSourceEnv, $this->sFinalEnv);
$this->WriteConfigFileSafe($oDryRemovalConfig);
$sSourceDir = $oDryRemovalConfig->Get('source_dir');
$aSearchDirs = $this->GetExtraDirsToCompile($sSourceDir); $aSearchDirs = $this->GetExtraDirsToCompile($sSourceDir);
$aModulesToLoad = $this->GetModulesToLoad($sSourceEnv, $aSearchDirs); $aModulesToLoad = $this->GetModulesToLoad($sSourceEnv, $aSearchDirs);
@@ -67,7 +57,7 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
private function DeclareExtensionAsRemoved(array $aExtensionCodes): void private function DeclareExtensionAsRemoved(array $aExtensionCodes): void
{ {
$oExtensionsMap = new iTopExtensionsMap($this->sFinalEnv); $oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv);
$oExtensionsMap->DeclareExtensionAsRemoved($aExtensionCodes); $oExtensionsMap->DeclareExtensionAsRemoved($aExtensionCodes);
} }
@@ -92,13 +82,31 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
return $aModulesToLoad; return $aModulesToLoad;
} }
public function Cleanup() public function Cleanup(): void
{ {
$sEnv = $this->sFinalEnv; $sEnv = $this->sTargetEnv;
SetupUtils::rrmdir(APPROOT."/data/$sEnv-modules");
SetupUtils::rrmdir(APPROOT."/data/cache-$sEnv"); //keep this folder empty
SetupUtils::rrmdir(APPROOT."/env-$sEnv"); SetupUtils::tidydir(APPROOT."/env-$sEnv");
SetupUtils::rrmdir(APPROOT."/conf/$sEnv");
@unlink(APPROOT."/data/datamodel-$sEnv.xml"); $aFolders = [
APPROOT."/data/$sEnv-modules",
APPROOT."/data/cache-$sEnv",
APPROOT."/conf/$sEnv",
];
foreach ($aFolders as $sFolder) {
SetupUtils::tidydir($sFolder);
SetupUtils::rmdir_safe($sFolder);
}
$sFiles = [
APPROOT."/data/datamodel-$sEnv.xml",
APPROOT."/data/$sEnv.delta.prev.xml",
];
foreach ($sFiles as $sFile) {
if (is_file($sFile)) {
@unlink($sFile);
}
}
} }
} }

View File

@@ -7,17 +7,14 @@ require_once APPROOT.'setup/feature_removal/ModelReflectionSerializer.php';
class SetupAudit extends AbstractSetupAudit class SetupAudit extends AbstractSetupAudit
{ {
//file used when present to trigger audit exception when testing specific setups
public const GETISSUE_ERROR_MSG_FILE_FORTESTONLY = '.setup_audit_error_msg.txt';
private string $sEnvBefore; private string $sEnvBefore;
private string $sEnvAfter; private string $sEnvAfter;
public function __construct(string $sEnvBefore, string $sEnvAfter) public function __construct(string $sEnvBefore)
{ {
parent::__construct(); parent::__construct();
$this->sEnvBefore = $sEnvBefore; $this->sEnvBefore = $sEnvBefore;
$this->sEnvAfter = $sEnvAfter; $this->sEnvAfter = "$sEnvBefore-build";
} }
public function ComputeClasses(): void public function ComputeClasses(): void

View File

@@ -25,6 +25,7 @@ require_once APPROOT.'setup/feature_removal/SetupAudit.php';
require_once(APPROOT.'setup/sequencers/StepSequencer.php'); require_once(APPROOT.'setup/sequencers/StepSequencer.php');
require_once(APPROOT.'setup/sequencers/ApplicationInstallSequencer.php'); require_once(APPROOT.'setup/sequencers/ApplicationInstallSequencer.php');
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit; use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
class DataAuditSequencer extends ApplicationInstallSequencer class DataAuditSequencer extends ApplicationInstallSequencer
@@ -34,7 +35,7 @@ class DataAuditSequencer extends ApplicationInstallSequencer
protected function GetTempEnv() protected function GetTempEnv()
{ {
$sTargetEnv = $this->GetTargetEnv(); $sTargetEnv = $this->GetTargetEnv();
return 'dry-'.$sTargetEnv; return $sTargetEnv.'-build';
} }
protected function GetTargetDir() protected function GetTargetDir()
@@ -177,10 +178,9 @@ class DataAuditSequencer extends ApplicationInstallSequencer
*/ */
$oContextTag = new ContextTag(ContextTag::TAG_SETUP); $oContextTag = new ContextTag(ContextTag::TAG_SETUP);
$sTargetEnvironment = $this->GetTempEnv();
$sPreviousEnvironment = $this->GetTargetEnv(); $sPreviousEnvironment = $this->GetTargetEnv();
$oSetupAudit = new SetupAudit($sPreviousEnvironment, $sTargetEnvironment); $oSetupAudit = new SetupAudit($sPreviousEnvironment);
//Make sure the MetaModel is started before analysing for issues //Make sure the MetaModel is started before analysing for issues
$sConfFile = utils::GetConfigFilePath($sPreviousEnvironment); $sConfFile = utils::GetConfigFilePath($sPreviousEnvironment);
@@ -195,8 +195,29 @@ class DataAuditSequencer extends ApplicationInstallSequencer
protected function DoCleanup() protected function DoCleanup()
{ {
$sDestination = APPROOT.$this->GetTargetDir(); $sEnv = $this->GetTempEnv();
SetupUtils::tidydir($sDestination);
SetupUtils::rmdir_safe($sDestination); //keep this folder empty
SetupUtils::tidydir(APPROOT."/env-$sEnv");
$aFolders = [
APPROOT."/data/$sEnv-modules",
APPROOT."/data/cache-$sEnv",
APPROOT."/conf/$sEnv",
];
foreach ($aFolders as $sFolder) {
SetupUtils::tidydir($sFolder);
SetupUtils::rmdir_safe($sFolder);
}
$sFiles = [
APPROOT."/data/datamodel-$sEnv.xml",
APPROOT."/data/$sEnv.delta.prev.xml",
];
foreach ($sFiles as $sFile) {
if (is_file($sFile)) {
@unlink($sFile);
}
}
} }
} }

View File

@@ -51,11 +51,10 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
public function testComputeDryRemoval() public function testComputeDryRemoval()
{ {
$oDryRemovalRuntimeEnvt = new DryRemovalRuntimeEnvironment(); $oDryRemovalRuntimeEnvt = new DryRemovalRuntimeEnvironment($this->GetTestEnvironment(), ['nominal_ext1', 'finalclass_ext2']);
$oDryRemovalRuntimeEnvt->Prepare($this->GetTestEnvironment(), ['nominal_ext1', 'finalclass_ext2']);
$oDryRemovalRuntimeEnvt->CompileFrom($this->GetTestEnvironment()); $oDryRemovalRuntimeEnvt->CompileFrom($this->GetTestEnvironment());
$oSetupAudit = new SetupAudit(MetaModel::GetEnvironment(), DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV); $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment());
$expected = [ $expected = [
"Feature1Module1MyClass", "Feature1Module1MyClass",
@@ -88,7 +87,7 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
$oOrg = $this->CreateOrganization($sUID); $oOrg = $this->CreateOrganization($sUID);
$this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); $this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
$oSetupAudit = new SetupAudit(MetaModel::GetEnvironment(), DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV); $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment());
$aRemovedClasses = [ $aRemovedClasses = [
"Feature1Module1MyClass", "Feature1Module1MyClass",
"FinalClassFeature1Module1MyClass", "FinalClassFeature1Module1MyClass",
@@ -114,7 +113,7 @@ class SetupAuditTest extends ItopCustomDatamodelTestCase
$this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); $this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
$this->createObject('FinalClassFeature2Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); $this->createObject('FinalClassFeature2Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]);
$oSetupAudit = new SetupAudit(MetaModel::GetEnvironment(), DryRemovalRuntimeEnvironment::DRY_REMOVAL_AUDIT_ENV); $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment());
$aRemovedClasses = [ $aRemovedClasses = [
"Feature1Module1MyClass", "Feature1Module1MyClass",
"FinalClassFeature1Module1MyClass", "FinalClassFeature1Module1MyClass",