diff --git a/app/config/routes.php b/app/config/routes.php
index 6a58a01..189d66f 100644
--- a/app/config/routes.php
+++ b/app/config/routes.php
@@ -14,7 +14,7 @@ return [
'controller' => ProjectController::class,
],
'badge' => [
- 'pattern' => '/badge/{user}/{repository}.svg',
+ 'pattern' => '/badge/{badge}/{user}/{repository}.svg',
'controller' => BadgeController::class,
],
];
diff --git a/src/Maintained/Application/Controller/BadgeController.php b/src/Maintained/Application/Controller/BadgeController.php
index 18f96fd..ea246b3 100644
--- a/src/Maintained/Application/Controller/BadgeController.php
+++ b/src/Maintained/Application/Controller/BadgeController.php
@@ -4,7 +4,9 @@ namespace Maintained\Application\Controller;
use DI\Annotation\Inject;
use Github\Exception\ApiLimitExceedException;
+use Maintained\Statistics\Statistics;
use Maintained\Statistics\StatisticsProvider;
+use PUGX\Poser\Image;
use PUGX\Poser\Poser;
/**
@@ -12,6 +14,9 @@ use PUGX\Poser\Poser;
*/
class BadgeController
{
+ const BADGE_RESOLUTION = 'resolution';
+ const BADGE_OPEN_RATIO = 'opened';
+
const COLOR_OK = '18bc9c';
const COLOR_WARNING = 'CC9237';
const COLOR_DANGER = '9C3838';
@@ -28,22 +33,20 @@ class BadgeController
*/
private $poser;
- public function __invoke($user, $repository)
+ public function __invoke($badge, $user, $repository)
{
try {
$statistics = $this->statisticsProvider->getStatistics($user, $repository);
- $days = $statistics->resolutionTime->toDays();
-
- if ($days < 2) {
- $color = self::COLOR_OK;
- } elseif ($days < 8) {
- $color = self::COLOR_WARNING;
- } else {
- $color = self::COLOR_DANGER;
+ switch ($badge) {
+ case self::BADGE_OPEN_RATIO:
+ $badge = $this->createOpenRatioBadge($statistics);
+ break;
+ case self::BADGE_RESOLUTION:
+ default:
+ $badge = $this->createResolutionBadge($statistics);
+ break;
}
-
- $badge = $this->poser->generate('resolution', $statistics->resolutionTime, $color, 'svg');
} catch (ApiLimitExceedException $e) {
$badge = $this->poser->generate('github-api', 'limit', self::COLOR_DANGER, 'svg');
}
@@ -51,4 +54,42 @@ class BadgeController
header('Content-type: image/svg+xml');
echo $badge;
}
+
+ /**
+ * @param Statistics $statistics
+ * @return Image
+ */
+ private function createResolutionBadge(Statistics $statistics)
+ {
+ $days = $statistics->resolutionTime->toDays();
+
+ if ($days < 2) {
+ $color = self::COLOR_OK;
+ } elseif ($days < 8) {
+ $color = self::COLOR_WARNING;
+ } else {
+ $color = self::COLOR_DANGER;
+ }
+
+ return $this->poser->generate('resolution', $statistics->resolutionTime->formatShort(), $color, 'svg');
+ }
+
+ /**
+ * @param Statistics $statistics
+ * @return Image
+ */
+ private function createOpenRatioBadge(Statistics $statistics)
+ {
+ $ratio = $statistics->openIssuesRatio;
+
+ if ($ratio < 0.1) {
+ $color = self::COLOR_OK;
+ } elseif ($ratio < 0.2) {
+ $color = self::COLOR_WARNING;
+ } else {
+ $color = self::COLOR_DANGER;
+ }
+
+ return $this->poser->generate('opened issues', round($ratio * 100) . '%', $color, 'svg');
+ }
}
diff --git a/src/Maintained/Application/Controller/HomeController.php b/src/Maintained/Application/Controller/HomeController.php
index 0640314..167c8fd 100644
--- a/src/Maintained/Application/Controller/HomeController.php
+++ b/src/Maintained/Application/Controller/HomeController.php
@@ -2,13 +2,29 @@
namespace Maintained\Application\Controller;
+use Twig_Environment;
+
/**
* @author Matthieu Napoli
- Median time needed to close an issue.
+ Median time needed to close an issue or pull request.
+
+ Issues or PR opened by the collaborators are ignored.
- Percentage of closed issues.
+ Percentage of closed issues and pull requests.
+
+ Issues or PR opened by the collaborators are ignored.
-
- Symfony
-
-
-
- ProxyManager
-
-
-
- PHPExcel
-
-
-
- Composer
-
-
-
- Behat
-
-
-
- Assetic
-
-
-
- PHPUnit
-
-
+
+ {{ name }}
+
+
+ {{ badge(repository, 'resolution') }}
+
+ {{ badge(repository, 'opened') }}
+
+
HTML;
}
}
diff --git a/src/Maintained/Application/View/home.twig b/src/Maintained/Application/View/home.twig
index b6188ee..da45d3c 100644
--- a/src/Maintained/Application/View/home.twig
+++ b/src/Maintained/Application/View/home.twig
@@ -66,13 +66,19 @@
Resolution time
Closed percentage
- The resolution time is the median time an issue stays open. + The resolution time is the median time an issue or pull request stays open. +
++ Issues or PR opened by the collaborators are ignored. +
+ ++ Open issues: + {{ openedIssues }}% +
++ {{ badge(repository, 'opened') }} +
++ The percentage of open issues and pull requests. +
++ Issues or PR opened by the collaborators are ignored.
diff --git a/src/Maintained/Issue.php b/src/Maintained/Issue.php index 8431fa9..9bdcfbe 100644 --- a/src/Maintained/Issue.php +++ b/src/Maintained/Issue.php @@ -78,4 +78,12 @@ class Issue { return $this->openedFor; } + + /** + * @return bool + */ + public function isOpen() + { + return $this->open; + } } diff --git a/src/Maintained/Statistics/Statistics.php b/src/Maintained/Statistics/Statistics.php index 5446cc6..3bec3b4 100644 --- a/src/Maintained/Statistics/Statistics.php +++ b/src/Maintained/Statistics/Statistics.php @@ -12,7 +12,16 @@ use Maintained\TimeInterval; class Statistics { /** + * Average time for closing an issue. + * * @var TimeInterval */ public $resolutionTime; + + /** + * Ratio of open issues. + * + * @var float + */ + public $openIssuesRatio; } diff --git a/src/Maintained/Statistics/StatisticsComputer.php b/src/Maintained/Statistics/StatisticsComputer.php index 49b96f1..5e15464 100644 --- a/src/Maintained/Statistics/StatisticsComputer.php +++ b/src/Maintained/Statistics/StatisticsComputer.php @@ -27,10 +27,12 @@ class StatisticsComputer implements StatisticsProvider { $issues = $this->fetchIssues($user, $repository); $collaborators = $this->fetchCollaborators($user, $repository); + $issues = $this->excludeIssuesCreatedByCollaborators($issues, $collaborators); $statistics = new Statistics(); $statistics->resolutionTime = $this->computeResolutionTime($issues); + $statistics->openIssuesRatio = $this->computeOpenIssueRatio($issues); return $statistics; } @@ -48,6 +50,27 @@ class StatisticsComputer implements StatisticsProvider return new TimeInterval($this->median($durations)); } + /** + * @param Issue[] $issues + * @return float + */ + private function computeOpenIssueRatio(array $issues) + { + if (empty($issues)) { + return 0; + } + + $openIssues = 0; + + foreach ($issues as $issue) { + if ($issue->isOpen()) { + $openIssues++; + } + } + + return $openIssues / count($issues); + } + /** * @param Issue[] $issues * @param string[] $collaborators