Completed
Push — 2.0 ( 4e07f8...e8af7e )
by David
14s
created

BuildService::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 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
     * @param string $projectName
26
     * @param string $commitSha
27
     * @return array The merge request object
28
     * @throws MergeRequestNotFoundException
29
     */
30
    public function findMergeRequestByCommitSha(string $projectName, string $commitSha) : array
31
    {
32
        // Find in the merge requests (since our build was triggered recently, it should definitely be there)
33
        $mergeRequests = $this->client->merge_requests->all($projectName, [
34
            'order_by' => 'updated_at',
35
            'sort' => 'desc'
36
        ]);
37
38
        foreach ($mergeRequests as $mergeRequest) {
39
            // 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)
40
41
            if ($mergeRequest['sha'] === $commitSha) {
42
                return $mergeRequest;
43
            }
44
        }
45
46
        throw new MergeRequestNotFoundException('Could not find a PR whose last commit/buildRef ID is '.$commitSha);
47
    }
48
49
    public function getLatestCommitIdFromBranch(string $projectName, string $branchName) : string
50
    {
51
        $branch = $this->client->repositories->branch($projectName, $branchName);
52
        return $branch['commit']['id'];
53
    }
54
55
    private $pipelines = [];
56
57
    private function getPipelines(string $projectName) : array
58
    {
59
        if (!isset($this->pipelines[$projectName])) {
60
            $this->pipelines[$projectName] = $this->client->projects->pipelines($projectName);
61
        }
62
        return $this->pipelines[$projectName];
63
    }
64
65
    public function findPipelineByCommit(string $projectName, string $commitId) : ?array
66
    {
67
        $pipelines = $this->getPipelines($projectName);
68
69
        foreach ($pipelines as $pipeline) {
70
            if ($pipeline['sha'] === $commitId) {
71
                return $pipeline;
72
            }
73
        }
74
75
        return null;
76
    }
77
78
    /**
79
     * Recursive function that attempts to find a build in the previous commits.
80
     *
81
     * @param string $projectName
82
     * @param string $commitId
83
     * @param int $numIter
84
     * @return array
85
     * @throws BuildNotFoundException
86
     */
87
    public function getLatestPipelineFromCommitId(string $projectName, string $commitId, int $numIter = 0) : array
88
    {
89
90
        $pipeline = $this->findPipelineByCommit($projectName, $commitId);
91
92
        if ($pipeline !== null) {
93
            return $pipeline;
94
        }
95
96
        $numIter++;
97
        // Let's find a build in the last 10 commits.
98
        if ($numIter > 10) {
99
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
100
        }
101
102
        // Let's get the commit info
103
        $commit = $this->client->repositories->commit($projectName, $commitId);
104
        $parentIds = $commit['parent_ids'];
105
106
        if (count($parentIds) !== 1) {
107
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
108
        }
109
110
        // Not found? Let's recurse.
111
        return $this->getLatestPipelineFromCommitId($projectName, $parentIds[0], $numIter);
112
    }
113
114
    /**
115
     * @param string $projectName
116
     * @param string $branchName
117
     * @return array
118
     * @throws BuildNotFoundException
119
     */
120
    public function getLatestPipelineFromBranch(string $projectName, string $branchName) : array
121
    {
122
        $commitId = $this->getLatestCommitIdFromBranch($projectName, $branchName);
123
124
        try {
125
            return $this->getLatestPipelineFromCommitId($projectName, $commitId);
126
        } catch (BuildNotFoundException $e) {
127
            throw new BuildNotFoundException('Could not find a build for branch '.$projectName.':'.$branchName, 0, $e);
128
        }
129
    }
130
131
    public function dumpArtifact(string $projectName, string $pipelineId, string $buildName, string $jobStage, string $file)
132
    {
133
        // Call seems broken
134
        //$artifactContent = $this->client->jobs->artifactsByRefName($projectName, $buildRef, $jobName);
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
135
136
        $jobs = $this->client->jobs->pipelineJobs($projectName, $pipelineId);
137
        $job = null;
138
        foreach ($jobs as $jobItem) {
139
            if ($jobItem['name'] === $buildName && $jobItem['stage'] === $jobStage && (in_array($jobItem['status'], ['failed', 'success']))) {
140
                $job = $jobItem;
141
                break;
142
            }
143
        }
144
145
        if ($job === null) {
146
            throw new \RuntimeException('Could not find finished job with build name "'.$buildName.'" and stage "'.$jobStage.'" in pipeline "'.$pipelineId.'"');
147
        }
148
149
        $artifactContent = $this->client->jobs->artifacts($projectName, $job['id']);
150
151
        $stream = StreamWrapper::getResource($artifactContent);
152
153
        $filesystem = new Filesystem();
154
        $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...
155
    }
156
157
    public function dumpArtifactFromBranch(string $projectName, string $branchName, string $buildName, string $jobStage, string $file)
158
    {
159
        $pipeline = $this->getLatestPipelineFromBranch($projectName, $branchName);
160
        $this->dumpArtifact($projectName, $pipeline['id'], $buildName, $jobStage, $file);
161
    }
162
}
163