Skip to content

Commit f6ac6d5

Browse files
committed
refactor: improve docblocks for changelog classes and interfaces & add tests
Signed-off-by: Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
1 parent 28fefc0 commit f6ac6d5

20 files changed

Lines changed: 566 additions & 125 deletions

src/Changelog/BootstrapResult.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
final readonly class BootstrapResult
2525
{
2626
/**
27-
* @param bool $configCreated
28-
* @param bool $changelogCreated
29-
* @param bool $unreleasedCreated
27+
* Creates a new instance of `BootstrapResult`.
28+
*
29+
* @param bool $configCreated indicates whether the configuration file was created during bootstrap
30+
* @param bool $changelogCreated Indicates whether the changelog file was created during bootstrap
31+
* @param bool $unreleasedCreated Indicates whether the unreleased changelog file was created during bootstrap
3032
*/
3133
public function __construct(
3234
public bool $configCreated,

src/Changelog/Bootstrapper.php

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
use Symfony\Component\Filesystem\Filesystem;
2222
use Symfony\Component\Filesystem\Path;
2323

24-
use function Safe\file_get_contents;
2524
use function rtrim;
2625
use function str_contains;
2726
use function str_replace;
@@ -34,51 +33,50 @@
3433
final readonly class Bootstrapper implements BootstrapperInterface
3534
{
3635
/**
37-
* @param Filesystem|null $filesystem
38-
* @param HistoryGeneratorInterface|null $historyGenerator
39-
* @param KeepAChangelogConfigRenderer|null $configRenderer
36+
* Initializes the `Bootstrapper` with optional dependencies.
37+
*
38+
* @param Filesystem $filesystem filesystem instance for file operations, allowing for easier testing and potential customization
39+
* @param HistoryGeneratorInterface $historyGenerator history generator instance for generating changelog history
40+
* @param KeepAChangelogConfigRenderer $configRenderer config renderer instance for rendering keep-a-changelog configuration
4041
*/
4142
public function __construct(
42-
private ?Filesystem $filesystem = null,
43-
private ?HistoryGeneratorInterface $historyGenerator = null,
44-
private ?KeepAChangelogConfigRenderer $configRenderer = null,
43+
private Filesystem $filesystem = new Filesystem(),
44+
private HistoryGeneratorInterface $historyGenerator = new HistoryGenerator(),
45+
private KeepAChangelogConfigRenderer $configRenderer = new KeepAChangelogConfigRenderer(),
4546
) {}
4647

4748
/**
49+
* Bootstraps changelog automation assets in the given working directory.
50+
*
4851
* @param string $workingDirectory
4952
*
5053
* @return BootstrapResult
5154
*/
5255
public function bootstrap(string $workingDirectory): BootstrapResult
5356
{
54-
$filesystem = $this->filesystem ?? new Filesystem();
5557
$configPath = Path::join($workingDirectory, '.keep-a-changelog.ini');
5658
$changelogPath = Path::join($workingDirectory, 'CHANGELOG.md');
5759

5860
$configCreated = false;
5961
$changelogCreated = false;
6062
$unreleasedCreated = false;
6163

62-
if (! $filesystem->exists($configPath)) {
63-
$filesystem->dumpFile($configPath, ($this->configRenderer ?? new KeepAChangelogConfigRenderer())->render());
64+
if (! $this->filesystem->exists($configPath)) {
65+
$this->filesystem->dumpFile($configPath, $this->configRenderer->render());
6466
$configCreated = true;
6567
}
6668

67-
if (! $filesystem->exists($changelogPath)) {
68-
$filesystem->dumpFile(
69-
$changelogPath,
70-
($this->historyGenerator ?? new HistoryGenerator())
71-
->generate($workingDirectory),
72-
);
69+
if (! $this->filesystem->exists($changelogPath)) {
70+
$this->filesystem->dumpFile($changelogPath, $this->historyGenerator->generate($workingDirectory));
7371
$changelogCreated = true;
7472

7573
return new BootstrapResult($configCreated, $changelogCreated, $unreleasedCreated);
7674
}
7775

78-
$contents = file_get_contents($changelogPath);
76+
$contents = $this->filesystem->readFile($changelogPath);
7977

8078
if (! str_contains($contents, '## Unreleased - ')) {
81-
$filesystem->dumpFile($changelogPath, $this->prependUnreleasedSection($contents));
79+
$this->filesystem->dumpFile($changelogPath, $this->prependUnreleasedSection($contents));
8280
$unreleasedCreated = true;
8381
}
8482

src/Changelog/BootstrapperInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,17 @@
2020

2121
/**
2222
* Bootstraps repository-local changelog automation artifacts.
23+
*
24+
* The BootstrapperInterface defines a contract for bootstrapping changelog automation assets in a given working directory.
25+
* Implementations of this interface are MUST setup necessary files, configurations, or other resources required to enable
26+
* changelog automation in a repository. The bootstrap method takes a working directory as input and returns a BootstrapResult
27+
* indicating the outcome of the bootstrapping process.
2328
*/
2429
interface BootstrapperInterface
2530
{
2631
/**
32+
* Bootstraps changelog automation assets in the given working directory.
33+
*
2734
* @param string $workingDirectory
2835
*
2936
* @return BootstrapResult

src/Changelog/CommitClassifier.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
final readonly class CommitClassifier implements CommitClassifierInterface
3131
{
3232
/**
33-
* @param string $subject
33+
* Classifies a commit subject into a changelog section based on conventional prefixes and keywords.
3434
*
35-
* @return string
35+
* @param string $subject commit subject to classify
36+
*
37+
* @return string Changelog section name (e.g., "Added", "Changed", "Deprecated", "Removed", "Fixed", "Security", or "Uncategorized").
3638
*/
3739
public function classify(string $subject): string
3840
{
@@ -64,9 +66,11 @@ public function classify(string $subject): string
6466
}
6567

6668
/**
67-
* @param string $subject
69+
* Normalizes a commit subject by stripping conventional prefixes, tags, and extra whitespace, while preserving the core message.
70+
*
71+
* @param string $subject commit subject to normalize
6872
*
69-
* @return string
73+
* @return string normalized commit subject
7074
*/
7175
public function normalize(string $subject): string
7276
{

src/Changelog/CommitClassifierInterface.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,37 @@
2020

2121
/**
2222
* Maps raw commit subjects to Keep a Changelog sections.
23+
*
24+
* The CommitClassifierInterface defines a contract for classifying commit subjects into specific changelog
25+
* sections based on conventional prefixes and keywords.
26+
*
27+
* Implementations of this interface MUST analyze commit subjects and determine the appropriate
28+
* changelog section (e.g., "Added", "Changed", "Deprecated", "Removed", "Fixed", "Security", or "Uncategorized") based
29+
* on recognized patterns such as "fix:", "feat:", "docs:", "chore:", and security-related keywords.
2330
*/
2431
interface CommitClassifierInterface
2532
{
2633
/**
27-
* @param string $subject
34+
* Classifies a commit subject into a changelog section based on conventional prefixes and keywords.
35+
*
36+
* The classification logic SHOULD recognize common patterns such as "fix:", "feat:", "docs:", "chore:",
37+
* and security-related keywords, while also allowing for free-form subjects to be categorized under a default section.
2838
*
29-
* @return string
39+
* @param string $subject commit subject to classify
40+
*
41+
* @return string Changelog section name (e.g., "Added", "Changed", "Deprecated", "Removed", "Fixed", "Security", or "Uncategorized").
3042
*/
3143
public function classify(string $subject): string;
3244

3345
/**
34-
* @param string $subject
46+
* Normalizes a commit subject by stripping conventional prefixes, tags, and extra whitespace, while preserving the core message.
47+
*
48+
* The normalization process SHOULD remove any conventional commit type indicators (e.g., "fix:", "feat:", "docs:")
49+
* and scope annotations (e.g., "(api)"),
50+
*
51+
* @param string $subject commit subject to normalize
3552
*
36-
* @return string
53+
* @return string normalized commit subject
3754
*/
3855
public function normalize(string $subject): string;
3956
}

src/Changelog/GitProcessRunner.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
final readonly class GitProcessRunner implements GitProcessRunnerInterface
2929
{
3030
/**
31-
* @param list<string> $command
32-
* @param string $workingDirectory
31+
* Executes a git command in the specified working directory and returns the trimmed output.
3332
*
34-
* @return string
33+
* @param list<string> $command Git command to execute (e.g., ['git', 'log', '--oneline']).
34+
* @param string $workingDirectory Directory in which to execute the command (e.g., repository root).
35+
*
36+
* @return string trimmed output from the executed command
3537
*/
3638
public function run(array $command, string $workingDirectory): string
3739
{

src/Changelog/GitProcessRunnerInterface.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,25 @@
2020

2121
/**
2222
* Executes git-aware shell commands for changelog automation services.
23+
*
24+
* The GitProcessRunnerInterface defines a contract for executing git-related commands in the context of changelog automation.
25+
* Implementations of this interface MUST run specified git commands in a given working directory and return the trimmed output.
26+
* The run method takes a list of command arguments and a working directory as input, and it returns the output from the executed command,
27+
* allowing changelog automation services to interact with git repositories effectively.
2328
*/
2429
interface GitProcessRunnerInterface
2530
{
2631
/**
2732
* Runs a command in the provided working directory and returns stdout.
2833
*
29-
* @param list<string> $command
30-
* @param string $workingDirectory
34+
* The method SHOULD execute the given command and return the trimmed output.
35+
* The implementation MUST handle any necessary process execution and error handling,
36+
* ensuring that the command is executed in the context of the specified working directory.
37+
*
38+
* @param list<string> $command Git command to execute (e.g., ['git', 'log', '--oneline']).
39+
* @param string $workingDirectory Directory in which to execute the command (e.g., repository root).
3140
*
32-
* @return string
41+
* @return string trimmed output from the executed command
3342
*/
3443
public function run(array $command, string $workingDirectory): string;
3544
}

src/Changelog/GitReleaseCollector.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,20 @@
3232
final readonly class GitReleaseCollector implements GitReleaseCollectorInterface
3333
{
3434
/**
35-
* @param GitProcessRunnerInterface $gitProcessRunner
35+
* Initializes the GitReleaseCollector with a GitProcessRunner for executing git commands.
36+
*
37+
* @param GitProcessRunnerInterface $gitProcessRunner git process runner for executing git commands
3638
*/
3739
public function __construct(
3840
private GitProcessRunnerInterface $gitProcessRunner = new GitProcessRunner()
3941
) {}
4042

4143
/**
42-
* @param string $workingDirectory
44+
* Collects release information from git tags in the specified working directory.
45+
*
46+
* @param string $workingDirectory Directory in which to execute git commands (e.g., repository root).
4347
*
44-
* @return list<array{version: string, tag: string, date: string, commits: list<string>}>
48+
* @return list<array{version: string, tag: string, date: string, commits: list<string>}> list of releases with version, tag, date, and associated commit subjects
4549
*/
4650
public function collect(string $workingDirectory): array
4751
{
@@ -90,10 +94,12 @@ public function collect(string $workingDirectory): array
9094
}
9195

9296
/**
93-
* @param string $workingDirectory
94-
* @param string $range
97+
* Collects commit subjects for a given git range in the specified working directory.
9598
*
96-
* @return list<string>
99+
* @param string $workingDirectory Directory in which to execute git commands (e.g., repository root).
100+
* @param string $range Git range to collect commits from (e.g., 'v1.0.0..v1.1.0' or 'v1.0.0').
101+
*
102+
* @return list<string> list of commit subjects for the specified range, excluding merges and ignored subjects
97103
*/
98104
private function collectCommitSubjects(string $workingDirectory, string $range): array
99105
{
@@ -116,9 +122,11 @@ private function collectCommitSubjects(string $workingDirectory, string $range):
116122
}
117123

118124
/**
119-
* @param string $subject
125+
* Determines whether a commit subject should be ignored based on common patterns (e.g., merge commits, wiki updates).
126+
*
127+
* @param string $subject commit subject to evaluate for ignoring
120128
*
121-
* @return bool
129+
* @return bool True if the subject should be ignored (e.g., empty, merge commits, wiki updates); false otherwise.
122130
*/
123131
private function shouldIgnore(string $subject): bool
124132
{

src/Changelog/GitReleaseCollectorInterface.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,22 @@
2020

2121
/**
2222
* Discovers released tags and the commit subjects they contain.
23+
*
24+
* The GitReleaseCollectorInterface defines a contract for collecting release information from git tags in a specified working directory.
25+
* Implementations of this interface are responsible for executing git commands to read tags and their associated commit subjects, building
26+
* a structured list of releases that includes version, tag name, creation date, and commit
2327
*/
2428
interface GitReleaseCollectorInterface
2529
{
2630
/**
27-
* @param string $workingDirectory
31+
* Collects release information from git tags in the specified working directory.
32+
*
33+
* The method SHOULD read git tags and their associated commit subjects to build a structured list of releases.
34+
* Each release entry MUST include the version, tag name, creation date, and a list of commit subjects that are part of that release.
35+
*
36+
* @param string $workingDirectory Directory in which to execute git commands (e.g., repository root).
2837
*
29-
* @return list<array{version: string, tag: string, date: string, commits: list<string>}>
38+
* @return list<array{version: string, tag: string, date: string, commits: list<string>}> list of releases with version, tag, date, and associated commit subjects
3039
*/
3140
public function collect(string $workingDirectory): array;
3241
}

src/Changelog/HistoryGenerator.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@
2626
final readonly class HistoryGenerator implements HistoryGeneratorInterface
2727
{
2828
/**
29-
* @param GitReleaseCollectorInterface $gitReleaseCollector
30-
* @param CommitClassifierInterface $commitClassifier
31-
* @param MarkdownRenderer|null $markdownRenderer
29+
* Initializes the `HistoryGenerator` with optional dependencies.
30+
*
31+
* @param GitReleaseCollectorInterface $gitReleaseCollector git release collector instance for collecting release metadata and commit subjects
32+
* @param CommitClassifierInterface $commitClassifier commit classifier instance for classifying and normalizing commit subjects into changelog sections
33+
* @param MarkdownRenderer $markdownRenderer markdown renderer instance for rendering the final changelog markdown from structured release and commit data
3234
*/
3335
public function __construct(
3436
private GitReleaseCollectorInterface $gitReleaseCollector = new GitReleaseCollector(),
3537
private CommitClassifierInterface $commitClassifier = new CommitClassifier(),
36-
private ?MarkdownRenderer $markdownRenderer = null,
38+
private MarkdownRenderer $markdownRenderer = new MarkdownRenderer(),
3739
) {}
3840

3941
/**
@@ -65,7 +67,6 @@ public function generate(string $workingDirectory): string
6567
];
6668
}
6769

68-
return ($this->markdownRenderer ?? new MarkdownRenderer())
69-
->render($releases);
70+
return $this->markdownRenderer->render($releases);
7071
}
7172
}

0 commit comments

Comments
 (0)