Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
GerritExtDistProvider
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 6
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 makeGerritApiRequest
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 fetchBranches
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 fetchRepositoryList
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 getTarballLocation
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getCacheDuration
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\ExtensionDistributor\Providers;
4
5use FormatJson;
6use MediaWiki\MediaWikiServices;
7use MediaWiki\Status\Status;
8
9/**
10 * ExtensionDistributor provider for the Gerrit Code Review system
11 * Requires an external service to provide tarballs
12 *
13 * @author Legoktm
14 *
15 * Example configuration for Wikimedia sites:
16 *
17 * use MediaWiki\Extension\ExtensionDistributor\Providers\GerritExtDistProvider;
18 *
19 * $wgExtDistAPIConfig = [
20 *  'class' => GerritExtDistProvider::class,
21 *  'apiUrl' => 'https://gerrit.wikimedia.org/r/projects/mediawiki%2F$TYPE%2F$EXT/branches',
22 *  'tarballUrl' => 'http://extdist.wmflabs.org/dist/$TYPE/$EXT-$REF-$SHA.tar.gz',
23 *  'tarballName' => '$EXT-$REF-$SHA.tar.gz',
24 *  'repoListUrl' => 'https://gerrit.wikimedia.org/r/projects/?b=master&p=mediawiki/$TYPE/',
25 *  'sourceUrl' => 'https://gerrit.wikimedia.org/r/mediawiki/$TYPE/$EXT.git',
26 * ];
27 *
28 */
29class GerritExtDistProvider extends ExtDistProvider {
30
31    private $repoListUrl = false;
32
33    public function __construct( array $options ) {
34        parent::__construct( $options );
35        if ( isset( $options['repoListUrl'] ) ) {
36            $this->repoListUrl = $options['repoListUrl'];
37        }
38    }
39
40    /**
41     * @param string $url full URL to request
42     * @return array[]
43     */
44    private function makeGerritApiRequest( $url ) {
45        $options = [];
46        if ( $this->proxy ) {
47            $options['proxy'] = $this->proxy;
48        }
49
50        $req = MediaWikiServices::getInstance()->getHttpRequestFactory()
51            ->create( $url, $options, __METHOD__ );
52        $status = $req->execute();
53        if ( !$status->isOK() ) {
54            $errorText = Status::wrap( $status )->getWikiText( false, false, 'en' );
55            $this->logger->error( __METHOD__ . ": Could not fetch \"{$url}\", " .
56                "received: " . $errorText
57            );
58            return [];
59        }
60        // Gerrit API responses start with )]}' so trim it, then parse the JSON
61        $clean = substr( $req->getContent(), 4 );
62        return wfObjectToArray( FormatJson::decode( $clean ), true );
63    }
64
65    protected function fetchBranches( $name ) {
66        $url = $this->substituteUrlVariables( $this->apiUrl, $name );
67        $info = $this->makeGerritApiRequest( $url );
68        $branches = [];
69        foreach ( $info as $branch ) {
70            if ( strpos( $branch['ref'], 'refs/heads/' ) === 0 ) {
71                $name = substr( $branch['ref'], strlen( 'refs/heads/' ) );
72                $branches[$name] = $branch['revision'];
73            }
74        }
75
76        return $branches;
77    }
78
79    protected function fetchRepositoryList() {
80        if ( !$this->repoListUrl ) {
81            // Not configured, fallback to default
82            return parent::fetchRepositoryList();
83        }
84
85        $repos = [];
86        $out = $this->makeGerritApiRequest(
87            $this->substituteUrlVariables( $this->repoListUrl )
88        );
89        foreach ( $out as $name => $info ) {
90            // Skip read-only repositories
91            if ( isset( $info['state'] ) && $info['state'] === 'READ_ONLY' ) {
92                continue;
93            }
94            $parts = explode( '/', $name );
95            if ( count( $parts ) === 3 ) {
96                $repos[] = array_pop( $parts );
97            }
98        }
99
100        return $repos;
101    }
102
103    public function getTarballLocation( $ext, $version ) {
104        $shortHash = $this->getBranchSha( $ext, $version );
105        return $this->substituteUrlVariables( $this->tarballUrl, $ext, $version, $shortHash );
106    }
107
108    /**
109     * Cache list of branches for 30 minutes
110     *
111     * @return int
112     */
113    protected function getCacheDuration() {
114        return 60 * 30;
115    }
116}