|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +namespace AsyncAws\CodeGenerator\Command; |
| 6 | + |
| 7 | +use AsyncAws\CodeGenerator\ChangeLogUpdater; |
| 8 | +use Symfony\Component\Console\Attribute\AsCommand; |
| 9 | +use Symfony\Component\Console\Command\Command; |
| 10 | +use Symfony\Component\Console\Input\InputArgument; |
| 11 | +use Symfony\Component\Console\Input\InputInterface; |
| 12 | +use Symfony\Component\Console\Output\ConsoleOutput; |
| 13 | +use Symfony\Component\Console\Output\OutputInterface; |
| 14 | +use Symfony\Component\Process\Process; |
| 15 | + |
| 16 | +/** |
| 17 | + * @internal |
| 18 | + */ |
| 19 | +#[AsCommand(name: 'add-change-log', description: 'Add a change log entry in all packages containing modified files.')] |
| 20 | +class AddChangeLogCommand extends Command |
| 21 | +{ |
| 22 | + private const CHANGELOG_LABELS = ['BC-BREAK', 'Removed', 'Added', 'Deprecated', 'Dependency bumped', 'Changed', 'Fixed', 'Security']; |
| 23 | + |
| 24 | + private readonly ChangeLogUpdater $changeLogUpdater; |
| 25 | + |
| 26 | + public function __construct() |
| 27 | + { |
| 28 | + $this->changeLogUpdater = new ChangeLogUpdater(); |
| 29 | + parent::__construct(); |
| 30 | + } |
| 31 | + |
| 32 | + protected function configure(): void |
| 33 | + { |
| 34 | + $this->addArgument('type', InputArgument::REQUIRED, 'The type of change. Supported values: ' . implode(', ', self::CHANGELOG_LABELS), null, self::CHANGELOG_LABELS); |
| 35 | + $this->addArgument('message', InputArgument::REQUIRED); |
| 36 | + } |
| 37 | + |
| 38 | + protected function execute(InputInterface $input, OutputInterface $output): int |
| 39 | + { |
| 40 | + $errorOutput = $output instanceof ConsoleOutput ? $output->getErrorOutput() : $output; |
| 41 | + |
| 42 | + if (!\in_array($input->getArgument('type'), self::CHANGELOG_LABELS, true)) { |
| 43 | + $errorOutput->writeln('Invalid type provided. It must be one of: ' . implode(', ', self::CHANGELOG_LABELS) . '.'); |
| 44 | + |
| 45 | + return 1; |
| 46 | + } |
| 47 | + |
| 48 | + $changedFiles = explode("\n", (new Process(['git', 'ls-files', '--modified']))->mustRun()->getOutput()); |
| 49 | + |
| 50 | + $changedServices = []; |
| 51 | + foreach ($changedFiles as $file) { |
| 52 | + $parts = explode('/', $file); |
| 53 | + if ('src' !== $parts[0]) { |
| 54 | + continue; |
| 55 | + } |
| 56 | + if (!isset($parts[1])) { |
| 57 | + continue; |
| 58 | + } |
| 59 | + |
| 60 | + if ('Service' === $parts[1]) { |
| 61 | + $service = $parts[2]; |
| 62 | + $base = 'src/Service/' . $service; |
| 63 | + |
| 64 | + if ('.template' === $service) { |
| 65 | + continue; // The service template does not have an actual changelog |
| 66 | + } |
| 67 | + } elseif ('Integration' === $parts[1]) { |
| 68 | + $service = $parts[2] . '/' . $parts[3]; |
| 69 | + $base = 'src/Integration/' . $service; |
| 70 | + } elseif ('CodeGenerator' === $parts[1]) { |
| 71 | + continue; // The code generator does not have a changelog as it has no releases |
| 72 | + } elseif ('Core' === $parts[1]) { |
| 73 | + $service = $parts[1]; |
| 74 | + $base = 'src/' . $service; |
| 75 | + } else { |
| 76 | + continue; |
| 77 | + } |
| 78 | + |
| 79 | + $subPath = substr($file, \strlen($base)); |
| 80 | + $normalizedSubPath = str_replace(\DIRECTORY_SEPARATOR, '/', $subPath); |
| 81 | + |
| 82 | + if (\in_array($normalizedSubPath, ['/README.md', '/Makefile', '/.gitattributes', '/.gitignore', '/LICENSE', '/phpunit.xml.dist', '/roave-bc-check.yaml'], true) || str_starts_with($normalizedSubPath, '/.github/') || str_starts_with($normalizedSubPath, '/tests/')) { |
| 83 | + // Scaffolding files don't require a changelog entry when modified as they don't impact the usage of the packages |
| 84 | + continue; |
| 85 | + } |
| 86 | + |
| 87 | + if (!isset($changedServices[$service])) { |
| 88 | + $changedServices[$service] = ['base' => $base, 'files' => []]; |
| 89 | + } |
| 90 | + $changedServices[$service]['files'][] = $subPath; |
| 91 | + } |
| 92 | + |
| 93 | + $fixSectionLabel = '### ' . $input->getArgument('type'); |
| 94 | + $message = $input->getArgument('message'); |
| 95 | + |
| 96 | + foreach ($changedServices as $service => $info) { |
| 97 | + $newLines = ['- ' . $message]; |
| 98 | + |
| 99 | + $changeLogPath = $info['base'] . '/CHANGELOG.md'; |
| 100 | + $this->changeLogUpdater->addNewChangeLogLines($changeLogPath, $service, $fixSectionLabel, $newLines, $errorOutput->writeln(...)); |
| 101 | + } |
| 102 | + |
| 103 | + return 0; |
| 104 | + } |
| 105 | +} |
0 commit comments