Write revision info from a CLI

Signed-off-by: William Desportes <williamdes@wdes.fr>
This commit is contained in:
William Desportes 2021-03-25 12:12:02 +01:00
parent 84ede575e3
commit 7c2ebb163c
No known key found for this signature in database
GPG Key ID: 90A0EF1B8251A889
7 changed files with 259 additions and 44 deletions

View File

@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use function file_put_contents;
use function shell_exec;
use function trim;
use function str_replace;
use function sprintf;
class WriteGitRevisionCommand extends Command
{
/** @var string */
protected static $defaultName = 'write-revision-info';
/** @var string */
private static $generatedClassTemplate = <<<'PHP'
<?php
declare(strict_types=1);
/**
* This file is generated by scripts/console.
*
* @see \PhpMyAdmin\Command\WriteGitRevisionCommand
*/
return [
'revision' => '%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;
}
}

View File

@ -82,26 +82,23 @@ class Footer
{
$message = '<a href="/">' . __('phpMyAdmin Demo Server') . '</a>: ';
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.'),
'<a target="_blank" rel="noopener noreferrer" href="'
. htmlspecialchars($repobase . $fullrevision) . '">'
. htmlspecialchars($revision) . '</a>',
'<a target="_blank" rel="noopener noreferrer" href="'
. htmlspecialchars($repobranchbase . $branch) . '">'
. htmlspecialchars($branch) . '</a>'
);
} 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.'),
'<a target="_blank" rel="noopener noreferrer" href="'
. htmlspecialchars($info['revisionUrl'] ?? '') . '">'
. htmlspecialchars($info['revision'] ?? '') . '</a>',
'<a target="_blank" rel="noopener noreferrer" href="'
. htmlspecialchars($info['branchUrl'] ?? '') . '">'
. htmlspecialchars($info['branch'] ?? '') . '</a>'
)
)->getDisplay();
}
}
return Message::notice($message)->getDisplay();
return Message::notice($message . __('Git information missing!'))->getDisplay();
}
/**

View File

@ -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
*

View File

@ -112,6 +112,14 @@
<code>$defaultName</code>
</NonInvariantDocblockPropertyType>
</file>
<file src="libraries/classes/Command/WriteGitRevisionCommand.php">
<ForbiddenCode occurrences="1">
<code>shell_exec('git ' . $command)</code>
</ForbiddenCode>
<NonInvariantDocblockPropertyType occurrences="1">
<code>$defaultName</code>
</NonInvariantDocblockPropertyType>
</file>
<file src="libraries/classes/Config.php">
<NullableReturnStatement occurrences="1">
<code>$this-&gt;get('is_https')</code>
@ -305,7 +313,9 @@
<MissingFile occurrences="1">
<code>include ROOT_PATH . 'libraries/language_stats.inc.php'</code>
</MissingFile>
<PossiblyNullArgument occurrences="1">
<PossiblyNullArgument occurrences="3">
<code>$this-&gt;config-&gt;get('ShowGitRevision')</code>
<code>$this-&gt;config-&gt;get('ShowGitRevision')</code>
<code>$this-&gt;config-&gt;get('TempDir')</code>
</PossiblyNullArgument>
</file>
@ -948,9 +958,6 @@
<InvalidReturnType occurrences="1">
<code>object</code>
</InvalidReturnType>
<MissingFile occurrences="1">
<code>include ROOT_PATH . 'revision-info.php'</code>
</MissingFile>
<ReferenceConstraintViolation occurrences="2">
<code>$object</code>
<code>return $object;</code>
@ -2625,9 +2632,6 @@
<InvalidReturnType occurrences="1">
<code>int</code>
</InvalidReturnType>
<NullableReturnStatement occurrences="1">
<code>$wktval</code>
</NullableReturnStatement>
<PossiblyFalseOperand occurrences="2">
<code>mb_strpos($value, '.')</code>
<code>mb_strrpos($columnSpecification, ')')</code>

View File

@ -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();

View File

@ -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();
}
/**

View File

@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace PhpMyAdmin\Tests\Command;
use PhpMyAdmin\Command\WriteGitRevisionCommand;
use PhpMyAdmin\Tests\AbstractTestCase;
use Symfony\Component\Console\Command\Command;
use function class_exists;
use function sprintf;
class WriteGitRevisionCommandTest extends AbstractTestCase
{
/** @var WriteGitRevisionCommand */
private $command;
public function testGetGeneratedClassValidVersion(): void
{
if (! class_exists(Command::class)) {
$this->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'
<?php
declare(strict_types=1);
/**
* This file is generated by scripts/console.
*
* @see \PhpMyAdmin\Command\WriteGitRevisionCommand
*/
return [
'revision' => '%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
);
}
}