diff --git a/config/services.yaml b/config/services.yaml index 41c18e3..95aea5d 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -74,6 +74,8 @@ parameters: - 'App\Subscriber\RewriteUnwantedPhrasesSubscriber' - 'App\Subscriber\AllowEditFromMaintainerSubscriber' secret: '%env(SYMFONY_AI_SECRET)%' + ignored_labels: + - 'Run examples' symfony/ux: subscribers: diff --git a/src/Model/Repository.php b/src/Model/Repository.php index db7d2a0..4eaf098 100644 --- a/src/Model/Repository.php +++ b/src/Model/Repository.php @@ -10,12 +10,14 @@ class Repository { /** - * @param string|null $secret the webhook secret used by GitHub + * @param string|null $secret the webhook secret used by GitHub + * @param list $ignoredLabels labels that should not be auto-applied from PR/issue titles */ public function __construct( private readonly string $vendor, private readonly string $name, private readonly ?string $secret = null, + private readonly array $ignoredLabels = [], ) { } @@ -44,6 +46,14 @@ public function getNeedsReviewUrl(): string ); } + /** + * @return list + */ + public function getIgnoredLabels(): array + { + return $this->ignoredLabels; + } + public function getFullName(): string { return sprintf('%s/%s', $this->getVendor(), $this->getName()); diff --git a/src/Service/LabelNameExtractor.php b/src/Service/LabelNameExtractor.php index 246c68d..08f748d 100644 --- a/src/Service/LabelNameExtractor.php +++ b/src/Service/LabelNameExtractor.php @@ -54,6 +54,9 @@ public function extractLabels(string $title, Repository $repository): array } } + $ignoredLabels = array_map('strtolower', $repository->getIgnoredLabels()); + $labels = array_values(array_filter($labels, static fn (string $label): bool => !\in_array(strtolower($label), $ignoredLabels, true))); + $this->logger->debug('Searched for labels in title', ['title' => $title, 'labels' => \json_encode($labels, \JSON_THROW_ON_ERROR)]); return $labels; diff --git a/src/Service/RepositoryProvider.php b/src/Service/RepositoryProvider.php index 2b091be..87d2ecf 100644 --- a/src/Service/RepositoryProvider.php +++ b/src/Service/RepositoryProvider.php @@ -15,7 +15,7 @@ class RepositoryProvider private array $repositories = []; /** - * @param array $repositories + * @param array}> $repositories */ public function __construct(array $repositories) { @@ -29,7 +29,8 @@ public function __construct(array $repositories) $this->addRepository(new Repository( $vendorName, $repositoryName, - $repositoryData['secret'] ?? null + $repositoryData['secret'] ?? null, + $repositoryData['ignored_labels'] ?? [], )); } } diff --git a/tests/Service/LabelNameExtractorTest.php b/tests/Service/LabelNameExtractorTest.php index 26f3524..9098932 100644 --- a/tests/Service/LabelNameExtractorTest.php +++ b/tests/Service/LabelNameExtractorTest.php @@ -31,4 +31,28 @@ public static function provideLabels(): iterable yield [['Messenger', 'Mime'], '[Messenger] [Mime] Foobar']; yield [['Messenger', 'Mime'], '[Messenger] Foobar [Mime]']; } + + public function testIgnoredLabelsAreFilteredOut(): void + { + $extractor = new LabelNameExtractor(new StaticLabelApi(), new NullLogger()); + $repo = new Repository('carsonbot-playground', 'symfony', null, ['Messenger']); + + $this->assertSame([], $extractor->extractLabels('[Messenger] Foobar', $repo)); + } + + public function testIgnoredLabelsAreCaseInsensitive(): void + { + $extractor = new LabelNameExtractor(new StaticLabelApi(), new NullLogger()); + $repo = new Repository('carsonbot-playground', 'symfony', null, ['messenger']); + + $this->assertSame([], $extractor->extractLabels('[Messenger] Foobar', $repo)); + } + + public function testIgnoredLabelsOnlyFilterConfiguredOnes(): void + { + $extractor = new LabelNameExtractor(new StaticLabelApi(), new NullLogger()); + $repo = new Repository('carsonbot-playground', 'symfony', null, ['Messenger']); + + $this->assertSame(['Mime'], $extractor->extractLabels('[Messenger] [Mime] Foobar', $repo)); + } } diff --git a/tests/Subscriber/AutoLabelFromContentSubscriberTest.php b/tests/Subscriber/AutoLabelFromContentSubscriberTest.php index 6ff5e82..a078794 100644 --- a/tests/Subscriber/AutoLabelFromContentSubscriberTest.php +++ b/tests/Subscriber/AutoLabelFromContentSubscriberTest.php @@ -179,4 +179,39 @@ public static function getPRTests(): array return $tests; } + + public function testIgnoredLabelsAreNotAppliedFromPRTitle(): void + { + $labelsApi = $this->getMockBuilder(StaticLabelApi::class) + ->disableOriginalConstructor() + ->onlyMethods(['addIssueLabels']) + ->getMock(); + + $subscriber = new AutoLabelFromContentSubscriber($labelsApi, new LabelNameExtractor($labelsApi, new NullLogger())); + $repository = new Repository('weaverryan', 'symfony', null, ['Bug']); + + $dispatcher = new EventDispatcher(); + $dispatcher->addSubscriber($subscriber); + + $labelsApi->expects($this->once()) + ->method('addIssueLabels') + ->with(1234, ['Asset', 'BC Break'], $repository); + + $event = new GitHubEvent([ + 'action' => 'opened', + 'pull_request' => [ + 'number' => 1234, + 'title' => '[Asset][bc Break][Bug] Some PR title', + 'body' => '', + 'draft' => false, + ], + ], $repository); + + $dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST); + + $responseData = $event->getResponseData(); + + $this->assertSame(1234, $responseData['pull_request']); + $this->assertSame(['Asset', 'BC Break'], $responseData['pr_labels']); + } }