r69748 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r69747‎ | r69748 | r69749 >
Date:20:18, 22 July 2010
Author:maxsem
Status:resolved (Comments)
Tags:
Comment:
Statistics feature for CodeReview
Modified paths:
  • /trunk/extensions/CodeReview/CodeReview.i18n.php (modified) (history)
  • /trunk/extensions/CodeReview/CodeReview.php (modified) (history)
  • /trunk/extensions/CodeReview/backend/RepoStats.php (added) (history)
  • /trunk/extensions/CodeReview/ui/CodeRepoListView.php (modified) (history)
  • /trunk/extensions/CodeReview/ui/CodeRepoStatsView.php (added) (history)
  • /trunk/extensions/CodeReview/ui/SpecialCode.php (modified) (history)

Diff [purge]

Index: trunk/extensions/CodeReview/CodeReview.i18n.php
@@ -130,6 +130,13 @@
131131 Commit summary:
132132
133133 $4',
 134+
 135+ 'code-stats' => 'statistics',
 136+ 'code-stats-header' => 'Repository statistics for $1',
 137+ 'code-stats-main' => 'As of $1, the repository has $2 {{PLURAL:$2|revision|revisions}} by [[Special:Code/$3/author|$4 {{PLURAL:$4|author|authors}}]].',
 138+ 'code-stats-staus-breakdown' => 'Number of revisions per state',
 139+ 'code-stats-fixme-breakdown' => 'Breakdown of fixmes per author',
 140+ 'code-stats-count' => 'Number of revisions',
134141
135142 'repoadmin' => 'Repository Administration',
136143 'repoadmin-new-legend' => 'Create a new repository',
Index: trunk/extensions/CodeReview/CodeReview.php
@@ -52,8 +52,10 @@
5353 $wgAutoloadClasses['CodeCommentLinkerHtml'] = $dir . 'backend/CodeCommentLinker.php';
5454 $wgAutoloadClasses['CodeCommentLinkerWiki'] = $dir . 'backend/CodeCommentLinker.php';
5555 $wgAutoloadClasses['CodePropChange'] = $dir . 'backend/CodePropChange.php';
 56+$wgAutoloadClasses['RepoStats'] = $dir . 'backend/RepoStats.php';
5657
5758 $wgAutoloadClasses['CodeRepoListView'] = $dir . 'ui/CodeRepoListView.php';
 59+$wgAutoloadClasses['CodeRepoStatsView'] = $dir . 'ui/CodeRepoStatsView.php';
5860 $wgAutoloadClasses['CodeRevisionAuthorView'] = $dir . 'ui/CodeRevisionAuthorView.php';
5961 $wgAutoloadClasses['CodeRevisionAuthorLink'] = $dir . 'ui/CodeRevisionAuthorLink.php';
6062 $wgAutoloadClasses['CodeRevisionCommitter'] = $dir . 'ui/CodeRevisionCommitter.php';
Index: trunk/extensions/CodeReview/backend/RepoStats.php
@@ -0,0 +1,80 @@
 2+<?php
 3+
 4+class RepoStats {
 5+ private $repo;
 6+
 7+ public $time;
 8+
 9+ // Statistics
 10+ public $revisions,
 11+ $authors,
 12+ $states,
 13+ $fixmes;
 14+
 15+ public static function newFromRepo( CodeRepository $repo ) {
 16+ global $wgMemc;
 17+
 18+ $key = wfMemcKey( 'codereview1', 'stats', $repo->getName() );
 19+ $stats = $wgMemc->get( $key );
 20+ wfDebug( "{$repo->getName()} repo stats: cache " );
 21+ if ( $stats ) {
 22+ wfDebug( "hit\n" );
 23+ return $stats;
 24+ }
 25+ wfDebug( "miss\n" );
 26+ $stats = new RepoStats( $repo );
 27+ $stats->generate();
 28+ $wgMemc->set( $key, $stats, 12 * 60 * 60 ); // 12 hours
 29+ return $stats;
 30+ }
 31+
 32+ public function __construct( CodeRepository $repo ) {
 33+ $this->repo = $repo;
 34+ $this->time = wfTimestamp( TS_MW );
 35+ }
 36+
 37+ private function generate() {
 38+ wfProfileIn( __METHOD__ );
 39+ $dbr = wfGetDB( DB_SLAVE );
 40+
 41+ $this->revisions = $dbr->selectField( 'code_rev',
 42+ 'COUNT(*)',
 43+ array( 'cr_repo_id' => $this->repo->getId() ),
 44+ __METHOD__
 45+ );
 46+
 47+ $this->authors = $dbr->selectField( 'code_rev',
 48+ 'COUNT(DISTINCT cr_author)',
 49+ array( 'cr_repo_id' => $this->repo->getId() ),
 50+ __METHOD__
 51+ );
 52+
 53+ $this->states = array();
 54+ $res = $dbr->select( 'code_rev',
 55+ array( 'cr_status', 'COUNT(*) AS revs' ),
 56+ array( 'cr_repo_id' => $this->repo->getId() ),
 57+ __METHOD__,
 58+ array( 'GROUP BY' => 'cr_status' )
 59+ );
 60+ foreach ( $res as $row ) {
 61+ $this->states[$row->cr_status] = $row->revs;
 62+ }
 63+
 64+ $this->fixmes = array();
 65+ $res = $dbr->select( 'code_rev',
 66+ array( 'COUNT(*) AS revs', 'cr_author' ),
 67+ array( 'cr_repo_id' => $this->repo->getId(), 'cr_status' => 'fixme' ),
 68+ __METHOD__,
 69+ array(
 70+ 'GROUP BY' => 'cr_author',
 71+ 'ORDER BY' => 'revs DESC',
 72+ 'LIMIT' => 500,
 73+ )
 74+ );
 75+ foreach ( $res as $row ) {
 76+ $this->fixmes[$row->cr_author] = $row->revs;
 77+ }
 78+
 79+ wfProfileOut( __METHOD__ );
 80+ }
 81+}
\ No newline at end of file
Property changes on: trunk/extensions/CodeReview/backend/RepoStats.php
___________________________________________________________________
Added: svn:eol-style
182 + native
Index: trunk/extensions/CodeReview/ui/CodeRepoStatsView.php
@@ -0,0 +1,59 @@
 2+<?php
 3+
 4+// Special:Code/MediaWiki/stats
 5+class CodeRepoStatsView extends CodeView {
 6+
 7+ function __construct( $repoName ) {
 8+ parent::__construct();
 9+ $this->mRepo = CodeRepository::newFromName( $repoName );
 10+ }
 11+
 12+ function execute() {
 13+ global $wgOut, $wgLang, $wgSkin;
 14+
 15+ $stats = RepoStats::newFromRepo( $this->mRepo );
 16+ $repoName = $this->mRepo->getName();
 17+ $wgOut->wrapWikiMsg( '<h2 id="stats-main">$1</h2>', array( 'code-stats-header', $repoName ) );
 18+ $wgOut->addWikiMsg( 'code-stats-main',
 19+ $wgLang->timeanddate( $stats->time, true ),
 20+ $wgLang->formatNum( $stats->revisions ),
 21+ $repoName,
 22+ $wgLang->formatNum( $stats->authors )
 23+ );
 24+
 25+ if ( !empty( $stats->states ) ) {
 26+ $wgOut->wrapWikiMsg( '<h3 id="stats-revisions">$1</h3>', 'code-stats-staus-breakdown' );
 27+ $wgOut->addHTML( '<table class="TablePager">'
 28+ . '<tr><th>' . wfMsgHtml( 'code-field-status' ) . '</th><th>'
 29+ . wfMsgHtml( 'code-stats-count' ) . '</th></tr>' );
 30+ foreach ( CodeRevision::getPossibleStates() as $state ) {
 31+ $count = isset( $stats->states[$state] ) ? $stats->states[$state] : 0;
 32+ $count = htmlspecialchars( $wgLang->formatNum( $count ) );
 33+ $link = $this->mSkin->link(
 34+ SpecialPage::getTitleFor( 'Code', $repoName . '/status/' . $state ),
 35+ htmlspecialchars( $this->statusDesc( $state ) )
 36+ );
 37+ $wgOut->addHTML( "<tr class=\"mw-codereview-status-$state\"><td>$link</td>"
 38+ . "<td>$count</td></tr>" );
 39+ }
 40+ $wgOut->addHTML( '</table>' );
 41+ }
 42+
 43+ if ( !empty( $stats->fixmes ) ) {
 44+ $wgOut->wrapWikiMsg( '<h3 id="stats-fixme">$1</h3>', 'code-stats-fixme-breakdown' );
 45+ $wgOut->addHTML( '<table class="TablePager">'
 46+ . '<tr><th>' . wfMsgHtml( 'code-field-author' ) . '</th><th>'
 47+ . wfMsgHtml( 'code-stats-count' ) . '</th></tr>' );
 48+ foreach ( $stats->fixmes as $user => $count ) {
 49+ $count = htmlspecialchars( $wgLang->formatNum( $count ) );
 50+ $link = $this->mSkin->link(
 51+ SpecialPage::getTitleFor( 'Code', $repoName . '/author/' . $user ),
 52+ htmlspecialchars( $user )
 53+ );
 54+ $wgOut->addHTML( "<tr><td>$link</td>"
 55+ . "<td>$count</td></tr>" );
 56+ }
 57+ $wgOut->addHTML( '</table>' );
 58+ }
 59+ }
 60+}
\ No newline at end of file
Property changes on: trunk/extensions/CodeReview/ui/CodeRepoStatsView.php
___________________________________________________________________
Added: svn:eol-style
161 + native
Index: trunk/extensions/CodeReview/ui/SpecialCode.php
@@ -35,6 +35,9 @@
3636 } elseif ( $params[1] === 'author' ) {
3737 $view = new CodeAuthorListView( $params[0] );
3838 break;
 39+ } elseif ( $params[1] === 'stats' ) {
 40+ $view = new CodeRepoStatsView( $params[0] );
 41+ break;
3942 } elseif ( $params[1] === 'status' ) {
4043 $view = new CodeStatusListView( $params[0] );
4144 break;
Index: trunk/extensions/CodeReview/ui/CodeRepoListView.php
@@ -34,6 +34,7 @@
3535 $links[] = "[[Special:Code/$name/author|" . wfMsgHtml( 'code-authors' ) . "]]";
3636 $links[] = "[[Special:Code/$name/status|" . wfMsgHtml( 'code-status' ) . "]]";
3737 $links[] = "[[Special:Code/$name/releasenotes|" . wfMsgHtml( 'code-releasenotes' ) . "]]";
 38+ $links[] = "[[Special:Code/$name/stats|" . wfMsgHtml( 'code-stats' ) . "]]";
3839 $text .= $wgLang->pipeList( $links );
3940 $text .= ")";
4041 return $text;

Follow-up revisions

RevisionCommit summaryAuthorDate
r69828Follow-up to r69748: add optional separate time and date per CRmaxsem11:17, 24 July 2010
r74076Followup r69748, tweak wordingdemon16:05, 1 October 2010

Comments

#Comment by Nikerabbit (talk | contribs)   20:36, 22 July 2010
+$wgOut->addWikiMsg( 'code-stats-main',
+	$wgLang->timeanddate( $stats->time, true ),

Should provide time and date as distinct variables too.

+$wgOut->addHTML( '<table class="TablePager">'

I assume that this class is used elsewhere too, since it has unusual style?

+'code-stats-header' => 'Repository statistics for $1',

Does Statistics for repository $1 mean the same? It would be easier to translate.

+'code-stats-staus-breakdown' => 'Number of revisions per state',

Should perhaps clarify what is a state in this context. Either by amending this message and/or adding message documentation (language code qqq). Should we also talk about commits instead of revisions? I'm not sure which term would be the best.

The rest looks fine to me.

#Comment by MaxSem (talk | contribs)   11:41, 24 July 2010

Should provide time and date as distinct variables too.

Done in r69828.

I assume that this class is used elsewhere too, since it has unusual style?

Yup, was there before me.

Should we also talk about commits instead of revisions?

This extension seems to prefer to call 'em revisions.


I've created a couple of message descriptions on TWN.

#Comment by P858snake (talk | contribs)   11:49, 24 July 2010

I would go for revisions, because each one is a different revision of the file you are editing, a commit is adding the new version (or reverting) of that file on top of it.

#Comment by Reedy (talk | contribs)   08:45, 26 July 2010

I'm wondering if we should kill the states in favour of this...

The states gives no added information...

Status & tagging log