Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
ChangelogEntryCommand
100.00% covered (success)
100.00%
52 / 52
100.00% covered (success)
100.00%
3 / 3
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 configure
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\Console\Command;
21
22use FastForward\DevTools\Console\Command\Traits\LogsCommandResults;
23use Composer\Command\BaseCommand;
24use FastForward\DevTools\Changelog\Document\ChangelogDocument;
25use FastForward\DevTools\Changelog\Entry\ChangelogEntryType;
26use FastForward\DevTools\Changelog\Manager\ChangelogManagerInterface;
27use FastForward\DevTools\Console\Input\HasJsonOption;
28use FastForward\DevTools\Filesystem\FilesystemInterface;
29use Psr\Log\LoggerInterface;
30use Symfony\Component\Console\Attribute\AsCommand;
31use Symfony\Component\Console\Input\InputArgument;
32use Symfony\Component\Console\Input\InputInterface;
33use Symfony\Component\Console\Input\InputOption;
34use Symfony\Component\Console\Output\OutputInterface;
35
36/**
37 * Inserts a changelog entry into the managed changelog file.
38 */
39#[AsCommand(
40    name: 'changelog:entry',
41    description: 'Adds a changelog entry to Unreleased or a specific version section.',
42    help: 'This command appends one categorized changelog entry to the selected changelog file so it can be reused by local authoring flows and skills.'
43)]
44 class ChangelogEntryCommand extends BaseCommand implements LoggerAwareCommandInterface
45{
46    use HasJsonOption;
47    use LogsCommandResults;
48
49    /**
50     * @param FilesystemInterface $filesystem
51     * @param ChangelogManagerInterface $changelogManager
52     * @param LoggerInterface $logger
53     */
54    public function __construct(
55        private  FilesystemInterface $filesystem,
56        private  ChangelogManagerInterface $changelogManager,
57        private  LoggerInterface $logger,
58    ) {
59        parent::__construct();
60    }
61
62    /**
63     * Configures the entry authoring arguments and options.
64     */
65    protected function configure(): void
66    {
67        $this->addJsonOption()
68            ->addArgument(
69                name: 'message',
70                mode: InputArgument::REQUIRED,
71                description: 'The changelog entry text to append.',
72            )
73            ->addOption(
74                name: 'type',
75                shortcut: 't',
76                mode: InputOption::VALUE_REQUIRED,
77                description: 'The changelog category (added, changed, deprecated, removed, fixed, security).',
78                default: 'added',
79                suggestedValues: array_map(
80                    static fn(ChangelogEntryType $type): string => strtolower($type->value),
81                    ChangelogEntryType::ordered()
82                ),
83            )
84            ->addOption(
85                name: 'release',
86                mode: InputOption::VALUE_REQUIRED,
87                description: 'The target release section. Defaults to Unreleased.',
88                default: ChangelogDocument::UNRELEASED_VERSION,
89            )
90            ->addOption(
91                name: 'date',
92                mode: InputOption::VALUE_REQUIRED,
93                description: 'Optional release date for published sections in YYYY-MM-DD format.',
94            )
95            ->addOption(
96                name: 'file',
97                mode: InputOption::VALUE_REQUIRED,
98                description: 'Path to the changelog file.',
99                default: 'CHANGELOG.md',
100            );
101    }
102
103    /**
104     * Appends a changelog entry to the requested section.
105     *
106     * @param InputInterface $input
107     * @param OutputInterface $output
108     */
109    protected function execute(InputInterface $input, OutputInterface $output): int
110    {
111        $file = $this->filesystem->getAbsolutePath((string) $input->getOption('file'));
112        $type = ChangelogEntryType::fromInput((string) $input->getOption('type'));
113        $version = (string) $input->getOption('release');
114        $date = $input->getOption('date');
115        $message = (string) $input->getArgument('message');
116
117        $this->changelogManager->addEntry($file, $type, $message, $version, \is_string($date) ? $date : null);
118
119        return $this->success(
120            'Added {type} changelog entry to [{release}] in {absolute_file}.',
121            $input,
122            [
123                'absolute_file' => $file,
124                'type' => strtolower($type->value),
125                'release' => $version,
126                'date' => \is_string($date) ? $date : null,
127                'message' => $message,
128            ],
129        );
130    }
131}