WriteGitRevisionCommand.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin\Command;
  4. use PhpMyAdmin\Git;
  5. use Symfony\Component\Console\Command\Command;
  6. use Symfony\Component\Console\Input\InputInterface;
  7. use Symfony\Component\Console\Input\InputOption;
  8. use Symfony\Component\Console\Output\OutputInterface;
  9. use function addcslashes;
  10. use function explode;
  11. use function file_put_contents;
  12. use function is_string;
  13. use function shell_exec;
  14. use function sprintf;
  15. use function str_replace;
  16. use function trim;
  17. class WriteGitRevisionCommand extends Command
  18. {
  19. /** @var string */
  20. protected static $defaultName = 'write-revision-info';
  21. /** @var string */
  22. private static $generatedClassTemplate = <<<'PHP'
  23. <?php
  24. declare(strict_types=1);
  25. /**
  26. * This file is generated by scripts/console.
  27. *
  28. * @see \PhpMyAdmin\Command\WriteGitRevisionCommand
  29. */
  30. return [
  31. 'revision' => '%s',
  32. 'revisionHash' => '%s',
  33. 'revisionUrl' => '%s',
  34. 'branch' => '%s',
  35. 'branchUrl' => '%s',
  36. 'message' => '%s',
  37. 'author' => [
  38. 'name' => '%s',
  39. 'email' => '%s',
  40. 'date' => '%s',
  41. ],
  42. 'committer' => [
  43. 'name' => '%s',
  44. 'email' => '%s',
  45. 'date' => '%s',
  46. ],
  47. ];
  48. PHP;
  49. protected function configure(): void
  50. {
  51. $this->setDescription('Write Git revision');
  52. $this->addOption(
  53. 'remote-commit-url',
  54. null,
  55. InputOption::VALUE_OPTIONAL,
  56. 'The remote URL to a commit',
  57. 'https://github.com/phpmyadmin/phpmyadmin/commit/%s'
  58. );
  59. $this->addOption(
  60. 'remote-branch-url',
  61. null,
  62. InputOption::VALUE_OPTIONAL,
  63. 'The remote URL to a branch',
  64. 'https://github.com/phpmyadmin/phpmyadmin/tree/%s'
  65. );
  66. $this->setHelp('This command generates the revision-info.php file from Git data.');
  67. }
  68. protected function execute(InputInterface $input, OutputInterface $output): int
  69. {
  70. /** @var string $commitUrlFormat */
  71. $commitUrlFormat = $input->getOption('remote-commit-url');
  72. /** @var string $branchUrlFormat */
  73. $branchUrlFormat = $input->getOption('remote-branch-url');
  74. $generatedClass = $this->getRevisionInfo($commitUrlFormat, $branchUrlFormat);
  75. if ($generatedClass === null) {
  76. $output->writeln('No revision information detected.');
  77. return Command::SUCCESS;
  78. }
  79. if (! $this->writeGeneratedFile($generatedClass)) {
  80. return Command::FAILURE;
  81. }
  82. $output->writeln('revision-info.php successfully generated!');
  83. return Command::SUCCESS;
  84. }
  85. private function getRevisionInfo(string $commitUrlFormat, string $branchUrlFormat): ?string
  86. {
  87. $revisionText = $this->gitCli('describe --always');
  88. if ($revisionText === null) {
  89. return null;
  90. }
  91. $commitHash = $this->gitCli('log -1 --format="%H"');
  92. if ($commitHash === null) {
  93. return null;
  94. }
  95. $branchName = $this->gitCli('symbolic-ref -q HEAD') ?? $this->gitCli('name-rev --name-only HEAD 2>/dev/null');
  96. if ($branchName === null) {
  97. return null;
  98. }
  99. $commitDetails = $this->gitCli(
  100. 'show -s --pretty="tree %T%nparent %P%nauthor %an <%ae> %at%ncommitter %cn <%ce> %ct%n%n%B"'
  101. );
  102. if ($commitDetails === null) {
  103. return null;
  104. }
  105. $branchName = addcslashes(trim(str_replace('refs/heads/', '', $branchName)), "'");
  106. [$author, $committer, $message] = Git::extractDataFormTextBody(explode("\n", $commitDetails));
  107. return sprintf(
  108. self::$generatedClassTemplate,
  109. trim($revisionText),
  110. trim($commitHash),
  111. sprintf($commitUrlFormat, trim($commitHash)),
  112. $branchName,
  113. sprintf($branchUrlFormat, $branchName),
  114. addcslashes(trim($message), "'"), // Commit message
  115. addcslashes($author['name'], "'"), // Author name
  116. addcslashes($author['email'], "'"), // Author email
  117. $author['date'], // Author date
  118. addcslashes($committer['name'], "'"), // Committer name
  119. addcslashes($committer['email'], "'"), // Committer email
  120. $committer['date'] // Committer date
  121. );
  122. }
  123. protected function gitCli(string $command): ?string
  124. {
  125. /** @psalm-suppress ForbiddenCode */
  126. $output = shell_exec('git ' . $command);
  127. return is_string($output) ? $output : null;
  128. }
  129. private function writeGeneratedFile(string $generatedClass): bool
  130. {
  131. $result = file_put_contents(ROOT_PATH . 'revision-info.php', $generatedClass);
  132. return $result !== false;
  133. }
  134. }