Index: trunk/extensions/CodeReview/CodeReview.i18n.php |
— | — | @@ -130,6 +130,13 @@ |
131 | 131 | Commit summary: |
132 | 132 | |
133 | 133 | $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', |
134 | 141 | |
135 | 142 | 'repoadmin' => 'Repository Administration', |
136 | 143 | 'repoadmin-new-legend' => 'Create a new repository', |
Index: trunk/extensions/CodeReview/CodeReview.php |
— | — | @@ -52,8 +52,10 @@ |
53 | 53 | $wgAutoloadClasses['CodeCommentLinkerHtml'] = $dir . 'backend/CodeCommentLinker.php'; |
54 | 54 | $wgAutoloadClasses['CodeCommentLinkerWiki'] = $dir . 'backend/CodeCommentLinker.php'; |
55 | 55 | $wgAutoloadClasses['CodePropChange'] = $dir . 'backend/CodePropChange.php'; |
| 56 | +$wgAutoloadClasses['RepoStats'] = $dir . 'backend/RepoStats.php'; |
56 | 57 | |
57 | 58 | $wgAutoloadClasses['CodeRepoListView'] = $dir . 'ui/CodeRepoListView.php'; |
| 59 | +$wgAutoloadClasses['CodeRepoStatsView'] = $dir . 'ui/CodeRepoStatsView.php'; |
58 | 60 | $wgAutoloadClasses['CodeRevisionAuthorView'] = $dir . 'ui/CodeRevisionAuthorView.php'; |
59 | 61 | $wgAutoloadClasses['CodeRevisionAuthorLink'] = $dir . 'ui/CodeRevisionAuthorLink.php'; |
60 | 62 | $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 |
1 | 82 | + 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 |
1 | 61 | + native |
Index: trunk/extensions/CodeReview/ui/SpecialCode.php |
— | — | @@ -35,6 +35,9 @@ |
36 | 36 | } elseif ( $params[1] === 'author' ) { |
37 | 37 | $view = new CodeAuthorListView( $params[0] ); |
38 | 38 | break; |
| 39 | + } elseif ( $params[1] === 'stats' ) { |
| 40 | + $view = new CodeRepoStatsView( $params[0] ); |
| 41 | + break; |
39 | 42 | } elseif ( $params[1] === 'status' ) { |
40 | 43 | $view = new CodeStatusListView( $params[0] ); |
41 | 44 | break; |
Index: trunk/extensions/CodeReview/ui/CodeRepoListView.php |
— | — | @@ -34,6 +34,7 @@ |
35 | 35 | $links[] = "[[Special:Code/$name/author|" . wfMsgHtml( 'code-authors' ) . "]]"; |
36 | 36 | $links[] = "[[Special:Code/$name/status|" . wfMsgHtml( 'code-status' ) . "]]"; |
37 | 37 | $links[] = "[[Special:Code/$name/releasenotes|" . wfMsgHtml( 'code-releasenotes' ) . "]]"; |
| 38 | + $links[] = "[[Special:Code/$name/stats|" . wfMsgHtml( 'code-stats' ) . "]]"; |
38 | 39 | $text .= $wgLang->pipeList( $links ); |
39 | 40 | $text .= ")"; |
40 | 41 | return $text; |