Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/Api/Issue/GithubIssueApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,25 @@ public function findStaleIssues(Repository $repository, \DateTimeImmutable $noUp
'desc',
]);
}

public function findBotComment(Repository $repository, int $issueNumber, string $search): ?int
{
$allComments = $this->issueCommentApi->all($repository->getVendor(), $repository->getName(), $issueNumber, ['per_page' => 100]);
foreach (array_reverse($allComments) as $comment) {
if ($this->botUsername !== ($comment['user']['login'] ?? null)) {
continue;
}

if (str_contains($comment['body'] ?? '', $search)) {
return $comment['id'];
}
}

return null;
}

public function removeComment(Repository $repository, int $commentId): void
{
$this->issueCommentApi->remove($repository->getVendor(), $repository->getName(), $commentId);
}
}
4 changes: 4 additions & 0 deletions src/Api/Issue/IssueApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,8 @@ public function findStaleIssues(Repository $repository, \DateTimeImmutable $noUp
* Close an issue and mark it as "not_planned".
*/
public function close(Repository $repository, int $issueNumber): void;

public function findBotComment(Repository $repository, int $issueNumber, string $search): ?int;

public function removeComment(Repository $repository, int $commentId): void;
}
9 changes: 9 additions & 0 deletions src/Api/Issue/NullIssueApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,13 @@ public function findStaleIssues(Repository $repository, \DateTimeImmutable $noUp
public function close(Repository $repository, int $issueNumber): void
{
}

public function findBotComment(Repository $repository, int $issueNumber, string $search): ?int
{
return null;
}

public function removeComment(Repository $repository, int $commentId): void
{
}
}
19 changes: 15 additions & 4 deletions src/Subscriber/AllowEditFromMaintainerSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,31 @@ public function __construct(
public function onPullRequest(GitHubEvent $event): void
{
$data = $event->getData();
if (!in_array($data['action'], ['opened', 'ready_for_review']) || ($data['pull_request']['draft'] ?? false)) {
if (!in_array($data['action'], ['opened', 'ready_for_review', 'edited']) || ($data['pull_request']['draft'] ?? false)) {
return;
}

if ($data['repository']['full_name'] === $data['pull_request']['head']['repo']['full_name']) {
return;
}

$repository = $event->getRepository();
$pullRequestNumber = $data['pull_request']['number'];
$commentId = $this->commentsApi->findBotComment($repository, $pullRequestNumber, 'Allow edits from maintainer');

if ($data['pull_request']['maintainer_can_modify'] ?? true) {
if ($commentId) {
$this->commentsApi->removeComment($event->getRepository(), $commentId);
}

return;
}

if ($data['repository']['full_name'] === $data['pull_request']['head']['repo']['full_name']) {
// Avoid duplicate comments
if ($commentId) {
return;
}

$repository = $event->getRepository();
$pullRequestNumber = $data['pull_request']['number'];
$this->commentsApi->commentOnIssue($repository, $pullRequestNumber, <<<TXT
It looks like you unchecked the "Allow edits from maintainer" box. That is fine, but please note that if you have multiple commits, you'll need to squash your commits into one before this can be merged. Or, you can check the "Allow edits from maintainers" box and the maintainer can squash for you.

Expand Down
13 changes: 12 additions & 1 deletion src/Subscriber/MismatchBranchDescriptionSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function __construct(
public function onPullRequest(GitHubEvent $event): void
{
$data = $event->getData();
if (!in_array($data['action'], ['opened', 'ready_for_review']) || ($data['pull_request']['draft'] ?? false)) {
if (!in_array($data['action'], ['opened', 'ready_for_review', 'edited']) || ($data['pull_request']['draft'] ?? false)) {
return;
}

Expand All @@ -38,7 +38,18 @@ public function onPullRequest(GitHubEvent $event): void
}

$targetBranch = $data['pull_request']['base']['ref'];
$commentId = $this->issueApi->findBotComment($event->getRepository(), $number, 'seems your PR description refers to branch');

if ($targetBranch === $descriptionBranch) {
if ($commentId) {
$this->issueApi->removeComment($event->getRepository(), $commentId);
}

return;
}

// Avoid duplicate comments
if ($commentId) {
return;
}

Expand Down
20 changes: 14 additions & 6 deletions src/Subscriber/UnsupportedBranchSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,11 @@ public function __construct(
public function onPullRequest(GitHubEvent $event): void
{
$data = $event->getData();
if (!in_array($data['action'], ['opened', 'ready_for_review']) || ($data['pull_request']['draft'] ?? false)) {
if (!in_array($data['action'], ['opened', 'ready_for_review', 'edited']) || ($data['pull_request']['draft'] ?? false)) {
return;
}

$targetBranch = $data['pull_request']['base']['ref'];
if ($targetBranch === $data['repository']['default_branch']) {
return;
}

try {
$validBranches = $this->symfonyVersionProvider->getMaintainedVersions();
Expand All @@ -44,11 +41,22 @@ public function onPullRequest(GitHubEvent $event): void
return;
}

if (in_array($targetBranch, $validBranches)) {
$number = $data['pull_request']['number'];
$commentId = $this->issueApi->findBotComment($event->getRepository(), $number, 'target one of these branches instead');

if ($targetBranch === $data['repository']['default_branch'] || in_array($targetBranch, $validBranches)) {
if ($commentId) {
$this->issueApi->removeComment($event->getRepository(), $commentId);
}

return;
}

// Avoid duplicate comments
if ($commentId) {
return;
}

$number = $data['pull_request']['number'];
$validBranchesString = implode(', ', $validBranches);
$this->issueApi->commentOnIssue($event->getRepository(), $number, <<<TXT
Hey!
Expand Down
76 changes: 76 additions & 0 deletions tests/Subscriber/AllowEditFromMaintainerSubscriberTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace App\Tests\Subscriber;

use App\Api\Issue\NullIssueApi;
use App\Event\GitHubEvent;
use App\GitHubEvents;
use App\Model\Repository;
use App\Subscriber\AllowEditFromMaintainerSubscriber;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;

class AllowEditFromMaintainerSubscriberTest extends TestCase
{
private $issueApi;
private $repository;
private $dispatcher;

protected function setUp(): void
{
$this->issueApi = $this->createMock(NullIssueApi::class);
$this->repository = new Repository('carsonbot-playground', 'symfony', null);

$subscriber = new AllowEditFromMaintainerSubscriber($this->issueApi);

$this->dispatcher = new EventDispatcher();
$this->dispatcher->addSubscriber($subscriber);
}

public function testOnPullRequestEditedCleanup()
{
$this->issueApi->expects($this->once())
->method('findBotComment')
->with($this->repository, 1234, 'Allow edits from maintainer')
->willReturn(666);

$this->issueApi->expects($this->once())
->method('removeComment')
->with($this->repository, 666);

$event = new GitHubEvent([
'action' => 'edited',
'pull_request' => [
'number' => 1234,
'maintainer_can_modify' => true,
'head' => ['repo' => ['full_name' => 'contributor/symfony']],
],
'repository' => ['full_name' => 'fabpot/symfony', 'owner' => ['login' => 'fabpot'], 'name' => 'symfony'],
], $this->repository);

$this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST);
}

public function testOnPullRequestEditedIdempotency()
{
$this->issueApi->expects($this->once())
->method('findBotComment')
->with($this->repository, 1234, 'Allow edits from maintainer')
->willReturn(666);

$this->issueApi->expects($this->never())
->method('commentOnIssue');

$event = new GitHubEvent([
'action' => 'edited',
'pull_request' => [
'number' => 1234,
'maintainer_can_modify' => false,
'head' => ['repo' => ['full_name' => 'contributor/symfony']],
],
'repository' => ['full_name' => 'fabpot/symfony', 'owner' => ['login' => 'fabpot'], 'name' => 'symfony'],
], $this->repository);

$this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST);
}
}
57 changes: 57 additions & 0 deletions tests/Subscriber/MismatchBranchDescriptionSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,61 @@ public function testOnPullRequestOpenBranchNotInTable()

$this->assertCount(0, $responseData);
}

public function testOnPullRequestEditedCleanup()
{
$this->issueApi->expects($this->once())
->method('findBotComment')
->with($this->repository, 1234, 'seems your PR description refers to branch')
->willReturn(777);

$this->issueApi->expects($this->once())
->method('removeComment')
->with($this->repository, 777);

$body = <<<TXT
| Q | A
| --- | ---
| Branch? | 6.2 |
TXT;

$event = new GitHubEvent([
'action' => 'edited',
'pull_request' => [
'number' => 1234,
'body' => $body,
'base' => ['ref' => '6.2'],
],
], $this->repository);

$this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST);
}

public function testOnPullRequestEditedIdempotency()
{
$this->issueApi->expects($this->once())
->method('findBotComment')
->with($this->repository, 1234, 'seems your PR description refers to branch')
->willReturn(777);

$this->issueApi->expects($this->never())
->method('commentOnIssue');

$body = <<<TXT
| Q | A
| --- | ---
| Branch? | 6.2 |
TXT;

$event = new GitHubEvent([
'action' => 'edited',
'pull_request' => [
'number' => 1234,
'body' => $body,
'base' => ['ref' => '5.4'], // Mismatch
],
], $this->repository);

$this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST);
}
}
49 changes: 49 additions & 0 deletions tests/Subscriber/UnsupportedBranchSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,53 @@ public function testOnPullRequestNotOpen()
$responseData = $event->getResponseData();
$this->assertEmpty($responseData);
}

public function testOnPullRequestEditedCleanup()
{
$this->issueApi->expects($this->once())
->method('findBotComment')
->with($this->repository, 1234, 'target one of these branches instead')
->willReturn(888);

$this->issueApi->expects($this->once())
->method('removeComment')
->with($this->repository, 888);

$event = new GitHubEvent([
'action' => 'edited',
'pull_request' => [
'number' => 1234,
'base' => ['ref' => '4.4'],
],
'repository' => [
'default_branch' => '5.x',
],
], $this->repository);

$this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST);
}

public function testOnPullRequestEditedIdempotency()
{
$this->issueApi->expects($this->once())
->method('findBotComment')
->with($this->repository, 1234, 'target one of these branches instead')
->willReturn(888);

$this->issueApi->expects($this->never())
->method('commentOnIssue');

$event = new GitHubEvent([
'action' => 'edited',
'pull_request' => [
'number' => 1234,
'base' => ['ref' => '4.3'], // Unsupported branch
],
'repository' => [
'default_branch' => '5.x',
],
], $this->repository);

$this->dispatcher->dispatch($event, GitHubEvents::PULL_REQUEST);
}
}