Completed
Push — 2.0 ( 2e5539...7d686a )
by David
03:27
created

BuildService   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 9
dl 0
loc 150
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getCommitId() 0 5 1
A findMergeRequestByCommitSha() 0 18 3
A getLatestCommitIdFromBranch() 0 5 1
A getPipelines() 0 8 2
A findPipelineByCommit() 0 12 3
B getLatestPipelineFromCommitId() 0 26 4
A getLatestPipelineFromBranch() 0 10 2
A dumpArtifact() 0 9 1
A dumpArtifactFromBranch() 0 5 1
1
<?php
2
namespace TheCodingMachine\WashingMachine\Gitlab;
3
use Gitlab\Client;
4
use GuzzleHttp\Psr7\Stream;
5
use GuzzleHttp\Psr7\StreamWrapper;
6
use Symfony\Component\Filesystem\Filesystem;
7
8
/**
9
 * Class to access different data in Gitlab from the build reference
10
 */
11
class BuildService
12
{
13
    /**
14
     * @var Client
15
     */
16
    private $client;
17
18
    public function __construct(Client $client)
19
    {
20
21
        $this->client = $client;
22
    }
23
24
    /**
25
     * Returns a commit ID from a project name and build ref.
26
     *
27
     * @param string $projectName
28
     * @param string $buildRef
29
     * @return string
30
     */
31
    public function getCommitId(string $projectName, string $buildRef) : string
32
    {
33
        $build = $this->client->projects->build($projectName, $buildRef);
0 ignored issues
show
Bug introduced by
The method build() does not seem to exist on object<Gitlab\Api\Projects>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
34
        return $build['commit']['id'];
35
    }
36
37
    /**
38
     * @param string $projectName
39
     * @param string $commitSha
40
     * @return array The merge request object
41
     * @throws MergeRequestNotFoundException
42
     */
43
    public function findMergeRequestByCommitSha(string $projectName, string $commitSha) : array
44
    {
45
        // Find in the merge requests (since our build was triggered recently, it should definitely be there)
46
        $mergeRequests = $this->client->merge_requests->all($projectName, [
47
            'order_by' => 'updated_at',
48
            'sort' => 'desc'
49
        ]);
50
51
        foreach ($mergeRequests as $mergeRequest) {
52
            // Let's only return this PR if the returned commit is the FIRST one (otherwise, the commit ID is on an outdated version of the PR)
53
54
            if ($mergeRequest['sha'] === $commitSha) {
55
                return $mergeRequest;
56
            }
57
        }
58
59
        throw new MergeRequestNotFoundException('Could not find a PR whose last commit/buildRef ID is '.$commitSha);
60
    }
61
62
    public function getLatestCommitIdFromBranch(string $projectName, string $branchName) : string
63
    {
64
        $branch = $this->client->repositories->branch($projectName, $branchName);
65
        return $branch['commit']['id'];
66
    }
67
68
    private $pipelines = [];
69
70
    private function getPipelines(string $projectName) : array
71
    {
72
        if (!isset($this->pipelines[$projectName])) {
73
            $this->pipelines[$projectName] = $this->client->projects->pipelines($projectName);
74
            var_dump($this->pipelines[$projectName]);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($this->pipelines[$projectName]); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
75
        }
76
        return $this->pipelines[$projectName];
77
    }
78
79
    public function findPipelineByCommit(string $projectName, string $commitId) : ?array
80
    {
81
        $pipelines = $this->getPipelines($projectName);
82
83
        foreach ($pipelines as $pipeline) {
84
            if ($pipeline['sha'] === $commitId) {
85
                return $pipeline;
86
            }
87
        }
88
89
        return null;
90
    }
91
92
    /**
93
     * Recursive function that attempts to find a build in the previous commits.
94
     *
95
     * @param string $projectName
96
     * @param string $commitId
97
     * @param int $numIter
98
     * @return array
99
     * @throws BuildNotFoundException
100
     */
101
    public function getLatestPipelineFromCommitId(string $projectName, string $commitId, int $numIter = 0) : array
102
    {
103
104
        $pipeline = $this->findPipelineByCommit($projectName, $commitId);
105
106
        if ($pipeline !== null) {
107
            return $pipeline;
108
        }
109
110
        $numIter++;
111
        // Let's find a build in the last 10 commits.
112
        if ($numIter > 10) {
113
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
114
        }
115
116
        // Let's get the commit info
117
        $commit = $this->client->repositories->commit($projectName, $commitId);
118
        $parentIds = $commit['parent_ids'];
119
120
        if (count($parentIds) !== 1) {
121
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
122
        }
123
124
        // Not found? Let's recurse.
125
        return $this->getLatestPipelineFromCommitId($projectName, $parentIds[0], $numIter);
126
    }
127
128
    /**
129
     * @param string $projectName
130
     * @param string $branchName
131
     * @return array
132
     * @throws BuildNotFoundException
133
     */
134
    public function getLatestPipelineFromBranch(string $projectName, string $branchName) : array
135
    {
136
        $commitId = $this->getLatestCommitIdFromBranch($projectName, $branchName);
137
138
        try {
139
            return $this->getLatestPipelineFromCommitId($projectName, $commitId);
140
        } catch (BuildNotFoundException $e) {
141
            throw new BuildNotFoundException('Could not find a build for branch '.$projectName.':'.$branchName, 0, $e);
142
        }
143
    }
144
145
    public function dumpArtifact(string $projectName, string $buildRef, string $jobName, string $file)
146
    {
147
        $artifactContent = $this->client->jobs->artifactsByRefName($projectName, $buildRef, $jobName);
148
149
        $stream = StreamWrapper::getResource($artifactContent);
150
151
        $filesystem = new Filesystem();
152
        $filesystem->dumpFile($file, $stream);
0 ignored issues
show
Documentation introduced by
$stream is of type resource, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
153
    }
154
155
    public function dumpArtifactFromBranch(string $projectName, string $branchName, string $jobStage, string $file)
156
    {
157
        $build = $this->getLatestPipelineFromBranch($projectName, $branchName);
158
        $this->dumpArtifact($projectName, $build['id'], $jobStage, $file);
159
    }
160
}
161