diff --git a/setup/setuputils.class.inc.php b/setup/setuputils.class.inc.php index d0e2c68871..299b937d48 100644 --- a/setup/setuputils.class.inc.php +++ b/setup/setuputils.class.inc.php @@ -452,19 +452,20 @@ class SetupUtils } /** - * @param CheckResult[] $aResult checks log - * - * @since 3.0.0 N°2214 replace SetupLog::Log calls by CheckResult::TRACE + * @param CheckResult[] $aResult checks log + * @param string|null $sPhpVersion: if not provided, use current version + * @return void */ - private static function CheckPhpVersion(array &$aResult) + private static function CheckPhpVersion(array &$aResult, ?string $sPhpVersion = null, ?string $sPhpVersionDesc = null) { $aResult[] = new CheckResult(CheckResult::TRACE, 'Info - CheckPHPVersion'); - $sPhpVersion = phpversion(); + $sPhpVersion = $sPhpVersion ?? phpversion(); + $sPhpVersionDesc = $sPhpVersionDesc ?? "The current PHP Version"; if (version_compare($sPhpVersion, self::PHP_MIN_VERSION, '>=')) { $aResult[] = new CheckResult( CheckResult::INFO, - "The current PHP Version (".$sPhpVersion.") is greater than the minimum version required to run ".ITOP_APPLICATION.", which is (".self::PHP_MIN_VERSION.")" + "$sPhpVersionDesc (".$sPhpVersion.") is greater than the minimum version required to run ".ITOP_APPLICATION.", which is (".self::PHP_MIN_VERSION.")" ); $sPhpNextMinVersion = self::PHP_NEXT_MIN_VERSION; // mandatory before PHP 5.5 (arbitrary expressions), keeping compat because we're in the setup ! @@ -473,12 +474,12 @@ class SetupUtils if (version_compare($sPhpVersion, self::PHP_NEXT_MIN_VERSION, '>=')) { $aResult[] = new CheckResult( CheckResult::INFO, - "The current PHP Version (".$sPhpVersion.") is greater than the minimum version required to run next ".ITOP_APPLICATION." major release, which is (".self::PHP_NEXT_MIN_VERSION.")" + "$sPhpVersionDesc (".$sPhpVersion.") is greater than the minimum version required to run next ".ITOP_APPLICATION." major release, which is (".self::PHP_NEXT_MIN_VERSION.")" ); } else { $aResult[] = new CheckResult( CheckResult::WARNING, - "The current PHP Version (".$sPhpVersion.") is lower than the minimum version required to run next ".ITOP_APPLICATION." major release, which is (".self::PHP_NEXT_MIN_VERSION.")" + "$sPhpVersionDesc (".$sPhpVersion.") is lower than the minimum version required to run next ".ITOP_APPLICATION." major release, which is (".self::PHP_NEXT_MIN_VERSION.")" ); } } @@ -486,17 +487,61 @@ class SetupUtils if (version_compare($sPhpVersion, self::PHP_NOT_VALIDATED_VERSION, '>=')) { $aResult[] = new CheckResult( CheckResult::WARNING, - "The current PHP Version (".$sPhpVersion.") is not yet validated by Combodo. You may experience some incompatibility issues." + "$sPhpVersionDesc (".$sPhpVersion.") is not yet validated by Combodo. You may experience some incompatibility issues." ); } } else { $aResult[] = new CheckResult( CheckResult::ERROR, - "Error: The current PHP Version (".$sPhpVersion.") is lower than the minimum version required to run ".ITOP_APPLICATION.", which is (".self::PHP_MIN_VERSION.")" + "Error: $sPhpVersionDesc (".$sPhpVersion.") is lower than the minimum version required to run ".ITOP_APPLICATION.", which is (".self::PHP_MIN_VERSION.")" ); } } + /** + * @param string $sErrorLabel: error label with 1 placeholder inside for detailed error + * @return void + * @throws \ConfigException + * @throws \CoreException + */ + public static function CheckCliPhpVersionIsOk(string $sErrorLabel = '%s'): void + { + $sPHPExec = trim(utils::GetConfig()->Get('php_path')); + $aOutput = null; + $iRes = 0; + exec("$sPHPExec --version", $aOutput, $iRes); + if ($iRes != 0) { + $sError = sprintf($sErrorLabel, "Cannot check CLI/PHP version ($sPHPExec)"); + SetupLog::Error($sError, null, ['code' => $iRes, "output" => $aOutput, 'php_path' => $sPHPExec]); + throw new CoreException($sError); + } + + SetupUtils::CheckCliPhpVersionFromOutput($sErrorLabel, $sPHPExec, $aOutput); + } + + private static function CheckCliPhpVersionFromOutput(string $sErrorLabel, string $sPHPExec, $aOutput): void + { + $sFoundVersion = trim($aOutput[0] ?? ""); + if (false === preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { + // no php version parsed. no php version check is possible + // let itop work. it may raise error with less accurate symptoms in setup audit checks (composer blabla...) + return; + } + + $sFoundVersion = $aMatches[0]; + $aCheckResults = []; + self::CheckPhpVersion($aCheckResults, $sFoundVersion, 'The current CLI PHP Version'); + foreach ($aCheckResults as $oCheckRes) { + /** @var CheckResult $oCheckRes */ + if ($oCheckRes->iSeverity === CheckResult::ERROR) { + $sDetail = str_replace('Error: ', '', $oCheckRes->sLabel); + $sError = sprintf($sErrorLabel, $sDetail); + SetupLog::Error($sError, null, ["output" => $aOutput, 'php_path' => $sPHPExec]); + throw new CoreException($sError); + } + } + } + /** * Check that the selected modules meet their dependencies * @@ -2199,41 +2244,6 @@ JS return [$sButtonLabel, $sButtonUrl]; } - - /** - * @param string $sErrorLabel: error label with 1 placeholder inside for detailed error - * @return void - * @throws \ConfigException - * @throws \CoreException - */ - public static function CheckCliPhpVersionIsOk(string $sErrorLabel = '%s'): void - { - $sPHPExec = trim(utils::GetConfig()->Get('php_path')); - $aOutput = null; - $iRes = 0; - exec("$sPHPExec --version", $aOutput, $iRes); - if ($iRes != 0) { - $sError = sprintf($sErrorLabel, "Cannot check CLI/PHP version ($sPHPExec)"); - SetupLog::Error($sError, null, ['code' => $iRes, "output" => $aOutput, 'php_path' => $sPHPExec]); - throw new CoreException($sError); - } - - SetupUtils::CheckCliPhpVersionFromOutput($sErrorLabel, PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION, $sPHPExec, $aOutput); - } - - private static function CheckCliPhpVersionFromOutput(string $sErrorLabel, string $sUIPhpVersion, string $sPHPExec, $aOutput): void - { - $sFoundVersion = trim($aOutput[0] ?? ""); - if (false !== preg_match('/(\d+\.\d+)(?:\.\d+)?/', $sFoundVersion, $aMatches)) { - $sFoundVersion = $aMatches[1]; - } - - if ($sFoundVersion !== $sUIPhpVersion) { - $sError = sprintf($sErrorLabel, "Mismatch between PHP versions (CLI: $sFoundVersion/ UI: $sUIPhpVersion)"); - SetupLog::Error($sError, null, ["output" => $aOutput, 'php_path' => $sPHPExec]); - throw new CoreException($sError); - } - } } /** diff --git a/tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php b/tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php index f13b586ad2..c133c31428 100644 --- a/tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/SetupUtilsTest.php @@ -2,6 +2,7 @@ namespace Combodo\iTop\Test\UnitTest\Setup; +use CheckResult; use Combodo\iTop\Setup\FeatureRemoval\ModelReflectionSerializer; use Combodo\iTop\Test\UnitTest\ItopTestCase; use SetupUtils; @@ -155,34 +156,79 @@ class SetupUtilsTest extends ItopTestCase $this->assertTrue(true); } - public function testCheckCliPhpVersionFromOutputFail() - { - $this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); - $sOuput = <<expectException(\CoreException::class); - $this->expectExceptionMessage("Data consistency check failed: Mismatch between PHP versions (CLI: 7.4/ UI: 6.6)"); - $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, '6.6', 'sPHPExec', [$sOuput]]); - } - public function CheckOKProvider() { return [ ["7.4 7.2 7.3.33"], - ["PHP 7.4.33 (cli) (built: Aug 2 2024 16:22:28) ( NTS )"], - ["PHP 7.4.33 PHP 7.33.22"], - ["version: 7.4.27 stable"], + ["PHP 7.4.33 (cli) (built: Aug 2 2024 16:22:28) ( NTS )", "7.4.33"], + ["PHP 7.4.33 PHP 7.33.22", "7.4.33"], + ["version: 7.4.33 stable", "7.4.33"], ]; } + /** * @dataProvider CheckOKProvider */ - public function testCheckCliPhpVersionFromOutputOK($sOuput) + public function testCheckCliPhpVersionFromOutputFail($sOutput, $sFoundVersion = '7.4') { $this->RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); - $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, '7.4', 'sPHPExec', [$sOuput]]); + + $this->expectException(\CoreException::class); + $sDetails = sprintf('The current CLI PHP Version (%s) is lower than the minimum version required to run %s, which is (%s)', $sFoundVersion, ITOP_APPLICATION, SetupUtils::PHP_MIN_VERSION); + + $this->expectExceptionMessage("Data consistency check failed: $sDetails"); + $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, 'sPHPExec', [$sOutput]]); + } + + public function testCheckCliPhpVersionFromOutputOK() + { + $sOutput = <<RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); + $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckCliPhpVersionFromOutput', [ModelReflectionSerializer::ERROR_LABEL, 'sPHPExec', [$sOutput]]); $this->assertTrue(true); } + + public function testCheckPhpVersionIsOK() + { + $aRes = []; + $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckPhpVersion', [&$aRes]); + $this->ValidateCheckResults([], $aRes); + } + + public function testCheckPhpVersionIsNotValidatedYet() + { + $aRes = []; + $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckPhpVersion', [&$aRes, '100.0']); + $expected = [ + 'The current PHP Version (100.0) is not yet validated by Combodo. You may experience some incompatibility issues.', + ]; + $this->ValidateCheckResults($expected, $aRes); + } + + public function testCheckPhpVersionIsNOK() + { + $aRes = []; + $this->InvokeNonPublicStaticMethod(SetupUtils::class, 'CheckPhpVersion', [&$aRes, '1.0']); + $expected = [ + sprintf('Error: The current PHP Version (1.0) is lower than the minimum version required to run %s, which is (%s)', ITOP_APPLICATION, SetupUtils::PHP_MIN_VERSION), + ]; + $this->ValidateCheckResults($expected, $aRes); + } + + private function ValidateCheckResults(array $expected, array $aActualCheckResults) + { + $aActual = []; + foreach ($aActualCheckResults as $oCheckRes) { + /** @var CheckResult $oCheckRes */ + if ($oCheckRes->iSeverity <= CheckResult::WARNING) { + $aActual [] = $oCheckRes->sLabel; + } + } + + self::assertEquals($expected, $aActual); + } + }