Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
UnreleasedEntryChecker
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
3 / 3
8
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
 hasPendingChanges
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
5
 flattenEntries
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
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\Changelog\Checker;
21
22use FastForward\DevTools\Changelog\Document\ChangelogRelease;
23use FastForward\DevTools\Changelog\Entry\ChangelogEntryType;
24use FastForward\DevTools\Filesystem\FilesystemInterface;
25use FastForward\DevTools\Git\GitClientInterface;
26use FastForward\DevTools\Changelog\Parser\ChangelogParserInterface;
27use Throwable;
28
29use function array_diff;
30use function array_values;
31
32/**
33 * Compares unreleased changelog entries against the current branch or a base ref.
34 */
35  class UnreleasedEntryChecker implements UnreleasedEntryCheckerInterface
36{
37    /**
38     * Constructs a new UnreleasedEntryChecker.
39     *
40     * @param GitClientInterface $gitClient the Git client used for baseline inspection
41     * @param FilesystemInterface $filesystem
42     * @param ChangelogParserInterface $parser
43     */
44    public function __construct(
45        private FilesystemInterface $filesystem,
46        private GitClientInterface $gitClient,
47        private ChangelogParserInterface $parser,
48    ) {}
49
50    /**
51     * Checks if there are pending unreleased entries in the changelog compared to a given reference.
52     *
53     * @param string $file the changelog file path to inspect
54     * @param string|null $againstReference The reference to compare against (e.g., a branch or commit hash).
55     *
56     * @return bool true if there are pending unreleased entries, false otherwise
57     */
58    public function hasPendingChanges(string $file, ?string $againstReference = null): bool
59    {
60        try {
61            $content = $this->filesystem->readFile($file);
62        } catch (Throwable) {
63            return false;
64        }
65
66        $currentEntries = $this->flattenEntries($this->parser->parse($content)->getUnreleased());
67
68        if ([] === $currentEntries) {
69            return false;
70        }
71
72        if (null === $againstReference) {
73            return true;
74        }
75
76        try {
77            $baseline = $this->gitClient->show($againstReference, $file, $this->filesystem->dirname($file));
78        } catch (Throwable) {
79            return true;
80        }
81
82        $baselineEntries = $this->flattenEntries($this->parser->parse($baseline)->getUnreleased());
83
84        return [] !== array_values(array_diff($currentEntries, $baselineEntries));
85    }
86
87    /**
88     * Flattens release entries for set comparison.
89     *
90     * @param ChangelogRelease $release
91     *
92     * @return list<string>
93     */
94    private function flattenEntries(ChangelogRelease $release): array
95    {
96        $entries = [];
97
98        foreach (ChangelogEntryType::ordered() as $type) {
99            $entries = [...$entries, ...$release->getEntriesFor($type)];
100        }
101
102        return array_values(array_unique($entries));
103    }
104}