Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
RepoStats
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 7
272
0.00% covered (danger)
0.00%
0 / 1
 newFromRepo
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 generate
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
42
 getAuthorStatusCounts
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 getPathFixmes
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getPathNews
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStatusPath
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Extension\CodeReview\Backend;
4
5use MediaWiki\MediaWikiServices;
6
7class RepoStats {
8
9    /**
10     * @var CodeRepository
11     */
12    private $repo;
13
14    public $time;
15
16    public $revisions;
17
18    public $authors;
19
20    public $states;
21
22    public $fixmes;
23
24    public $new;
25
26    public $fixmesPerPath;
27
28    public $newPerPath;
29
30    /** @var string[] */
31    private static $cacheFields = [
32        'time',
33        'revisions',
34        'authors',
35        'states',
36        'fixmes',
37        'new',
38        'fixmesPerPath',
39        'newPerPath'
40    ];
41
42    /**
43     * @param CodeRepository $repo
44     * @return RepoStats
45     */
46    public static function newFromRepo( CodeRepository $repo ) {
47        global $wgCodeReviewRepoStatsCacheTime;
48
49        $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
50
51        $data = $cache->getWithSetCallback(
52            $cache->makeKey( 'codereview-stats', $repo->getName() ),
53            $wgCodeReviewRepoStatsCacheTime,
54            static function () use ( $repo ) {
55                $freshStats = new RepoStats( $repo );
56                $freshStats->generate();
57
58                $map = [];
59                foreach ( self::$cacheFields as $field ) {
60                    $map[$field] = $freshStats->$field;
61                }
62
63                return $map;
64            }
65        );
66
67        $stats = new RepoStats( $repo );
68        foreach ( self::$cacheFields as $field ) {
69            $stats->$field = $data[$field];
70        }
71
72        return $stats;
73    }
74
75    /**
76     * @param CodeRepository $repo
77     */
78    public function __construct( CodeRepository $repo ) {
79        $this->repo = $repo;
80        $this->time = wfTimestamp( TS_MW );
81    }
82
83    private function generate() {
84        $dbr = wfGetDB( DB_REPLICA );
85
86        $this->revisions = $dbr->selectField( 'code_rev',
87            'COUNT(*)',
88            [ 'cr_repo_id' => $this->repo->getId() ],
89            __METHOD__
90        );
91
92        $this->authors = $dbr->selectField( 'code_rev',
93            'COUNT(DISTINCT cr_author)',
94            [ 'cr_repo_id' => $this->repo->getId() ],
95            __METHOD__
96        );
97
98        $this->states = [];
99        $res = $dbr->select( 'code_rev',
100            [ 'cr_status', 'COUNT(*) AS revs' ],
101            [ 'cr_repo_id' => $this->repo->getId() ],
102            __METHOD__,
103            [ 'GROUP BY' => 'cr_status' ]
104        );
105        foreach ( $res as $row ) {
106            $this->states[$row->cr_status] = $row->revs;
107        }
108
109        $repoName = $this->repo->getName();
110
111        $this->fixmes = $this->getAuthorStatusCounts( 'fixme' );
112        $this->new = $this->getAuthorStatusCounts( 'new' );
113
114        $this->fixmesPerPath = [];
115        global $wgCodeReviewFixmePerPath;
116        if ( isset( $wgCodeReviewFixmePerPath[$repoName] ) ) {
117            foreach ( $wgCodeReviewFixmePerPath[$repoName] as $path ) {
118                $this->fixmesPerPath[$path] = $this->getPathFixmes( $path );
119            }
120        }
121
122        $this->newPerPath = [];
123        global $wgCodeReviewNewPerPath;
124        if ( isset( $wgCodeReviewNewPerPath[$repoName] ) ) {
125            foreach ( $wgCodeReviewNewPerPath[$repoName] as $path ) {
126                $this->newPerPath[$path] = $this->getPathNews( $path );
127            }
128        }
129    }
130
131    /**
132     * @param string $status
133     *
134     * @return array
135     */
136    private function getAuthorStatusCounts( $status ) {
137        $array = [];
138        $dbr = wfGetDB( DB_REPLICA );
139        $res = $dbr->select( 'code_rev',
140            [ 'COUNT(*) AS revs', 'cr_author' ],
141            [ 'cr_repo_id' => $this->repo->getId(), 'cr_status' => $status ],
142            __METHOD__,
143            [
144                'GROUP BY' => 'cr_author',
145                'ORDER BY' => 'revs DESC',
146                'LIMIT' => 500,
147            ]
148        );
149        foreach ( $res as $row ) {
150            $array[$row->cr_author] = $row->revs;
151        }
152        return $array;
153    }
154
155    /**
156     * @param array|string $path path to get fixmes for
157     * @return array
158     */
159    private function getPathFixmes( $path ) {
160        return $this->getStatusPath( $path, 'fixme' );
161    }
162
163    /**
164     * @param array|string $path path to get fixmes for
165     * @return array
166     */
167    private function getPathNews( $path ) {
168        return $this->getStatusPath( $path, 'new' );
169    }
170
171    /**
172     * @param array|string $path
173     * @param string $status
174     * @return array
175     */
176    private function getStatusPath( $path, $status ) {
177        $array = [];
178        $dbr = wfGetDB( DB_REPLICA );
179        $res = $dbr->select(
180            [ 'code_paths', 'code_rev' ],
181            [ 'COUNT(*) AS revs', 'cr_author' ],
182            [
183                'cr_repo_id' => $this->repo->getId(),
184                'cp_path' => $path,
185                'cr_status' => $status,
186            ],
187            __METHOD__,
188            [
189                'GROUP BY' => 'cr_author',
190                'ORDER BY' => 'revs DESC',
191                'LIMIT' => 500,
192            ],
193            [
194                'code_rev' => [ 'INNER JOIN', 'cr_repo_id = cp_repo_id AND cr_id = cp_rev_id' ]
195            ]
196        );
197        foreach ( $res as $row ) {
198            $array[$row->cr_author] = $row->revs;
199        }
200        return $array;
201    }
202}