1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 05:50:55 +01:00

Load reviewer stats

Summary:
This allows getting stats for any arbitrary period, e.g.

- everything
- last week
- week before last week

Test Plan: Ran the script for last week.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Differential Revision: https://secure.phabricator.com/D3064
This commit is contained in:
vrana 2012-07-24 23:50:25 -07:00
parent 28618b345e
commit 1fc2dfd54b
2 changed files with 124 additions and 24 deletions

View file

@ -18,18 +18,21 @@
final class DifferentialReviewerStats { final class DifferentialReviewerStats {
private $since = 0; private $since = 0;
private $now; private $until;
public function setSince($value) { public function setSince($value) {
$this->since = $value; $this->since = $value;
return $this; return $this;
} }
public function setNow($value) { public function setUntil($value) {
$this->now = $value; $this->until = $value;
return $this; return $this;
} }
/**
* @return array($reviewed, $not_reviewed)
*/
public function computeTimes( public function computeTimes(
DifferentialRevision $revision, DifferentialRevision $revision,
array $comments) { array $comments) {
@ -103,7 +106,7 @@ final class DifferentialReviewerStats {
} }
} }
// TODO: Respect workdays. // TODO: Respect workdays and status away.
if ($old_status != $status) { if ($old_status != $status) {
if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) { if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
@ -123,10 +126,10 @@ final class DifferentialReviewerStats {
} }
if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) { if ($status == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) {
$now = ($this->now !== null ? $this->now : time()); $date = ($this->until !== null ? $this->until : time());
if ($now >= $this->since) { if ($date >= $this->since) {
foreach ($reviewers as $phid => $start) { foreach ($reviewers as $phid => $start) {
$not_reviewed[$phid][] = $now - $start; $not_reviewed[$phid][] = $date - $start;
} }
} }
} }
@ -134,4 +137,106 @@ final class DifferentialReviewerStats {
return array($reviewed, $not_reviewed); return array($reviewed, $not_reviewed);
} }
public function loadAvgs() {
$limit = 1000;
$conn_r = id(new DifferentialRevision())->establishConnection('r');
$sums = array();
$counts = array();
$all_not_reviewed = array();
$last_id = 0;
do {
$where = '';
if ($this->until !== null) {
$where .= qsprintf(
$conn_r,
' AND dateCreated < %d',
$this->until);
}
if ($this->since) {
$where .= qsprintf(
$conn_r,
' AND (dateModified > %d OR status = %s)',
$this->since,
ArcanistDifferentialRevisionStatus::NEEDS_REVIEW);
}
$revisions = id(new DifferentialRevision())->loadAllWhere(
'id > %d%Q ORDER BY id LIMIT %d',
$last_id,
$where,
$limit);
if (!$revisions) {
break;
}
$last_id = last_key($revisions);
$relations = queryfx_all(
$conn_r,
'SELECT * FROM %T WHERE revisionID IN (%Ld) AND relation = %s',
DifferentialRevision::RELATIONSHIP_TABLE,
array_keys($revisions),
DifferentialRevision::RELATION_REVIEWER);
$relations = igroup($relations, 'revisionID');
$where = '';
if ($this->until !== null) {
$where = qsprintf(
$conn_r,
' AND dateCreated < %d',
$this->until);
}
$all_comments = id(new DifferentialComment())->loadAllWhere(
'revisionID IN (%Ld)%Q ORDER BY revisionID, id',
array_keys($revisions),
$where);
$all_comments = mgroup($all_comments, 'getRevisionID');
foreach ($revisions as $id => $revision) {
$revision->attachRelationships(idx($relations, $id, array()));
$comments = idx($all_comments, $id, array());
list($reviewed, $not_reviewed) =
$this->computeTimes($revision, $comments);
foreach ($reviewed as $phid => $times) {
$sums[$phid] = idx($sums, $phid, 0) + array_sum($times);
$counts[$phid] = idx($counts, $phid, 0) + count($times);
}
foreach ($not_reviewed as $phid => $times) {
$all_not_reviewed[$phid][] = $times;
}
}
} while (count($revisions) >= $limit);
foreach ($all_not_reviewed as $phid => $not_reviewed) {
if (!array_key_exists($phid, $counts)) {
// If the person didn't make any reviews than take maximum time because
// he is at least that slow.
$sums[$phid] = max(array_map('max', $not_reviewed));
$counts[$phid] = 1;
continue;
}
$avg = $sums[$phid] / $counts[$phid];
foreach ($not_reviewed as $times) {
foreach ($times as $time) {
// Don't shorten the average time just because the reviewer was lucky
// to be in a group with someone faster.
if ($time > $avg) {
$sums[$phid] += $time;
$counts[$phid]++;
}
}
}
}
$avgs = array();
foreach ($sums as $phid => $sum) {
$avgs[$phid] = $sum / $counts[$phid];
}
return $avgs;
}
} }

View file

@ -19,13 +19,11 @@
final class DifferentialReviewerStatsTestCase extends PhabricatorTestCase { final class DifferentialReviewerStatsTestCase extends PhabricatorTestCase {
public function testReviewerStats() { public function testReviewerStats() {
$revw = DifferentialRevision::RELATION_REVIEWER;
$revision = new DifferentialRevision(); $revision = new DifferentialRevision();
$revision->setDateCreated(1); $revision->setDateCreated(1);
$revision->attachRelationships(array( $revision->attachRelationships(array(
array('relation' => $revw, 'objectPHID' => 'R1'), $this->newReviewer('R1'),
array('relation' => $revw, 'objectPHID' => 'R3'), $this->newReviewer('R3'),
)); ));
$comments = array( $comments = array(
@ -69,12 +67,7 @@ final class DifferentialReviewerStatsTestCase extends PhabricatorTestCase {
public function testReviewerStatsSince() { public function testReviewerStatsSince() {
$revision = new DifferentialRevision(); $revision = new DifferentialRevision();
$revision->setDateCreated(1); $revision->setDateCreated(1);
$revision->attachRelationships(array( $revision->attachRelationships(array($this->newReviewer('R')));
array(
'relation' => DifferentialRevision::RELATION_REVIEWER,
'objectPHID' => 'R',
),
));
$comments = array( $comments = array(
$this->newComment(2, 'R', DifferentialAction::ACTION_REJECT), $this->newComment(2, 'R', DifferentialAction::ACTION_REJECT),
@ -93,23 +86,25 @@ final class DifferentialReviewerStatsTestCase extends PhabricatorTestCase {
public function testReviewerStatsRequiresReview() { public function testReviewerStatsRequiresReview() {
$revision = new DifferentialRevision(); $revision = new DifferentialRevision();
$revision->setDateCreated(1); $revision->setDateCreated(1);
$revision->attachRelationships(array( $revision->attachRelationships(array($this->newReviewer('R')));
array(
'relation' => DifferentialRevision::RELATION_REVIEWER,
'objectPHID' => 'R',
),
));
$comments = array(); $comments = array();
$stats = new DifferentialReviewerStats(); $stats = new DifferentialReviewerStats();
$stats->setNow(2); $stats->setUntil(2);
list($reviewed, $not_reviewed) = $stats->computeTimes($revision, $comments); list($reviewed, $not_reviewed) = $stats->computeTimes($revision, $comments);
$this->assertEqual(array(), $reviewed); $this->assertEqual(array(), $reviewed);
$this->assertEqual(array('R' => array(2 - 1)), $not_reviewed); $this->assertEqual(array('R' => array(2 - 1)), $not_reviewed);
} }
private function newReviewer($phid) {
return array(
'relation' => DifferentialRevision::RELATION_REVIEWER,
'objectPHID' => $phid,
);
}
private function newComment($date, $author, $action, $metadata = array()) { private function newComment($date, $author, $action, $metadata = array()) {
return id(new DifferentialComment()) return id(new DifferentialComment())
->setDateCreated($date) ->setDateCreated($date)