From 7199f49c3e71d913bad00a5fcf6cfc152b919b08 Mon Sep 17 00:00:00 2001 From: Nathanael Esayeas Date: Sat, 31 Dec 2022 19:22:41 -0600 Subject: [PATCH 1/5] Add support for git tag existence check Signed-off-by: Nathanael Esayeas --- src/Git/HasTag.php | 14 +++++ src/Git/HasTagViaConsole.php | 23 ++++++++ test/unit/Git/HasTagViaConsoleTest.php | 75 ++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 src/Git/HasTag.php create mode 100644 src/Git/HasTagViaConsole.php create mode 100644 test/unit/Git/HasTagViaConsoleTest.php diff --git a/src/Git/HasTag.php b/src/Git/HasTag.php new file mode 100644 index 00000000..0dc274fa --- /dev/null +++ b/src/Git/HasTag.php @@ -0,0 +1,14 @@ +repository = create_temporary_file(temp_dir(), 'HasTagViaConsoleRepository'); + + $this->hasTag = new HasTagViaConsole(); + + delete_file($this->repository); + create_directory($this->repository); + + execute('git', ['init'], $this->repository); + + execute('git', ['config', 'user.email', 'me@example.com'], $this->repository); + execute('git', ['config', 'user.name', 'Just Me'], $this->repository); + + array_map(fn (string $tag) => $this->createTag($tag), [ + '1.0.0', + '2.0.0', + ]); + } + + private function createTag(string $tag): void + { + execute('git', ['commit', '--allow-empty', '-m', 'a commit for version ' . $tag], $this->repository); + execute('git', ['tag', '-a', $tag, '-m', 'version ' . $tag], $this->repository); + } + + /** @param non-empty-string $repository */ + private function assertGitTagExists(string $repository, string $tag): void + { + self::assertTrue(($this->hasTag)($repository, $tag), sprintf('Failed asserting git tag "%s" exists.', $tag)); + } + + /** @param non-empty-string $repository */ + private function assertGitTagMissing(string $repository, string $tag): void + { + self::assertFalse(($this->hasTag)($repository, $tag), sprintf('Failed asserting git tag "%s" is missing.', $tag)); + } + + public function testHasTag(): void + { + self::assertGitTagExists($this->repository, '1.0.0'); + } + + public function testHasTagMissing(): void + { + self::assertGitTagMissing($this->repository, '10.0.0'); + } +} From 277dbc96a4772417d24fe825e6220b8f23809164 Mon Sep 17 00:00:00 2001 From: Nathanael Esayeas Date: Sat, 31 Dec 2022 20:08:31 -0600 Subject: [PATCH 2/5] Refactor: create tag via console if not exists Signed-off-by: Nathanael Esayeas --- bin/console.php | 3 +- src/Git/CreateTagViaConsole.php | 30 ++++++++---- test/unit/Git/CreateTagViaConsoleTest.php | 56 +++++++++++++++++++---- 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/bin/console.php b/bin/console.php index 25a6504c..07533fdf 100755 --- a/bin/console.php +++ b/bin/console.php @@ -24,6 +24,7 @@ use Laminas\AutomaticReleases\Git\CreateTagViaConsole; use Laminas\AutomaticReleases\Git\FetchAndSetCurrentUserByReplacingCurrentOriginRemote; use Laminas\AutomaticReleases\Git\GetMergeTargetCandidateBranchesFromRemoteBranches; +use Laminas\AutomaticReleases\Git\HasTagViaConsole; use Laminas\AutomaticReleases\Git\PushViaConsole; use Laminas\AutomaticReleases\Github\Api\GraphQL\Query\GetMilestoneFirst100IssuesAndPullRequests; use Laminas\AutomaticReleases\Github\Api\GraphQL\RunGraphQLQuery; @@ -127,7 +128,7 @@ static function (int $errorCode, string $message = '', string $file = '', int $l $getMilestone, $commitChangelog, $createReleaseText, - new CreateTagViaConsole(), + new CreateTagViaConsole(new HasTagViaConsole()), $push, $createRelease, ), diff --git a/src/Git/CreateTagViaConsole.php b/src/Git/CreateTagViaConsole.php index 33a71f1d..5c8e68b8 100644 --- a/src/Git/CreateTagViaConsole.php +++ b/src/Git/CreateTagViaConsole.php @@ -6,13 +6,18 @@ use Laminas\AutomaticReleases\Git\Value\BranchName; use Laminas\AutomaticReleases\Gpg\SecretKeyId; -use Psl\Env; -use Psl\File; -use Psl\Filesystem; -use Psl\Shell; + +use function Psl\Env\temp_dir; +use function Psl\File\write; +use function Psl\Filesystem\create_temporary_file; +use function Psl\Shell\execute; final class CreateTagViaConsole implements CreateTag { + public function __construct(private HasTag $hasTag) + { + } + public function __invoke( string $repositoryDirectory, BranchName $sourceBranch, @@ -20,11 +25,20 @@ public function __invoke( string $changelog, SecretKeyId $keyId, ): void { - $tagFileName = Filesystem\create_temporary_file(Env\temp_dir(), 'created_tag'); + if (($this->hasTag)($repositoryDirectory, $tagName) === true) { + return; + } + + $tagFileName = create_temporary_file(temp_dir(), 'created_tag'); + + write($tagFileName, $changelog); - File\write($tagFileName, $changelog); + execute('git', ['checkout', $sourceBranch->name()], $repositoryDirectory); - Shell\execute('git', ['checkout', $sourceBranch->name()], $repositoryDirectory); - Shell\execute('git', ['tag', $tagName, '-F', $tagFileName, '--cleanup=whitespace', '--local-user=' . $keyId->id()], $repositoryDirectory); + execute( + 'git', + ['tag', $tagName, '-F', $tagFileName, '--cleanup=whitespace', '--local-user=' . $keyId->id()], + $repositoryDirectory, + ); } } diff --git a/test/unit/Git/CreateTagViaConsoleTest.php b/test/unit/Git/CreateTagViaConsoleTest.php index 7d4c131f..9e41b066 100644 --- a/test/unit/Git/CreateTagViaConsoleTest.php +++ b/test/unit/Git/CreateTagViaConsoleTest.php @@ -5,6 +5,8 @@ namespace Laminas\AutomaticReleases\Test\Unit\Git; use Laminas\AutomaticReleases\Git\CreateTagViaConsole; +use Laminas\AutomaticReleases\Git\HasTag; +use Laminas\AutomaticReleases\Git\HasTagViaConsole; use Laminas\AutomaticReleases\Git\Value\BranchName; use Laminas\AutomaticReleases\Gpg\ImportGpgKeyFromStringViaTemporaryFile; use Laminas\AutomaticReleases\Gpg\SecretKeyId; @@ -47,18 +49,20 @@ protected function setUp(): void public function testCreatesSignedTag(): void { $sourceUri = $this->createMock(UriInterface::class); + $sourceUri->method('__toString')->willReturn($this->repository); - $sourceUri->method('__toString') - ->willReturn($this->repository); + $hasTag = $this->createMock(HasTag::class); + $hasTag->method('__invoke') + ->with($this->repository, 'name-of-the-tag') + ->willReturn(false); - (new CreateTagViaConsole()) - ->__invoke( - $this->repository, - BranchName::fromName('tag-branch'), - 'name-of-the-tag', - 'changelog text for the tag', - $this->key, - ); + (new CreateTagViaConsole($hasTag))( + $this->repository, + BranchName::fromName('tag-branch'), + 'name-of-the-tag', + 'changelog text for the tag', + $this->key, + ); Shell\execute('git', ['tag', '-v', 'name-of-the-tag'], $this->repository); @@ -69,4 +73,36 @@ public function testCreatesSignedTag(): void self::assertStringContainsString('a commit', $fetchedTag); self::assertStringContainsString('-----BEGIN PGP SIGNATURE-----', $fetchedTag); } + + public function testSkipsIfTagAlreadyExists(): void + { + $sourceUri = $this->createMock(UriInterface::class); + $sourceUri->method('__toString')->willReturn($this->repository); + + $hasTag = new HasTagViaConsole(); + + (new CreateTagViaConsole($hasTag))( + $this->repository, + BranchName::fromName('tag-branch'), + 'name-of-the-tag', + 'changelog text for the tag', + $this->key, + ); + + Shell\execute('git', ['tag', '-v', 'name-of-the-tag'], $this->repository); + $fetchedTag = Shell\execute('git', ['show', 'name-of-the-tag'], $this->repository); + + self::assertStringContainsString('tag name-of-the-tag', $fetchedTag); + self::assertStringContainsString('changelog text for the tag', $fetchedTag); + self::assertStringContainsString('a commit', $fetchedTag); + self::assertStringContainsString('-----BEGIN PGP SIGNATURE-----', $fetchedTag); + + (new CreateTagViaConsole($hasTag))( + $this->repository, + BranchName::fromName('tag-branch'), + 'name-of-the-tag', + 'changelog text for the tag', + $this->key, + ); + } } From 6c9d81afca5ccd1c3bbfef40290bd066b6c4e47c Mon Sep 17 00:00:00 2001 From: Nathanael Esayeas Date: Sun, 1 Jan 2023 23:41:06 -0600 Subject: [PATCH 3/5] Revert Imports Signed-off-by: Nathanael Esayeas --- src/Git/CreateTagViaConsole.php | 17 +++++++++-------- src/Git/HasTagViaConsole.php | 9 +++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Git/CreateTagViaConsole.php b/src/Git/CreateTagViaConsole.php index 5c8e68b8..dd073aed 100644 --- a/src/Git/CreateTagViaConsole.php +++ b/src/Git/CreateTagViaConsole.php @@ -6,11 +6,12 @@ use Laminas\AutomaticReleases\Git\Value\BranchName; use Laminas\AutomaticReleases\Gpg\SecretKeyId; +use Psl\Env; +use Psl\File; +use Psl\Filesystem; +use Psl\Shell; -use function Psl\Env\temp_dir; -use function Psl\File\write; -use function Psl\Filesystem\create_temporary_file; -use function Psl\Shell\execute; +use function sprintf; final class CreateTagViaConsole implements CreateTag { @@ -29,13 +30,13 @@ public function __invoke( return; } - $tagFileName = create_temporary_file(temp_dir(), 'created_tag'); + $tagFileName = Filesystem\create_temporary_file(Env\temp_dir(), 'created_tag'); - write($tagFileName, $changelog); + File\write($tagFileName, $changelog); - execute('git', ['checkout', $sourceBranch->name()], $repositoryDirectory); + Shell\execute('git', ['checkout', $sourceBranch->name()], $repositoryDirectory); - execute( + Shell\execute( 'git', ['tag', $tagName, '-F', $tagFileName, '--cleanup=whitespace', '--local-user=' . $keyId->id()], $repositoryDirectory, diff --git a/src/Git/HasTagViaConsole.php b/src/Git/HasTagViaConsole.php index 5bc29b35..1308796a 100644 --- a/src/Git/HasTagViaConsole.php +++ b/src/Git/HasTagViaConsole.php @@ -4,7 +4,8 @@ namespace Laminas\AutomaticReleases\Git; -use function Psl\Shell\execute; +use Psl\Shell; + use function str_contains; use function trim; @@ -12,12 +13,12 @@ final class HasTagViaConsole implements HasTag { public function __invoke(string $repositoryDirectory, string $tagName): bool { - $outout = execute('git', ['tag', '--list', $tagName], $repositoryDirectory); + $output = Shell\execute('git', ['tag', '--list', $tagName], $repositoryDirectory); - if (trim($outout) === '') { + if (trim($output) === '') { return false; } - return str_contains($outout, $tagName); + return str_contains($output, $tagName); } } From b51fcfdae544d59ddfc599a9d9e39f23bff95003 Mon Sep 17 00:00:00 2001 From: Nathanael Esayeas Date: Sun, 1 Jan 2023 23:43:08 -0600 Subject: [PATCH 4/5] Add logs when skipping already existing tags Signed-off-by: Nathanael Esayeas --- bin/console.php | 2 +- src/Git/CreateTagViaConsole.php | 13 +++++++--- test/unit/Git/CreateTagViaConsoleTest.php | 29 +++++++++++++++++------ 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/bin/console.php b/bin/console.php index 07533fdf..944da302 100755 --- a/bin/console.php +++ b/bin/console.php @@ -128,7 +128,7 @@ static function (int $errorCode, string $message = '', string $file = '', int $l $getMilestone, $commitChangelog, $createReleaseText, - new CreateTagViaConsole(new HasTagViaConsole()), + new CreateTagViaConsole(new HasTagViaConsole(), $logger), $push, $createRelease, ), diff --git a/src/Git/CreateTagViaConsole.php b/src/Git/CreateTagViaConsole.php index dd073aed..4f999f17 100644 --- a/src/Git/CreateTagViaConsole.php +++ b/src/Git/CreateTagViaConsole.php @@ -10,13 +10,16 @@ use Psl\File; use Psl\Filesystem; use Psl\Shell; +use Psr\Log\LoggerInterface; use function sprintf; final class CreateTagViaConsole implements CreateTag { - public function __construct(private HasTag $hasTag) - { + public function __construct( + private readonly HasTag $hasTag, + private readonly LoggerInterface $logger, + ) { } public function __invoke( @@ -26,7 +29,11 @@ public function __invoke( string $changelog, SecretKeyId $keyId, ): void { - if (($this->hasTag)($repositoryDirectory, $tagName) === true) { + if (($this->hasTag)($repositoryDirectory, $tagName)) { + $this->logger->info( + sprintf('[CreateTagViaConsole] Skipping this step; tag "%s" already exists.', $tagName), + ); + return; } diff --git a/test/unit/Git/CreateTagViaConsoleTest.php b/test/unit/Git/CreateTagViaConsoleTest.php index 9e41b066..0c3e0027 100644 --- a/test/unit/Git/CreateTagViaConsoleTest.php +++ b/test/unit/Git/CreateTagViaConsoleTest.php @@ -15,8 +15,10 @@ use Psl\Filesystem; use Psl\Shell; use Psr\Http\Message\UriInterface; +use Psr\Log\LoggerInterface; use function Psl\File\read; +use function sprintf; /** @covers \Laminas\AutomaticReleases\Git\CreateTagViaConsole */ final class CreateTagViaConsoleTest extends TestCase @@ -48,6 +50,9 @@ protected function setUp(): void public function testCreatesSignedTag(): void { + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::never())->method('info'); + $sourceUri = $this->createMock(UriInterface::class); $sourceUri->method('__toString')->willReturn($this->repository); @@ -56,7 +61,7 @@ public function testCreatesSignedTag(): void ->with($this->repository, 'name-of-the-tag') ->willReturn(false); - (new CreateTagViaConsole($hasTag))( + (new CreateTagViaConsole($hasTag, $logger))( $this->repository, BranchName::fromName('tag-branch'), 'name-of-the-tag', @@ -76,31 +81,41 @@ public function testCreatesSignedTag(): void public function testSkipsIfTagAlreadyExists(): void { + $tagName = 'name-of-the-tag'; + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::never()) + ->method('info'); + $sourceUri = $this->createMock(UriInterface::class); $sourceUri->method('__toString')->willReturn($this->repository); $hasTag = new HasTagViaConsole(); - (new CreateTagViaConsole($hasTag))( + (new CreateTagViaConsole($hasTag, $logger))( $this->repository, BranchName::fromName('tag-branch'), - 'name-of-the-tag', + $tagName, 'changelog text for the tag', $this->key, ); - Shell\execute('git', ['tag', '-v', 'name-of-the-tag'], $this->repository); - $fetchedTag = Shell\execute('git', ['show', 'name-of-the-tag'], $this->repository); + Shell\execute('git', ['tag', '-v', $tagName], $this->repository); + $fetchedTag = Shell\execute('git', ['show', $tagName], $this->repository); self::assertStringContainsString('tag name-of-the-tag', $fetchedTag); self::assertStringContainsString('changelog text for the tag', $fetchedTag); self::assertStringContainsString('a commit', $fetchedTag); self::assertStringContainsString('-----BEGIN PGP SIGNATURE-----', $fetchedTag); - (new CreateTagViaConsole($hasTag))( + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::once()) + ->method('info') + ->with(sprintf('[CreateTagViaConsole] Skipping this step; tag "%s" already exists.', $tagName)); + + (new CreateTagViaConsole($hasTag, $logger))( $this->repository, BranchName::fromName('tag-branch'), - 'name-of-the-tag', + $tagName, 'changelog text for the tag', $this->key, ); From 1a771681999e51a42fc699248af8bc85417b68d0 Mon Sep 17 00:00:00 2001 From: Nathanael Esayeas Date: Sun, 1 Jan 2023 23:52:12 -0600 Subject: [PATCH 5/5] Fix Psalm docs Signed-off-by: Nathanael Esayeas --- src/Git/CreateTag.php | 5 +++- src/Git/HasTag.php | 5 +++- test/unit/Git/HasTagViaConsoleTest.php | 38 ++++++++++++++------------ 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/Git/CreateTag.php b/src/Git/CreateTag.php index fb6b3cc3..a8822d18 100644 --- a/src/Git/CreateTag.php +++ b/src/Git/CreateTag.php @@ -9,7 +9,10 @@ interface CreateTag { - /** @param non-empty-string $repositoryDirectory */ + /** + * @param non-empty-string $repositoryDirectory + * @param non-empty-string $tagName + */ public function __invoke( string $repositoryDirectory, BranchName $sourceBranch, diff --git a/src/Git/HasTag.php b/src/Git/HasTag.php index 0dc274fa..0c1bfaa3 100644 --- a/src/Git/HasTag.php +++ b/src/Git/HasTag.php @@ -6,7 +6,10 @@ interface HasTag { - /** @param non-empty-string $repositoryDirectory */ + /** + * @param non-empty-string $repositoryDirectory + * @param non-empty-string $tagName + */ public function __invoke( string $repositoryDirectory, string $tagName, diff --git a/test/unit/Git/HasTagViaConsoleTest.php b/test/unit/Git/HasTagViaConsoleTest.php index 1fae7a9b..7bd3a5b9 100644 --- a/test/unit/Git/HasTagViaConsoleTest.php +++ b/test/unit/Git/HasTagViaConsoleTest.php @@ -7,13 +7,11 @@ use Laminas\AutomaticReleases\Git\HasTag; use Laminas\AutomaticReleases\Git\HasTagViaConsole; use PHPUnit\Framework\TestCase; +use Psl\Env; +use Psl\Filesystem; +use Psl\Shell; use function array_map; -use function Psl\Env\temp_dir; -use function Psl\Filesystem\create_directory; -use function Psl\Filesystem\create_temporary_file; -use function Psl\Filesystem\delete_file; -use function Psl\Shell\execute; use function sprintf; /** @covers \Laminas\AutomaticReleases\Git\HasTagViaConsole */ @@ -27,17 +25,17 @@ protected function setUp(): void { parent::setUp(); - $this->repository = create_temporary_file(temp_dir(), 'HasTagViaConsoleRepository'); + $this->repository = Filesystem\create_temporary_file(Env\temp_dir(), 'HasTagViaConsoleRepository'); $this->hasTag = new HasTagViaConsole(); - delete_file($this->repository); - create_directory($this->repository); + Filesystem\delete_file($this->repository); + Filesystem\create_directory($this->repository); - execute('git', ['init'], $this->repository); + Shell\execute('git', ['init'], $this->repository); - execute('git', ['config', 'user.email', 'me@example.com'], $this->repository); - execute('git', ['config', 'user.name', 'Just Me'], $this->repository); + Shell\execute('git', ['config', 'user.email', 'me@example.com'], $this->repository); + Shell\execute('git', ['config', 'user.name', 'Just Me'], $this->repository); array_map(fn (string $tag) => $this->createTag($tag), [ '1.0.0', @@ -47,17 +45,23 @@ protected function setUp(): void private function createTag(string $tag): void { - execute('git', ['commit', '--allow-empty', '-m', 'a commit for version ' . $tag], $this->repository); - execute('git', ['tag', '-a', $tag, '-m', 'version ' . $tag], $this->repository); + Shell\execute('git', ['commit', '--allow-empty', '-m', 'a commit for version ' . $tag], $this->repository); + Shell\execute('git', ['tag', '-a', $tag, '-m', 'version ' . $tag], $this->repository); } - /** @param non-empty-string $repository */ + /** + * @param non-empty-string $repository + * @param non-empty-string $tag + */ private function assertGitTagExists(string $repository, string $tag): void { self::assertTrue(($this->hasTag)($repository, $tag), sprintf('Failed asserting git tag "%s" exists.', $tag)); } - /** @param non-empty-string $repository */ + /** + * @param non-empty-string $repository + * @param non-empty-string $tag + */ private function assertGitTagMissing(string $repository, string $tag): void { self::assertFalse(($this->hasTag)($repository, $tag), sprintf('Failed asserting git tag "%s" is missing.', $tag)); @@ -65,11 +69,11 @@ private function assertGitTagMissing(string $repository, string $tag): void public function testHasTag(): void { - self::assertGitTagExists($this->repository, '1.0.0'); + $this->assertGitTagExists($this->repository, '1.0.0'); } public function testHasTagMissing(): void { - self::assertGitTagMissing($this->repository, '10.0.0'); + $this->assertGitTagMissing($this->repository, '10.0.0'); } }