2012-02-19 05:16:35 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Render some distracting statistics on revisions
|
|
|
|
*/
|
|
|
|
final class DifferentialRevisionStatsView extends AphrontView {
|
|
|
|
private $comments;
|
|
|
|
private $revisions;
|
2012-07-04 03:24:58 +02:00
|
|
|
private $diffs;
|
|
|
|
private $filter;
|
2012-02-19 05:16:35 +01:00
|
|
|
|
|
|
|
public function setRevisions(array $revisions) {
|
2012-04-04 22:13:08 +02:00
|
|
|
assert_instances_of($revisions, 'DifferentialRevision');
|
2012-02-19 05:16:35 +01:00
|
|
|
$this->revisions = $revisions;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setComments(array $comments) {
|
2012-04-04 22:13:08 +02:00
|
|
|
assert_instances_of($comments, 'DifferentialComment');
|
2012-02-19 05:16:35 +01:00
|
|
|
$this->comments = $comments;
|
|
|
|
return $this;
|
|
|
|
}
|
2012-04-04 22:13:08 +02:00
|
|
|
|
2012-07-04 03:24:58 +02:00
|
|
|
public function setDiffs(array $diffs) {
|
|
|
|
assert_instances_of($diffs, 'DifferentialDiff');
|
|
|
|
$this->diffs = $diffs;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setFilter($filter) {
|
|
|
|
$this->filter = $filter;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-02-19 05:16:35 +01:00
|
|
|
public function render() {
|
|
|
|
$user = $this->user;
|
|
|
|
if (!$user) {
|
|
|
|
throw new Exception("Call setUser() before render()!");
|
|
|
|
}
|
|
|
|
|
|
|
|
$id_to_revision_map = array();
|
|
|
|
foreach ($this->revisions as $rev) {
|
|
|
|
$id_to_revision_map[$rev->getID()] = $rev;
|
|
|
|
}
|
|
|
|
$revisions_seen = array();
|
|
|
|
|
|
|
|
$dates = array();
|
|
|
|
$counts = array();
|
|
|
|
$lines = array();
|
|
|
|
$days_with_diffs = array();
|
|
|
|
$count_active = array();
|
2012-07-04 03:24:58 +02:00
|
|
|
$response_time = array();
|
|
|
|
$response_count = array();
|
2012-02-19 05:16:35 +01:00
|
|
|
$now = time();
|
|
|
|
$row_array = array();
|
|
|
|
|
|
|
|
foreach (array(
|
|
|
|
'1 week', '2 weeks', '3 weeks',
|
|
|
|
'1 month', '2 months', '3 months', '6 months', '9 months',
|
|
|
|
'1 year', '18 months',
|
|
|
|
'2 years', '3 years', '4 years', '5 years',
|
|
|
|
) as $age) {
|
2012-06-26 23:56:45 +02:00
|
|
|
$dates[$age] = strtotime($age . ' ago 23:59:59');
|
2012-02-19 05:16:35 +01:00
|
|
|
$counts[$age] = 0;
|
|
|
|
$lines[$age] = 0;
|
|
|
|
$count_active[$age] = 0;
|
2012-07-04 03:24:58 +02:00
|
|
|
$response_time[$age] = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$revision_diffs_map = mgroup($this->diffs, 'getRevisionID');
|
|
|
|
foreach ($revision_diffs_map as $revision_id => $diffs) {
|
|
|
|
$revision_diffs_map[$revision_id] = msort($diffs, 'getID');
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($this->comments as $comment) {
|
2012-07-04 03:24:58 +02:00
|
|
|
$comment_date = $comment->getDateCreated();
|
2012-02-19 05:16:35 +01:00
|
|
|
|
2012-07-04 03:24:58 +02:00
|
|
|
$day = phabricator_date($comment_date, $user);
|
2012-02-19 05:16:35 +01:00
|
|
|
$old_daycount = idx($days_with_diffs, $day, 0);
|
|
|
|
$days_with_diffs[$day] = $old_daycount + 1;
|
|
|
|
|
|
|
|
$rev_id = $comment->getRevisionID();
|
|
|
|
|
|
|
|
if (idx($revisions_seen, $rev_id)) {
|
2012-07-04 03:24:58 +02:00
|
|
|
$revision_seen = true;
|
|
|
|
$rev = null;
|
|
|
|
} else {
|
|
|
|
$revision_seen = false;
|
|
|
|
$rev = $id_to_revision_map[$rev_id];
|
|
|
|
$revisions_seen[$rev_id] = true;
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($dates as $age => $cutoff) {
|
2012-07-04 03:24:58 +02:00
|
|
|
if ($cutoff >= $comment_date) {
|
2012-02-19 05:16:35 +01:00
|
|
|
continue;
|
|
|
|
}
|
2012-07-04 03:24:58 +02:00
|
|
|
|
|
|
|
if (!$revision_seen) {
|
|
|
|
if ($rev) {
|
|
|
|
$lines[$age] += $rev->getLineCount();
|
|
|
|
}
|
|
|
|
$counts[$age]++;
|
|
|
|
if (!$old_daycount) {
|
|
|
|
$count_active[$age]++;
|
|
|
|
}
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|
2012-07-04 03:24:58 +02:00
|
|
|
|
|
|
|
$diffs = $revision_diffs_map[$rev_id];
|
|
|
|
$target_diff = $this->findTargetDiff($diffs, $comment);
|
|
|
|
if ($target_diff) {
|
|
|
|
$response_time[$age][] =
|
|
|
|
$comment_date - $target_diff->getDateCreated();
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$old_count = 0;
|
2012-03-02 01:32:31 +01:00
|
|
|
foreach (array_reverse($dates) as $age => $cutoff) {
|
2012-06-27 01:20:41 +02:00
|
|
|
$weeks = ceil(($now - $cutoff) / (60 * 60 * 24)) / 7;
|
2012-03-02 01:32:31 +01:00
|
|
|
if ($old_count == $counts[$age] && count($row_array) == 1) {
|
2012-06-27 01:20:41 +02:00
|
|
|
unset($dates[last_key($row_array)]);
|
2012-03-02 01:32:31 +01:00
|
|
|
$row_array = array();
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|
|
|
|
$old_count = $counts[$age];
|
|
|
|
|
|
|
|
$row_array[$age] = array(
|
|
|
|
'Revisions per week' => number_format($counts[$age] / $weeks, 2),
|
|
|
|
'Lines per week' => number_format($lines[$age] / $weeks, 1),
|
|
|
|
'Active days per week' =>
|
|
|
|
number_format($count_active[$age] / $weeks, 1),
|
|
|
|
'Revisions' => number_format($counts[$age]),
|
|
|
|
'Lines' => number_format($lines[$age]),
|
|
|
|
'Lines per diff' => number_format($lines[$age] /
|
|
|
|
($counts[$age] + 0.0001)),
|
|
|
|
'Active days' => number_format($count_active[$age]),
|
|
|
|
);
|
2012-07-04 03:24:58 +02:00
|
|
|
|
|
|
|
switch ($this->filter) {
|
|
|
|
case DifferentialAction::ACTION_CLOSE:
|
|
|
|
case DifferentialAction::ACTION_UPDATE:
|
|
|
|
case DifferentialAction::ACTION_COMMENT:
|
|
|
|
break;
|
|
|
|
case DifferentialAction::ACTION_ACCEPT:
|
|
|
|
case DifferentialAction::ACTION_REJECT:
|
|
|
|
$count = count($response_time[$age]);
|
|
|
|
if ($count) {
|
|
|
|
rsort($response_time[$age]);
|
|
|
|
$median = $response_time[$age][round($count / 2) - 1];
|
|
|
|
$average = array_sum($response_time[$age]) / $count;
|
|
|
|
} else {
|
|
|
|
$median = 0;
|
|
|
|
$average = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
$row_array[$age]['Response hours (median|average)'] =
|
|
|
|
number_format($median / 3600, 1).
|
|
|
|
' | '.
|
|
|
|
number_format($average / 3600, 1);
|
|
|
|
break;
|
|
|
|
}
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$rows = array();
|
|
|
|
$row_names = array_keys(head($row_array));
|
|
|
|
foreach ($row_names as $row_name) {
|
|
|
|
$rows[] = array($row_name);
|
|
|
|
}
|
|
|
|
foreach (array_keys($dates) as $age) {
|
|
|
|
$i = 0;
|
|
|
|
foreach ($row_names as $row_name) {
|
|
|
|
$rows[$i][] = idx(idx($row_array, $age), $row_name, '-');
|
|
|
|
++$i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$table = new AphrontTableView($rows);
|
|
|
|
$table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
'wide pri',
|
|
|
|
));
|
|
|
|
|
|
|
|
$table->setHeaders(
|
|
|
|
array_merge(
|
|
|
|
array(
|
|
|
|
'Metric',
|
|
|
|
),
|
|
|
|
array_keys($dates)));
|
|
|
|
|
|
|
|
return $table->render();
|
|
|
|
}
|
2012-07-04 03:24:58 +02:00
|
|
|
|
|
|
|
private function findTargetDiff(array $diffs,
|
|
|
|
DifferentialComment $comment) {
|
|
|
|
switch ($this->filter) {
|
|
|
|
case DifferentialAction::ACTION_CLOSE:
|
|
|
|
case DifferentialAction::ACTION_UPDATE:
|
|
|
|
case DifferentialAction::ACTION_COMMENT:
|
|
|
|
return null;
|
|
|
|
case DifferentialAction::ACTION_ACCEPT:
|
|
|
|
case DifferentialAction::ACTION_REJECT:
|
|
|
|
$result = head($diffs);
|
|
|
|
foreach ($diffs as $diff) {
|
|
|
|
if ($diff->getDateCreated() >= $comment->getDateCreated()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
$result = $diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 05:16:35 +01:00
|
|
|
}
|