diff --git a/libraries/classes/Command/WriteGitRevisionCommand.php b/libraries/classes/Command/WriteGitRevisionCommand.php new file mode 100644 index 0000000000..e7c49c819d --- /dev/null +++ b/libraries/classes/Command/WriteGitRevisionCommand.php @@ -0,0 +1,125 @@ + '%s', + 'revisionUrl' => '%s', + 'branch' => '%s', + 'branchUrl' => '%s', +]; + +PHP; + + protected function configure(): void + { + $this->setDescription('Write Git revision'); + $this->addOption( + 'remote-commit-url', + null, + InputOption::VALUE_OPTIONAL, + 'The remote URL to a commit', + 'https://github.com/phpmyadmin/phpmyadmin/commit/%s' + ); + $this->addOption( + 'remote-branch-url', + null, + InputOption::VALUE_OPTIONAL, + 'The remote URL to a branch', + 'https://github.com/phpmyadmin/phpmyadmin/tree/%s' + ); + $this->setHelp('This command generates the revision-info.php file from Git data.'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + /** @var string $commitUrlFormat */ + $commitUrlFormat = $input->getOption('remote-commit-url'); + /** @var string $branchUrlFormat */ + $branchUrlFormat = $input->getOption('remote-branch-url'); + + $generatedClass = $this->getRevisionInfo($commitUrlFormat, $branchUrlFormat); + if ($generatedClass === null) { + $output->writeln('No revision information detected.'); + + return Command::SUCCESS; + } + + if (! $this->writeGeneratedFile($generatedClass)) { + return Command::FAILURE; + } + + $output->writeln('revision-info.php successfully generated!'); + + return Command::SUCCESS; + } + + private function getRevisionInfo(string $commitUrlFormat, string $branchUrlFormat): ?string + { + $revisionText = $this->gitCli('describe --always'); + if ($revisionText === null) { + return null; + } + $commitHash = $this->gitCli('log -1 --format="%H"'); + if ($commitHash === null) { + return null; + } + $branchName = $this->gitCli('symbolic-ref -q HEAD') ?? $this->gitCli('name-rev --name-only HEAD 2>/dev/null'); + if ($branchName === null) { + return null; + } + $branchName = trim(str_replace('refs/heads/', '', $branchName)); + + return sprintf( + self::$generatedClassTemplate, + trim($revisionText), + sprintf($commitUrlFormat, trim($commitHash)), + trim($branchName), + sprintf($branchUrlFormat, $branchName) + ); + } + + protected function gitCli(string $command): ?string + { + return shell_exec('git ' . $command); + } + + private function writeGeneratedFile(string $generatedClass): bool + { + $result = file_put_contents( + ROOT_PATH . 'revision-info.php', + $generatedClass + ); + + return $result !== false; + } +} diff --git a/libraries/classes/Footer.php b/libraries/classes/Footer.php index 08bd69e539..512e353090 100644 --- a/libraries/classes/Footer.php +++ b/libraries/classes/Footer.php @@ -82,26 +82,23 @@ class Footer { $message = '' . __('phpMyAdmin Demo Server') . ': '; if (@file_exists(ROOT_PATH . 'revision-info.php')) { - $revision = ''; - $fullrevision = ''; - $repobase = ''; - $repobranchbase = ''; - $branch = ''; - include ROOT_PATH . 'revision-info.php'; - $message .= sprintf( - __('Currently running Git revision %1$s from the %2$s branch.'), - '' - . htmlspecialchars($revision) . '', - '' - . htmlspecialchars($branch) . '' - ); - } else { - $message .= __('Git information missing!'); + $info = include ROOT_PATH . 'revision-info.php'; + if (is_array($info)) { + return Message::notice( + $message . sprintf( + __('Currently running Git revision %1$s from the %2$s branch.'), + '' + . htmlspecialchars($info['revision'] ?? '') . '', + '' + . htmlspecialchars($info['branch'] ?? '') . '' + ) + )->getDisplay(); + } } - return Message::notice($message)->getDisplay(); + return Message::notice($message . __('Git information missing!'))->getDisplay(); } /** diff --git a/libraries/classes/Utils/HttpRequest.php b/libraries/classes/Utils/HttpRequest.php index 77cd33b3c1..16475b26fb 100644 --- a/libraries/classes/Utils/HttpRequest.php +++ b/libraries/classes/Utils/HttpRequest.php @@ -35,6 +35,10 @@ use const CURLOPT_SSL_VERIFYHOST; use const CURLOPT_SSL_VERIFYPEER; use const CURLOPT_TIMEOUT; use const CURLOPT_USERAGENT; +use function getenv; +use function parse_url; +use const PHP_SAPI; +use function is_array; /** * Handles HTTP requests @@ -59,6 +63,26 @@ class HttpRequest $this->proxyPass = $cfg['ProxyPass']; } + public static function setProxySettingsFromEnv(): void + { + global $cfg; + + $httpProxy = getenv('http_proxy'); + $urlInfo = parse_url((string) $httpProxy); + if (PHP_SAPI !== 'cli' || ! is_array($urlInfo)) { + return; + } + + $proxyUrl = ($urlInfo['host'] ?? '') + . (isset($urlInfo['port']) ? ':' . $urlInfo['port'] : ''); + $proxyUser = $urlInfo['user'] ?? ''; + $proxyPass = $urlInfo['pass'] ?? ''; + + $cfg['ProxyUrl'] = $proxyUrl; + $cfg['ProxyUser'] = $proxyUser; + $cfg['ProxyPass'] = $proxyPass; + } + /** * Returns information with regards to handling the http request * diff --git a/psalm-baseline.xml b/psalm-baseline.xml index df3718d4e8..034cb8566f 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -112,6 +112,14 @@ $defaultName + + + shell_exec('git ' . $command) + + + $defaultName + + $this->get('is_https') @@ -305,7 +313,9 @@ include ROOT_PATH . 'libraries/language_stats.inc.php' - + + $this->config->get('ShowGitRevision') + $this->config->get('ShowGitRevision') $this->config->get('TempDir') @@ -948,9 +958,6 @@ object - - include ROOT_PATH . 'revision-info.php' - $object return $object; @@ -2625,9 +2632,6 @@ int - - $wktval - mb_strpos($value, '.') mb_strrpos($columnSpecification, ')') diff --git a/scripts/console b/scripts/console index ee88c595ed..28d9fe84d2 100755 --- a/scripts/console +++ b/scripts/console @@ -3,6 +3,7 @@ use PhpMyAdmin\Command\CacheWarmupCommand; use PhpMyAdmin\Command\SetVersionCommand; +use PhpMyAdmin\Command\WriteGitRevisionCommand; use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; @@ -37,5 +38,6 @@ $application = new Application('phpMyAdmin Console Tool'); $application->add(new CacheWarmupCommand()); $application->add(new LintCommand($twig)); $application->add(new SetVersionCommand()); +$application->add(new WriteGitRevisionCommand()); $application->run(); diff --git a/test/classes/AbstractTestCase.php b/test/classes/AbstractTestCase.php index 817dc4b906..786f116ebe 100644 --- a/test/classes/AbstractTestCase.php +++ b/test/classes/AbstractTestCase.php @@ -13,15 +13,11 @@ use PhpMyAdmin\SqlParser\Translator; use PhpMyAdmin\Tests\Stubs\DbiDummy; use PhpMyAdmin\Tests\Stubs\Response; use PhpMyAdmin\Theme; +use PhpMyAdmin\Utils\HttpRequest; use PHPUnit\Framework\TestCase; use ReflectionClass; -use function getenv; use function in_array; -use function is_array; -use function parse_url; - -use const PHP_SAPI; /** * Abstract class to hold some usefull methods used in tests @@ -149,20 +145,7 @@ abstract class AbstractTestCase extends TestCase protected function setProxySettings(): void { - $httpProxy = getenv('http_proxy'); - $urlInfo = parse_url((string) $httpProxy); - if (PHP_SAPI !== 'cli' || ! is_array($urlInfo)) { - return; - } - - $proxyUrl = ($urlInfo['host'] ?? '') - . (isset($urlInfo['port']) ? ':' . $urlInfo['port'] : ''); - $proxyUser = $urlInfo['user'] ?? ''; - $proxyPass = $urlInfo['pass'] ?? ''; - - $GLOBALS['cfg']['ProxyUrl'] = $proxyUrl; - $GLOBALS['cfg']['ProxyUser'] = $proxyUser; - $GLOBALS['cfg']['ProxyPass'] = $proxyPass; + HttpRequest::setProxySettingsFromEnv(); } /** diff --git a/test/classes/Command/WriteGitRevisionCommandTest.php b/test/classes/Command/WriteGitRevisionCommandTest.php new file mode 100644 index 0000000000..5387214085 --- /dev/null +++ b/test/classes/Command/WriteGitRevisionCommandTest.php @@ -0,0 +1,80 @@ +markTestSkipped('The Symfony Console is missing'); + } + + $this->command = $this->getMockBuilder(WriteGitRevisionCommand::class) + ->onlyMethods(['gitCli']) + ->getMock(); + + $this->command->expects($this->exactly(3)) + ->method('gitCli') + ->withConsecutive( + ['describe --always'], + ['log -1 --format="%H"'], + ['symbolic-ref -q HEAD'] + ) + ->willReturnOnConsecutiveCalls( + 'RELEASE_5_1_0-638-g1c018e2a6c', + '1c018e2a6c6d518c4a2dde059e49f33af67c4636', + 'refs/heads/cli-rev-info' + ); + + $output = $this->callFunction( + $this->command, + WriteGitRevisionCommand::class, + 'getRevisionInfo', + [ + 'https://github.com/phpmyadmin/phpmyadmin/commit/%s', + 'https://github.com/phpmyadmin/phpmyadmin/tree/%s', + ] + ); + $template = <<<'PHP' + '%s', + 'revisionUrl' => '%s', + 'branch' => '%s', + 'branchUrl' => '%s', +]; + +PHP; + $this->assertSame( + sprintf( + $template, + 'RELEASE_5_1_0-638-g1c018e2a6c', + 'https://github.com/phpmyadmin/phpmyadmin/commit/1c018e2a6c6d518c4a2dde059e49f33af67c4636', + 'cli-rev-info', + 'https://github.com/phpmyadmin/phpmyadmin/tree/cli-rev-info' + ), + $output + ); + } +}