• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mborne / remote-git / 23622402787

26 Mar 2026 11:05PM UTC coverage: 91.473% (-1.4%) from 92.857%
23622402787

push

github

web-flow
Merge pull request #46 from mborne/upgrade_test

Improve tests

1 of 1 new or added line in 1 file covered. (100.0%)

10 existing lines in 3 files now uncovered.

354 of 387 relevant lines covered (91.47%)

2.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.61
/src/Github/GithubClient.php
1
<?php
2

3
namespace MBO\RemoteGit\Github;
4

5
use GuzzleHttp\Client as GuzzleHttpClient;
6
use MBO\RemoteGit\AbstractClient;
7
use MBO\RemoteGit\Exception\RawFileNotFoundException;
8
use MBO\RemoteGit\Exception\RequiredParameterException;
9
use MBO\RemoteGit\FindOptions;
10
use MBO\RemoteGit\Http\TokenType;
11
use MBO\RemoteGit\ProjectFilterInterface;
12
use MBO\RemoteGit\ProjectInterface;
13
use Psr\Log\LoggerInterface;
14

15
/**
16
 * Client implementation for github.
17
 *
18
 * See following github docs :
19
 *
20
 * https://developer.github.com/v3/repos/#list-organization-repositories
21
 * https://developer.github.com/v3/repos/#list-user-repositories
22
 * https://developer.github.com/v3/#pagination
23
 *
24
 * @author mborne
25
 */
26
class GithubClient extends AbstractClient
27
{
28
    public const TYPE = 'github';
29
    public const TOKEN_TYPE = TokenType::AUTHORIZATION_TOKEN;
30
    private const LIMIT_PER_PAGE_PARAM = 'per_page';
31

32
    /**
33
     * Constructor with an http client and a logger.
34
     *
35
     * @param $httpClient http client
36
     */
37
    public function __construct(
38
        GuzzleHttpClient $httpClient,
39
        ?LoggerInterface $logger = null,
40
    ) {
41
        parent::__construct($httpClient, self::LIMIT_PER_PAGE_PARAM, $logger);
2✔
42
    }
43

44
    protected function createProject(array $rawProject): GithubProject
45
    {
46
        return new GithubProject($rawProject);
2✔
47
    }
48

49
    public function getProjects(FindOptions $options): iterable
50
    {
51
        if (empty($options->getUsers()) && empty($options->getOrganizations())) {
2✔
UNCOV
52
            throw new RequiredParameterException('[GithubClient]Define at least an org or an user');
×
53
        }
54
        foreach ($options->getUsers() as $user) {
2✔
55
            yield from $this->findByUser(
2✔
56
                $user,
2✔
57
                $options->getFilter()
2✔
58
            );
2✔
59
        }
60
        foreach ($options->getOrganizations() as $org) {
2✔
61
            yield from $this->findByOrg(
1✔
62
                $org,
1✔
63
                $options->getFilter()
1✔
64
            );
1✔
65
        }
66
    }
67

68
    /**
69
     * Find projects by username.
70
     *
71
     * @see https://docs.github.com/en/rest/repos/repos#list-repositories-for-the-authenticated-user
72
     * @see https://docs.github.com/en/rest/repos/repos#list-repositories-for-a-user
73
     *
74
     * @return ProjectInterface[]
75
     */
76
    protected function findByUser(
77
        string $user,
78
        ProjectFilterInterface $projectFilter,
79
    ): iterable {
80
        /*
81
         * Use /user/repos?affiliation=owner for special user _me_
82
         */
83
        if ('_me_' == $user) {
2✔
UNCOV
84
            yield from $this->fetchAllPages(
×
UNCOV
85
                '/user/repos',
×
UNCOV
86
                $projectFilter,
×
UNCOV
87
                extraParams: [
×
UNCOV
88
                    'affiliation' => 'owner',
×
89
                ]
×
90
            );
×
91
        } else {
92
            yield from $this->fetchAllPages(
2✔
93
                '/users/'.$user.'/repos',
2✔
94
                $projectFilter
2✔
95
            );
2✔
96
        }
97
    }
98

99
    /**
100
     * Find projects by org name.
101
     *
102
     * @return iterable<ProjectInterface>
103
     */
104
    protected function findByOrg(
105
        string $org,
106
        ProjectFilterInterface $projectFilter,
107
    ): iterable {
108
        yield from $this->fetchAllPages(
1✔
109
            '/orgs/'.$org.'/repos',
1✔
110
            $projectFilter
1✔
111
        );
1✔
112
    }
113

114
    public function getRawFile(
115
        ProjectInterface $project,
116
        $filePath,
117
        $ref,
118
    ): string {
119
        $metadata = $project->getRawMetadata();
2✔
120
        $uri = str_replace(
2✔
121
            '{+path}',
2✔
122
            urlencode($filePath),
2✔
123
            $metadata['contents_url']
2✔
124
        );
2✔
125
        $uri .= '?ref='.$ref;
2✔
126

127
        try {
128
            $this->getLogger()->debug('GET '.$uri);
2✔
129
            $response = $this->getHttpClient()->request('GET', $uri, [
2✔
130
                'headers' => [
2✔
131
                    'Accept' => 'application/vnd.github.v3.raw',
2✔
132
                ],
2✔
133
            ]);
2✔
134

135
            return (string) $response->getBody();
2✔
136
        } catch (\Exception $e) {
1✔
137
            throw new RawFileNotFoundException($filePath, $ref, $e);
1✔
138
        }
139
    }
140
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc