Skip to content

Commit

Permalink
Merge pull request #22 from DASPRiD/feature/pr-url-resolver
Browse files Browse the repository at this point in the history
Check github URLs for existing pull request links
  • Loading branch information
weierophinney committed Apr 26, 2018
2 parents d214f97 + 729f57c commit 7e56bfe
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 5 deletions.
82 changes: 80 additions & 2 deletions src/EntryCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,94 @@ private function prepareEntry(InputInterface $input) : string

private function preparePullRequestLink(int $pr, ?string $package) : string
{
$package = $package ?: (new ComposerPackage())->getName(realpath(getcwd()));
if (null !== $package) {
$link = $this->generatePullRequestLink($pr, $package);

if (null !== $link) {
return $link;
}

throw Exception\InvalidPullRequestLinkException::forPackage($package, $pr);
}

$link = $this->generatePullRequestLink($pr, (new ComposerPackage())->getName(realpath(getcwd())));

if (null !== $link) {
return $link;
}

foreach ($this->getGithubPackageNames() as $package) {
$link = $this->generatePullRequestLink($pr, $package);

if (null !== $link) {
return $link;
}
}

throw Exception\InvalidPullRequestLinkException::noValidLinks($pr);
}

private function getGithubPackageNames() : array
{
exec('git remote', $remotes, $return);

if (0 !== $return) {
return [];
}

$packages = [];

foreach ($remotes as $remote) {
$url = [];
exec(sprintf('git remote get-url %s', escapeshellarg($remote)), $url, $return);

if (0 !== $return) {
continue;
}

if (0 === preg_match('(github.com[:/](.*?)\.git)', $url[0], $matches)) {
continue;
}

$packages[] = $matches[1];
}

return $packages;
}

private function generatePullRequestLink(int $pr, string $package) : ?string
{
if (! preg_match('#^[a-z0-9]+[a-z0-9_-]*/[a-z0-9]+[a-z0-9_-]*$#i', $package)) {
throw Exception\InvalidPackageNameException::forPackage($package);
}

return sprintf(
$link = sprintf(
'https://github.com/%s/pull/%d',
$package,
$pr
);

if (! $this->probeLink($link)) {
return null;
}

return $link;
}

private function probeLink(string $link) : bool
{
$headers = get_headers($link, 1, stream_context_create(['http' => ['method' => 'HEAD']]));
$statusLine = explode(' ', $headers[0]);
$statusCode = (int) $statusLine[1];

if ($statusCode < 300) {
return true;
}

if ($statusCode >= 300 && $statusCode <= 399 && array_key_exists('Location', $headers)) {
return $this->probeLink($headers['Location']);
}

return false;
}
}
23 changes: 23 additions & 0 deletions src/Exception/InvalidPullRequestException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
/**
* @see https://github.com/phly/keep-a-changelog-tagger for the canonical source repository
* @copyright Copyright (c) 2018 Matthew Weier O'Phinney
* @license https://github.com/phly/keep-a-changelog-tagger/blob/master/LICENSE.md New BSD License
*/

declare(strict_types=1);

namespace Phly\KeepAChangelog\Exception;

use RuntimeException;

class InvalidPullRequestException extends RuntimeException
{
public static function for(int $pr) : self
{
return new self(sprintf(
'PR %d is not valid',
$pr
));
}
}
32 changes: 32 additions & 0 deletions src/Exception/InvalidPullRequestLinkException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
/**
* @see https://github.com/phly/keep-a-changelog-tagger for the canonical source repository
* @copyright Copyright (c) 2018 Matthew Weier O'Phinney
* @license https://github.com/phly/keep-a-changelog-tagger/blob/master/LICENSE.md New BSD License
*/

declare(strict_types=1);

namespace Phly\KeepAChangelog\Exception;

use RuntimeException;

class InvalidPullRequestLinkException extends RuntimeException
{
public static function forPackage(string $package, int $pr) : self
{
return new self(sprintf(
'The pull request package %s has no PR %d',
$package,
$pr
));
}

public static function noValidLinks(int $pr) : self
{
return new self(sprintf(
'No valid pull request link could be found for PR %d',
$pr
));
}
}
22 changes: 19 additions & 3 deletions test/EntryCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function testPrepareEntryReturnsEntryVerbatimIfNoPrOptionProvided()
public function testPrepareEntryWithPrOptionRaisesExceptionIfPackageOptionIsInvalid()
{
$entry = 'This is the entry';
$pr = 42;
$pr = 1;
$package = 'not-a-valid-package-name';

$this->input->getArgument('entry')->willReturn($entry);
Expand All @@ -99,10 +99,26 @@ public function testPrepareEntryWithPrOptionRaisesExceptionIfPackageOptionIsInva
$this->reflectMethod($command, 'prepareEntry')->invoke($command, $this->input->reveal());
}

public function testPrepareEntryWithPrOptionRaisesExceptionIfLinkIsInvalid()
{
$entry = 'This is the entry';
$pr = 9999999999;
$package = 'phly/keep-a-changelog';

$this->input->getArgument('entry')->willReturn($entry);
$this->input->getOption('pr')->willReturn($pr);
$this->input->getOption('package')->willReturn($package);

$command = new EntryCommand('entry:added');

$this->expectException(Exception\InvalidPullRequestLinkException::class);
$this->reflectMethod($command, 'prepareEntry')->invoke($command, $this->input->reveal());
}

public function testPrepareEntryReturnsEntryWithPrLinkPrefixedWhenPackageOptionPresentAndValid()
{
$entry = 'This is the entry';
$pr = 42;
$pr = 1;
$package = 'phly/keep-a-changelog';

$this->input->getArgument('entry')->willReturn($entry);
Expand All @@ -111,7 +127,7 @@ public function testPrepareEntryReturnsEntryWithPrLinkPrefixedWhenPackageOptionP

$command = new EntryCommand('entry:added');

$expected = '[#42](https://github.com/phly/keep-a-changelog/pull/42) ' . $entry;
$expected = '[#1](https://github.com/phly/keep-a-changelog/pull/1) ' . $entry;

$this->assertSame(
$expected,
Expand Down

0 comments on commit 7e56bfe

Please sign in to comment.