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 MediaWiki\Json\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    /** @var string|false */
32    private $repoListUrl = false;
33
34    public function __construct( array $options ) {
35        parent::__construct( $options );
36        if ( isset( $options['repoListUrl'] ) ) {
37            $this->repoListUrl = $options['repoListUrl'];
38        }
39    }
40
41    /**
42     * @param string $url full URL to request
43     * @return array[]
44     */
45    private function makeGerritApiRequest( $url ) {
46        $options = [];
47        if ( $this->proxy ) {
48            $options['proxy'] = $this->proxy;
49        }
50
51        $req = MediaWikiServices::getInstance()->getHttpRequestFactory()
52            ->create( $url, $options, __METHOD__ );
53        $status = $req->execute();
54        if ( !$status->isOK() ) {
55            $errorText = Status::wrap( $status )->getWikiText( false, false, 'en' );
56            $this->logger->error( __METHOD__ . ": Could not fetch \"{$url}\", " .
57                "received: " . $errorText
58            );
59            return [];
60        }
61        // Gerrit API responses start with )]}' so trim it, then parse the JSON
62        $clean = substr( $req->getContent(), 4 );
63        return wfObjectToArray( FormatJson::decode( $clean ), true );
64    }
65
66    /** @inheritDoc */
67    protected function fetchBranches( $name ) {
68        $url = $this->substituteUrlVariables( $this->apiUrl, $name );
69        $info = $this->makeGerritApiRequest( $url );
70        $branches = [];
71        foreach ( $info as $branch ) {
72            if ( strpos( $branch['ref'], 'refs/heads/' ) === 0 ) {
73                $name = substr( $branch['ref'], strlen( 'refs/heads/' ) );
74                $branches[$name] = $branch['revision'];
75            }
76        }
77
78        return $branches;
79    }
80
81    protected function fetchRepositoryList() {
82        if ( !$this->repoListUrl ) {
83            // Not configured, fallback to default
84            return parent::fetchRepositoryList();
85        }
86
87        $repos = [];
88        $out = $this->makeGerritApiRequest(
89            $this->substituteUrlVariables( $this->repoListUrl )
90        );
91        foreach ( $out as $name => $info ) {
92            // Skip read-only repositories
93            if ( isset( $info['state'] ) && $info['state'] === 'READ_ONLY' ) {
94                continue;
95            }
96            $parts = explode( '/', $name );
97            if ( count( $parts ) === 3 ) {
98                $repos[] = array_pop( $parts );
99            }
100        }
101
102        return $repos;
103    }
104
105    /** @inheritDoc */
106    public function getTarballLocation( $ext, $version ) {
107        $shortHash = $this->getBranchSha( $ext, $version );
108        return $this->substituteUrlVariables( $this->tarballUrl, $ext, $version, $shortHash );
109    }
110
111    /**
112     * Cache list of branches for 30 minutes
113     *
114     * @return int
115     */
116    protected function getCacheDuration() {
117        return 60 * 30;
118    }
119}