diff --git a/src/Subscriber/AutoUpdateTitleWithLabelSubscriber.php b/src/Subscriber/AutoUpdateTitleWithLabelSubscriber.php index 9965d8a..eea7726 100644 --- a/src/Subscriber/AutoUpdateTitleWithLabelSubscriber.php +++ b/src/Subscriber/AutoUpdateTitleWithLabelSubscriber.php @@ -75,8 +75,22 @@ public function onPullRequest(GitHubEvent $event): void // Clean string from all HTML chars and remove whitespace at the beginning $prTitle = (string) preg_replace('@^[\h\s]+@u', '', html_entity_decode($prTitle)); - // Add back labels - $prTitle = trim($prPrefix.' '.trim($prTitle)); + // Extract any bracketed text at the beginning of the title + $leadingBrackets = ''; + $remainingTitle = $prTitle; + + // Match all consecutive bracketed items at the start of the title + while (preg_match('/^\[([^]]+)]\s*/', $remainingTitle, $matches)) { + $leadingBrackets .= '['.$matches[1].']'; + $remainingTitle = substr($remainingTitle, strlen($matches[0])); + } + + // Combine: valid labels + any unrecognized brackets + remaining title + if ('' !== trim($remainingTitle)) { + $prTitle = $prPrefix.$leadingBrackets.' '.trim($remainingTitle); + } else { + $prTitle = $prPrefix.$leadingBrackets; + } if ($originalTitle === $prTitle) { return; } diff --git a/tests/Subscriber/AutoUpdateTitleWithLabelSubscriberTest.php b/tests/Subscriber/AutoUpdateTitleWithLabelSubscriberTest.php index 6a935f4..174fd01 100644 --- a/tests/Subscriber/AutoUpdateTitleWithLabelSubscriberTest.php +++ b/tests/Subscriber/AutoUpdateTitleWithLabelSubscriberTest.php @@ -59,7 +59,7 @@ public function testOnPullRequestLabeled() $this->assertCount(2, $responseData); $this->assertSame(1234, $responseData['pull_request']); - $this->assertSame('[Console][FrameworkBundle] [bar] Foo', $responseData['new_title']); + $this->assertSame('[Console][FrameworkBundle][bar] Foo', $responseData['new_title']); } public function testOnPullRequestLabeledCaseInsensitive() @@ -110,7 +110,7 @@ public function testRemoveLabel() $responseData = $event->getResponseData(); $this->assertCount(2, $responseData); $this->assertSame(1234, $responseData['pull_request']); - $this->assertSame('[Console] [Random] Foo normal title', $responseData['new_title']); + $this->assertSame('[Console][Random] Foo normal title', $responseData['new_title']); } public function testExtraBlankSpace() @@ -129,4 +129,169 @@ public function testExtraBlankSpace() $this->assertSame(57753, $responseData['pull_request']); $this->assertSame('[ErrorHandler] restrict the maximum length of the X-Debug-Exception header', $responseData['new_title']); } + + public function testMultipleLabelsWithoutSpaceBetweenBrackets() + { + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => 'Foo Bar', + 'labels' => [ + ['name' => 'Platform', 'color' => 'dddddd'], + ['name' => 'Agent', 'color' => 'dddddd'], + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Agent][Platform] Foo Bar', $responseData['new_title']); + } + + public function testMultipleLabelsUpdateRemovesSpaceBetweenBrackets() + { + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => '[Platform] [Agent] Foo Bar', // Title already has labels with space + 'labels' => [ + ['name' => 'Platform', 'color' => 'dddddd'], + ['name' => 'Agent', 'color' => 'dddddd'], + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Agent][Platform] Foo Bar', $responseData['new_title']); + } + + public function testAddingLabelToExistingLabeledTitle() + { + // Simulating when we already have [Platform] and are adding Agent label + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => '[Platform] Foo Bar', // Title already has one label + 'labels' => [ + ['name' => 'Platform', 'color' => 'dddddd'], + ['name' => 'Agent', 'color' => 'dddddd'], // New label added + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Agent][Platform] Foo Bar', $responseData['new_title']); + } + + public function testLabelsNotRecognizedAsValidLabels() + { + // This test simulates what happens when [Platform] and [Agent] are in the title + // but they're NOT recognized as valid labels (wrong case or not in label list) + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => '[Platform] [Agent] Foo Bar', // These are in title but not recognized + 'labels' => [ + ['name' => 'Bug', 'color' => 'dddddd'], // Different valid label + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + // Since Platform and Agent are not recognized labels, they stay in the title without spaces + $this->assertSame('[Bug][Platform][Agent] Foo Bar', $responseData['new_title']); + } + + public function testBugWithLabelsNotInRepositoryLabelList() + { + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => 'Foo Bar', + 'labels' => [ + // These labels are attached to PR but not in the StaticLabelApi list + ['name' => 'Platform', 'color' => 'dddddd'], + ['name' => 'Agent', 'color' => 'dddddd'], + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Agent][Platform] Foo Bar', $responseData['new_title']); + } + + /** + * Test that ensures no spaces are ever added between label brackets. + */ + public function testNoSpacesBetweenLabelBrackets() + { + // Test with empty title after label removal + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => '[Console] [FrameworkBundle]', // Only labels, no other text + 'labels' => [ + ['name' => 'Console', 'color' => 'dddddd'], + ['name' => 'FrameworkBundle', 'color' => 'dddddd'], + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + + // Should produce labels without spaces and no trailing space + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Console][FrameworkBundle]', $responseData['new_title']); + } + + /** + * Test when title has unrecognized bracketed text like [Foo] that isn't a label. + */ + public function testUnrecognizedBracketedTextWithNewLabel() + { + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => '[Foo] Bar', // [Foo] is not a recognized label + 'labels' => [ + ['name' => 'Console', 'color' => 'dddddd'], // Adding Console label + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + + // Currently produces: [Console] [Foo] Bar (with space) + // Should produce: [Console][Foo] Bar (no space between brackets) + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Console][Foo] Bar', $responseData['new_title']); + } + + /** + * Test multiple unrecognized bracketed texts with real labels. + */ + public function testMultipleUnrecognizedBracketsWithRealLabels() + { + $event = new GitHubEvent(['action' => 'labeled', 'number' => 1234, 'pull_request' => []], $this->repository); + $this->pullRequestApi->method('show')->willReturn([ + 'title' => '[TODO] [WIP] [Foo] Some title', // [TODO], [WIP], [Foo] are not recognized labels + 'labels' => [ + ['name' => 'Console', 'color' => 'dddddd'], + ['name' => 'FrameworkBundle', 'color' => 'dddddd'], + ], + ]); + + $this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + $responseData = $event->getResponseData(); + + // Should keep unrecognized brackets but without spaces between any brackets + $this->assertCount(2, $responseData); + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame('[Console][FrameworkBundle][TODO][WIP][Foo] Some title', $responseData['new_title']); + } }