Skip to content

Commit 37c78dc

Browse files
committed
Merge branch 'fix_27' of https://github.com/javiereguiluz/carsonbot into javiereguiluz-fix_27
* 'fix_27' of https://github.com/javiereguiluz/carsonbot: Fixed tests They are "labels", not "tags" Improved the way we extract labels from PR titles Autolabel new Pull Requests
2 parents 114c50f + 8f115f7 commit 37c78dc

File tree

7 files changed

+199
-272
lines changed

7 files changed

+199
-272
lines changed

app/config/github.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ services:
1515
arguments:
1616
- '@app.status_api'
1717

18+
app.subscriber.auto_label_pr_from_content_subscriber:
19+
class: AppBundle\Subscriber\AutoLabelPRFromContentSubscriber
20+
arguments:
21+
- '@app.github.cached_labels_api'
22+
1823
parameters:
1924
# point to the main symfony repositories
2025
repositories:
@@ -23,7 +28,9 @@ parameters:
2328
- app.subscriber.status_change_by_comment_subscriber
2429
- app.subscriber.needs_review_new_pr_subscriber
2530
- app.subscriber.bug_label_new_issue_subscriber
31+
- app.subscriber.auto_label_pr_from_content_subscriber
2632
# secret: change_me
33+
2734
symfony/symfony-docs:
2835
subscribers:
2936
- app.subscriber.status_change_by_comment_subscriber
@@ -36,3 +43,4 @@ parameters:
3643
- app.subscriber.status_change_by_comment_subscriber
3744
- app.subscriber.needs_review_new_pr_subscriber
3845
- app.subscriber.bug_label_new_issue_subscriber
46+
- app.subscriber.auto_label_pr_from_content_subscriber

src/AppBundle/Controller/WebhookController.php

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,64 @@ class WebhookController extends Controller
1616
*/
1717
public function githubAction(Request $request)
1818
{
19-
$responseData = $this->get('app.github.request_handler')->handle($request);
19+
$data = json_decode($request->getContent(), true);
20+
if ($data === null) {
21+
throw new \Exception('Invalid JSON body!');
22+
}
23+
24+
$event = $request->headers->get('X-Github-Event');
25+
$listener = $this->get('app.issue_listener');
26+
27+
switch ($event) {
28+
case 'issue_comment':
29+
$responseData = [
30+
'issue' => $data['issue']['number'],
31+
'status_change' => $listener->handleCommentAddedEvent(
32+
$data['issue']['number'],
33+
$data['comment']['body']
34+
),
35+
];
36+
break;
37+
case 'pull_request':
38+
switch ($data['action']) {
39+
case 'opened':
40+
$responseData = [
41+
'pull_request' => $data['pull_request']['number'],
42+
'status_change' => $listener->handlePullRequestCreatedEvent(
43+
$data['pull_request']['number'],
44+
$data['pull_request']['title'],
45+
$data['pull_request']['body']
46+
),
47+
];
48+
break;
49+
default:
50+
$responseData = [
51+
'unsupported_action' => $data['action'],
52+
];
53+
}
54+
break;
55+
case 'issues':
56+
switch ($data['action']) {
57+
case 'labeled':
58+
$responseData = [
59+
'issue' => $data['issue']['number'],
60+
'status_change' => $listener->handleLabelAddedEvent(
61+
$data['issue']['number'],
62+
$data['label']['name']
63+
),
64+
];
65+
break;
66+
default:
67+
$responseData = [
68+
'unsupported_action' => $data['action'],
69+
];
70+
}
71+
break;
72+
default:
73+
$responseData = [
74+
'unsupported_event' => $event,
75+
];
76+
}
2077

2178
return new JsonResponse($responseData);
2279
}

src/AppBundle/Issues/GitHub/GitHubStatusApi.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ public function setIssueStatus($issueNumber, $newStatus, Repository $repository)
6868
}
6969
}
7070

71+
/**
72+
* Replaces the existing issue labels (if any) with the given array of
73+
* new labels. Use an empty array to remove all the existing labels.
74+
*
75+
* @param int $issueNumber The GitHub issue number
76+
* @param array $newLabels
77+
*/
78+
public function setIssueLabels($issueNumber, array $newLabels, Repository $repository)
79+
{
80+
foreach ($newLabels as $label) {
81+
$this->labelsApi->addIssueLabel($issueNumber, $label, $repository);
82+
}
83+
}
84+
7185
public function getIssueStatus($issueNumber, Repository $repository)
7286
{
7387
$currentLabels = $this->labelsApi->getIssueLabels($issueNumber, $repository);

src/AppBundle/Issues/NullStatusApi.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,10 @@ public function getIssueStatus($issueNumber, Repository $repository)
1515

1616
public function setIssueStatus($issueNumber, $newStatus, Repository $repository)
1717
{
18+
19+
}
20+
21+
public function setIssueLabels($issueNumber, array $newLabels, Repository $repository)
22+
{
1823
}
1924
}

src/AppBundle/Issues/StatusApi.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ interface StatusApi
1414
public function getIssueStatus($issueNumber, Repository $repository);
1515

1616
public function setIssueStatus($issueNumber, $newStatus, Repository $repository);
17+
18+
public function setIssueLabels($issueNumber, array $newLabels, Repository $repository);
1719
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<?php
2+
3+
namespace AppBundle\Subscriber;
4+
5+
use AppBundle\Event\GitHubEvent;
6+
use AppBundle\GitHubEvents;
7+
use AppBundle\Issues\GitHub\CachedLabelsApi;
8+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
9+
10+
/**
11+
* Looks at new pull requests and auto-labels based on text
12+
*/
13+
class AutoLabelPRFromContentSubscriber implements EventSubscriberInterface
14+
{
15+
private $labelsApi;
16+
17+
public function __construct(CachedLabelsApi $labelsApi)
18+
{
19+
$this->labelsApi = $labelsApi;
20+
}
21+
22+
/**
23+
* Adds a "Needs Review" label to new PRs.
24+
*
25+
* @param GitHubEvent $event
26+
*/
27+
public function onPullRequest(GitHubEvent $event)
28+
{
29+
$data = $event->getData();
30+
if ('opened' !== $action = $data['action']) {
31+
$event->setResponseData(array('unsupported_action' => $action));
32+
33+
return;
34+
}
35+
36+
$prNumber = $data['pull_request']['number'];
37+
$prTitle = $data['pull_request']['title'];
38+
$prBody = $data['pull_request']['body'];
39+
$prLabels = array();
40+
41+
// the PR title usually contains one or more labels
42+
foreach ($this->extractLabels($prTitle) as $label) {
43+
$prLabels[] = $label;
44+
}
45+
46+
// the PR body usually indicates if this is a Bug, Feature, BC Break or Deprecation
47+
if (preg_match('/^\|\s*Bug fix?\s*\|\s*yes\s*$/', $prBody, $matches)) {
48+
$prLabels[] = 'Bug';
49+
}
50+
if (preg_match('/^\|\s*New feature?\s*\|\s*yes\s*$/', $prBody, $matches)) {
51+
$prLabels[] = 'Feature';
52+
}
53+
if (preg_match('/^\|\s*BC breaks?\s*\|\s*yes\s*$/', $prBody, $matches)) {
54+
$prLabels[] = 'BC Break';
55+
}
56+
if (preg_match('/^\|\s*Deprecations?\s*\|\s*yes\s*$/', $prBody, $matches)) {
57+
$prLabels[] = 'Deprecation';
58+
}
59+
60+
foreach ($prLabels as $prLabel) {
61+
$this->labelsApi->addIssueLabel($prNumber, $prLabel, $event->getRepository());
62+
}
63+
64+
$event->setResponseData(array(
65+
'pull_request' => $prNumber,
66+
'pr_labels' => $prLabels
67+
));
68+
}
69+
70+
private function extractLabels($prTitle)
71+
{
72+
$labels = array();
73+
74+
// e.g. "[PropertyAccess] [RFC] [WIP] Allow custom methods on property accesses"
75+
if (preg_match_all('/\[(?P<labels>.+)\]/U', $prTitle, $matches)) {
76+
foreach ($matches['labels'] as $label) {
77+
if (in_array($label, $this->getValidLabels())) {
78+
$labels[] = $label;
79+
}
80+
}
81+
}
82+
83+
return $labels;
84+
}
85+
86+
/**
87+
* TODO: get valid labels from the repository via GitHub API
88+
*/
89+
private function getValidLabels()
90+
{
91+
return array(
92+
'Asset', 'BC Break', 'BrowserKit', 'Bug', 'Cache', 'ClassLoader',
93+
'Config', 'Console', 'Critical', 'CssSelector', 'Debug', 'DebugBundle',
94+
'DependencyInjection', 'Deprecation', 'Doctrine', 'DoctrineBridge',
95+
'DomCrawler', 'Drupal related', 'DX', 'Easy Pick', 'Enhancement',
96+
'EventDispatcher', 'ExpressionLanguage', 'Feature', 'Filesystem',
97+
'Finder', 'Form', 'FrameworkBundle', 'HttpFoundation', 'HttpKernel',
98+
'Intl', 'Ldap', 'Locale', 'MonologBridge', 'OptionsResolver',
99+
'PhpUnitBridge', 'Process', 'PropertyAccess', 'PropertyInfo', 'Ready',
100+
'RFC', 'Routing', 'Security', 'SecurityBundle', 'Serializer',
101+
'Stopwatch', 'Templating', 'Translator', 'TwigBridge', 'TwigBundle',
102+
'Unconfirmed', 'Validator', 'VarDumper', 'WebProfilerBundle', 'Yaml',
103+
);
104+
}
105+
106+
public static function getSubscribedEvents()
107+
{
108+
return array(
109+
GitHubEvents::PULL_REQUEST => 'onPullRequest',
110+
);
111+
}
112+
}

0 commit comments

Comments
 (0)