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

eiriksm / cosy-composer / 16469015360

23 Jul 2025 11:10AM UTC coverage: 86.578% (-0.4%) from 86.939%
16469015360

push

github

web-flow
More accurate parsing of named prs  (#427)

82 of 102 new or added lines in 9 files covered. (80.39%)

1 existing line in 1 file now uncovered.

2019 of 2332 relevant lines covered (86.58%)

44.84 hits per line

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

60.53
/src/Providers/Bitbucket.php
1
<?php
2

3
namespace eiriksm\CosyComposer\Providers;
4

5
use Bitbucket\Client;
6
use Bitbucket\ResultPager;
7
use eiriksm\CosyComposer\ProviderInterface;
8
use Violinist\Slug\Slug;
9

10
class Bitbucket implements ProviderInterface
11
{
12

13
    private $cache;
14

15
    /**
16
     * @var Client
17
     */
18
    private $client;
19

20
    public function __construct(Client $client)
21
    {
22
        $this->client = $client;
2✔
23
    }
24

25
    public function authenticate($user, $token)
26
    {
27
        $this->client->authenticate(Client::AUTH_OAUTH_TOKEN, $user);
1✔
28
        if ($user && $token) {
1✔
29
            $this->client->authenticate(Client::AUTH_HTTP_PASSWORD, $user, $token);
×
30
        }
31
    }
32

33
    public function authenticatePrivate($user, $token)
34
    {
35
        $this->client->authenticate(Client::AUTH_OAUTH_TOKEN, $user);
×
36
    }
37

38
    public function repoIsPrivate(Slug $slug)
39
    {
40
        $user = $slug->getUserName();
×
41
        $repo = $slug->getUserRepo();
×
42
        if (!isset($this->cache['repo'])) {
×
43
            $this->cache['repo'] = $this->getRepo($user, $repo);
×
44
        }
45
        return (bool) $this->cache["repo"]["is_private"];
×
46
    }
47

48
    protected function getRepo($user, $repo)
49
    {
50
        return $this->client->repositories()->workspaces($user)->show($repo);
1✔
51
    }
52

53
    public function getDefaultBranch(Slug $slug)
54
    {
55
        $user = $slug->getUserName();
1✔
56
        $repo = $slug->getUserRepo();
1✔
57
        if (!isset($this->cache['repo'])) {
1✔
58
            $this->cache['repo'] = $this->getRepo($user, $repo);
1✔
59
        }
60
        if (empty($this->cache["repo"]["mainbranch"]["name"])) {
1✔
61
            throw new \Exception('No default branch found');
×
62
        }
63
        return $this->cache["repo"]["mainbranch"]["name"];
1✔
64
    }
65

66
    protected function getBranches($user, $repo)
67
    {
68
        if (!isset($this->cache['branches'])) {
1✔
69
            $paginator = new ResultPager($this->client);
1✔
70
            $repo_users = $this->client->repositories()->workspaces($user);
1✔
71
            $branch_client = $repo_users->refs($repo)->branches();
1✔
72

73
            $this->cache['branches'] = [
1✔
74
                'values' => $paginator->fetchAll($branch_client, 'list'),
1✔
75
            ];
1✔
76
        }
77
        return $this->cache["branches"]["values"];
1✔
78
    }
79

80
    public function getBranchesFlattened(Slug $slug)
81
    {
82
        $user = $slug->getUserName();
1✔
83
        $repo = $slug->getUserRepo();
1✔
84
        $branches = $this->getBranches($user, $repo);
1✔
85

86
        $branches_flattened = [];
1✔
87
        foreach ($branches as $branch) {
1✔
88
            $branches_flattened[] = $branch['name'];
1✔
89
        }
90
        return $branches_flattened;
1✔
91
    }
92

93
    public function getPrsNamed(Slug $slug) : NamedPrs
94
    {
95
        $user = $slug->getUserName();
1✔
96
        $repo = $slug->getUserRepo();
1✔
97
        $api_repo = $this->client->repositories();
1✔
98
        $prs_client = $api_repo->workspaces($user)->pullRequests($repo);
1✔
99
        $paginator = new ResultPager($this->client);
1✔
100
        $prs = [
1✔
101
            'values' => $paginator->fetchAll($prs_client, 'list'),
1✔
102
        ];
1✔
103
        $prs_named = new NamedPrs();
1✔
104
        foreach ($prs["values"] as $pr) {
1✔
105
            if ($pr["state"] !== 'OPEN') {
×
106
                continue;
×
107
            }
NEW
108
            $data = [
×
109
                'base' => [
×
110
                    'sha' => $pr["destination"]["commit"]["hash"],
×
111
                    'ref' => $pr["destination"]["branch"]["name"],
×
112
                ],
×
113
                'html_url' => $pr["links"]["html"]["href"],
×
114
                'number' => $pr["id"],
×
115
                'title' => $pr["title"],
×
NEW
116
                'head' => [
×
NEW
117
                    'ref' => $pr["source"]["branch"]["name"],
×
NEW
118
                ],
×
UNCOV
119
            ];
×
NEW
120
            $prs_named->addFromPrData($data);
×
121
            try {
122
                // See if we can retrieve the commit as well.
NEW
123
                $commit = $api_repo->workspaces($user)->commit($repo)->show($pr["source"]["commit"]["hash"]);
×
NEW
124
                $prs_named->addFromCommit($commit["message"], $data);
×
NEW
125
            } catch (\Throwable $e) {
×
126
                // If the commit is not found, we just skip it.
127
            }
128
        }
129
        return $prs_named;
1✔
130
    }
131

132
    public function getDefaultBase(Slug $slug, $default_branch)
133
    {
134
        $user = $slug->getUserName();
1✔
135
        $repo = $slug->getUserRepo();
1✔
136
        $branches = $this->getBranches($user, $repo);
1✔
137
        $default_base = null;
1✔
138
        foreach ($branches as $branch) {
1✔
139
            if ($branch['name'] == $default_branch) {
1✔
140
                $default_base = $branch["target"]["hash"];
×
141
            }
142
        }
143
        // Since the branches only gives us 12 characters, we need to trim the default base to the same.
144
        return substr($default_base, 0, 12);
1✔
145
    }
146

147
    public function createFork($user, $repo, $fork_user)
148
    {
149
        throw new \Exception('Bitbucket integration only support creating PRs as the authenticated user.');
×
150
    }
151

152
    public function createPullRequest(Slug $slug, $params)
153
    {
154
        $user_name = $slug->getUserName();
1✔
155
        $user_repo = $slug->getUserRepo();
1✔
156
        $bitbucket_params = [
1✔
157
            'title' => $params['title'],
1✔
158
            'source' => [
1✔
159
                'branch' => [
1✔
160
                    'name' => $params["head"],
1✔
161
                ],
1✔
162
            ],
1✔
163
            'destination' => [
1✔
164
                'branch' => [
1✔
165
                    'name' => $params["base"],
1✔
166
                ],
1✔
167
            ],
1✔
168
            'description' => $params['body'],
1✔
169
        ];
1✔
170

171
        if (!empty($params['assignees'])) {
1✔
172
            foreach ($params['assignees'] as $assignee) {
×
173
                $bitbucket_params['reviewers'][] = [
×
174
                    'username' => $assignee,
×
175
                ];
×
176
            }
177
        }
178
        $data = $this->client
1✔
179
            ->repositories()
1✔
180
            ->workspaces($user_name)
1✔
181
            ->pullRequests($user_repo)
1✔
182
            ->create($bitbucket_params);
1✔
183
        if (!empty($data["links"]["html"]["href"])) {
1✔
184
            $data['html_url'] = $data["links"]["html"]["href"];
×
185
        }
186
        if (!empty($data['id'])) {
1✔
187
            $data['number'] = $data['id'];
×
188
        }
189
        return $data;
1✔
190
    }
191

192
    public function updatePullRequest(Slug $slug, $id, $params)
193
    {
194
        $user_name = $slug->getUserName();
×
195
        $user_repo = $slug->getUserRepo();
×
196
        return $this->client->repositories()->workspaces($user_name)->pullRequests($user_repo)->update($id, $params);
×
197
    }
198

199
    public function addLabels(array $pr_data, Slug $slug, array $labels): bool
200
    {
201
        // @todo: Not implemented yet. It's also not supported on bitbucket, so.
202
        // https://jira.atlassian.com/browse/BCLOUD-11976
203
        return false;
×
204
    }
205

206
    public function enableAutomerge(array $pr_data, Slug $slug, $merge_method = self::MERGE_METHOD_MERGE) : bool
207
    {
208
        // @todo: Not implemented yet.
209
        return false;
×
210
    }
211

212
    public function closePullRequestWithComment(Slug $slug, $pr_id, $comment)
213
    {
214
        $this->client->repositories()->workspaces($slug->getUserName())->pullRequests($slug->getUserRepo())->comments($pr_id)->create([
×
215
            'content' => [
×
216
                'raw' => $comment,
×
217
            ],
×
218
        ]);
×
219
        $this->client->repositories()->workspaces($slug->getUserName())->pullRequests($slug->getUserRepo())->decline($pr_id);
×
220
    }
221

222
    public static function tokenIndicatesUserAppPassword($token)
223
    {
224
        return strlen($token) < 50 && strpos($token, ':') !== false;
3✔
225
    }
226
}
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