Project page
This commit is contained in:
@@ -8,6 +8,9 @@ use Interop\Container\ContainerInterface;
|
||||
use Maintained\Badge\BadgeGenerator;
|
||||
use Maintained\Badge\BadgeProvider;
|
||||
use Maintained\Badge\CachedBadgeProvider;
|
||||
use Maintained\Statistics\CachedStatisticsProvider;
|
||||
use Maintained\Statistics\StatisticsComputer;
|
||||
use Maintained\Statistics\StatisticsProvider;
|
||||
use PUGX\Poser\Poser;
|
||||
use PUGX\Poser\Render\SvgRender;
|
||||
use function DI\factory;
|
||||
@@ -39,8 +42,12 @@ return [
|
||||
}),
|
||||
|
||||
Cache::class => object(FilesystemCache::class)
|
||||
->constructor(__DIR__ . '/../../app/cache/badges'),
|
||||
->constructor(__DIR__ . '/../../app/cache/app')
|
||||
->method('setNamespace', 'Maintained'),
|
||||
|
||||
BadgeProvider::class => object(CachedBadgeProvider::class)
|
||||
->constructorParameter('wrapped', link(BadgeGenerator::class)),
|
||||
|
||||
StatisticsProvider::class => object(CachedStatisticsProvider::class)
|
||||
->constructorParameter('wrapped', link(StatisticsComputer::class)),
|
||||
];
|
||||
|
||||
@@ -2,13 +2,18 @@
|
||||
|
||||
use Maintained\Application\Controller\BadgeController;
|
||||
use Maintained\Application\Controller\HomeController;
|
||||
use Maintained\Application\Controller\ProjectController;
|
||||
|
||||
return [
|
||||
'home' => [
|
||||
'home' => [
|
||||
'pattern' => '/',
|
||||
'controller' => HomeController::class,
|
||||
],
|
||||
'badge' => [
|
||||
'project' => [
|
||||
'pattern' => '/project/{user}/{repository}',
|
||||
'controller' => ProjectController::class,
|
||||
],
|
||||
'badge' => [
|
||||
'pattern' => '/badge/{user}/{repository}.svg',
|
||||
'controller' => BadgeController::class,
|
||||
],
|
||||
|
||||
33
src/Maintained/Application/Controller/ProjectController.php
Normal file
33
src/Maintained/Application/Controller/ProjectController.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Maintained\Application\Controller;
|
||||
|
||||
use Maintained\Statistics\StatisticsProvider;
|
||||
|
||||
/**
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class ProjectController
|
||||
{
|
||||
/**
|
||||
* @Inject
|
||||
* @var \Twig_Environment
|
||||
*/
|
||||
private $twig;
|
||||
|
||||
/**
|
||||
* @Inject
|
||||
* @var StatisticsProvider
|
||||
*/
|
||||
private $statisticsProvider;
|
||||
|
||||
public function __invoke($user, $repository)
|
||||
{
|
||||
$statistics = $this->statisticsProvider->getStatistics($user, $repository);
|
||||
|
||||
echo $this->twig->render('project.twig', [
|
||||
'repository' => $user . '/' . $repository,
|
||||
'resolutionTime' => $statistics->resolutionTime,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -32,25 +32,27 @@
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#page-top">Is it maintained?</a>
|
||||
<a class="navbar-brand" href="/#page-top">Is it maintained?</a>
|
||||
</div>
|
||||
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="hidden">
|
||||
<a href="#page-top"></a>
|
||||
<a href="/#page-top"></a>
|
||||
</li>
|
||||
<li class="page-scroll">
|
||||
<a href="#check">Check a project</a>
|
||||
<a href="/#check">Check a project</a>
|
||||
</li>
|
||||
<li class="page-scroll">
|
||||
<a href="#metrics">Metrics</a>
|
||||
<a href="/#metrics">Metrics</a>
|
||||
</li>
|
||||
<li class="page-scroll">
|
||||
<a href="#about">About</a>
|
||||
<a href="/#about">About</a>
|
||||
</li>
|
||||
<li class="page-scroll">
|
||||
<a href="https://github.com/mnapoli/Maintained"><i class="fa fa-github"></i> GitHub</a>
|
||||
<li>
|
||||
<a href="https://github.com/mnapoli/Maintained">
|
||||
<i class="fa fa-github"></i> GitHub
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
28
src/Maintained/Application/View/project.twig
Normal file
28
src/Maintained/Application/View/project.twig
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends 'layout.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center">
|
||||
<h2>{{ repository }}</h2>
|
||||
<hr class="star-primary">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-lg-offset-2 text-center">
|
||||
|
||||
<p>
|
||||
Resolution time: <strong>{{ resolutionTime.formatLong() }}</strong>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
@@ -11,7 +11,7 @@ use Doctrine\Common\Cache\Cache;
|
||||
*/
|
||||
class CachedBadgeProvider implements BadgeProvider
|
||||
{
|
||||
const CACHE_NAMESPACE = 'maintained/';
|
||||
const CACHE_NAMESPACE = 'badge/';
|
||||
|
||||
/**
|
||||
* @var Cache
|
||||
|
||||
@@ -55,7 +55,7 @@ class Diagnostic
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
* @return TimeInterval
|
||||
*/
|
||||
public function computeAverage()
|
||||
{
|
||||
@@ -67,6 +67,9 @@ class Diagnostic
|
||||
return new TimeInterval($average);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TimeInterval
|
||||
*/
|
||||
public function computeMedian()
|
||||
{
|
||||
$durations = array_map(function (Issue $issue) {
|
||||
|
||||
46
src/Maintained/Statistics/CachedStatisticsProvider.php
Normal file
46
src/Maintained/Statistics/CachedStatisticsProvider.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Maintained\Statistics;
|
||||
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
|
||||
/**
|
||||
* Wraps and caches another provider.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class CachedStatisticsProvider implements StatisticsProvider
|
||||
{
|
||||
const CACHE_NAMESPACE = 'statistics/';
|
||||
|
||||
/**
|
||||
* @var Cache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @var StatisticsProvider
|
||||
*/
|
||||
private $wrapped;
|
||||
|
||||
public function __construct(Cache $cache, StatisticsProvider $wrapped)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->wrapped = $wrapped;
|
||||
}
|
||||
|
||||
public function getStatistics($user, $repository)
|
||||
{
|
||||
$key = self::CACHE_NAMESPACE . $user . '/' . $repository;
|
||||
|
||||
$statistics = $this->cache->fetch($key);
|
||||
|
||||
if ($statistics === false) {
|
||||
$statistics = $this->wrapped->getStatistics($user, $repository);
|
||||
|
||||
$this->cache->save($key, $statistics);
|
||||
}
|
||||
|
||||
return $statistics;
|
||||
}
|
||||
}
|
||||
18
src/Maintained/Statistics/Statistics.php
Normal file
18
src/Maintained/Statistics/Statistics.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Maintained\Statistics;
|
||||
|
||||
use Maintained\TimeInterval;
|
||||
|
||||
/**
|
||||
* Statistics of an open source project.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class Statistics
|
||||
{
|
||||
/**
|
||||
* @var TimeInterval
|
||||
*/
|
||||
public $resolutionTime;
|
||||
}
|
||||
23
src/Maintained/Statistics/StatisticsComputer.php
Normal file
23
src/Maintained/Statistics/StatisticsComputer.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Maintained\Statistics;
|
||||
|
||||
use Maintained\Diagnostic;
|
||||
|
||||
/**
|
||||
* Computes statistics.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
class StatisticsComputer implements StatisticsProvider
|
||||
{
|
||||
public function getStatistics($user, $repository)
|
||||
{
|
||||
$diagnostic = new Diagnostic($user . '/' . $repository);
|
||||
|
||||
$statistics = new Statistics();
|
||||
$statistics->resolutionTime = $diagnostic->computeMedian();
|
||||
|
||||
return $statistics;
|
||||
}
|
||||
}
|
||||
18
src/Maintained/Statistics/StatisticsProvider.php
Normal file
18
src/Maintained/Statistics/StatisticsProvider.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Maintained\Statistics;
|
||||
|
||||
/**
|
||||
* Provides statistics.
|
||||
*
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
*/
|
||||
interface StatisticsProvider
|
||||
{
|
||||
/**
|
||||
* @param string $user
|
||||
* @param string $repository
|
||||
* @return Statistics
|
||||
*/
|
||||
public function getStatistics($user, $repository);
|
||||
}
|
||||
@@ -54,6 +54,25 @@ class TimeInterval
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format to a long display string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function formatLong()
|
||||
{
|
||||
switch (true) {
|
||||
case $this->seconds < self::TO_MINUTE:
|
||||
return sprintf('%d second(s)', $this->seconds);
|
||||
case $this->seconds < self::TO_HOUR:
|
||||
return sprintf('%d minute(s)', $this->toMinutes());
|
||||
case $this->seconds < self::TO_DAY:
|
||||
return sprintf('%d hour(s)', $this->toHours());
|
||||
default:
|
||||
return sprintf('%d day(s)', $this->toDays());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
|
||||
@@ -27,6 +27,7 @@ body {
|
||||
line-height: 1.42857143;
|
||||
color: #2c3e50;
|
||||
background-color: #ffffff;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -107,7 +108,7 @@ header {
|
||||
}
|
||||
|
||||
header .container {
|
||||
padding-top: 100px;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
@@ -130,8 +131,10 @@ header .intro-text .skills {
|
||||
}
|
||||
|
||||
@media(min-width:768px) {
|
||||
body {
|
||||
padding-top: 100px;
|
||||
}
|
||||
header .container {
|
||||
padding-top: 140px;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user