Completed
Push — 2.0 ( 70b5fd...92ff60 )
by David
01:49
created

BuildService::getLatestPipelineFromBranch()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 2
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
    /**
69
     * Recursive function that attempts to find a build in the previous commits.
70
     *
71
     * @param string $projectName
72
     * @param string $commitId
73
     * @param int $numIter
74
     * @return array
75
     * @throws BuildNotFoundException
76
     */
77
    public function getLatestPipelineFromCommitId(string $projectName, string $commitId, int $numIter = 0) : array
78
    {
79
        // FIXME: can we pass ref to commitId?
80
        $pipelines = $this->client->projects->pipelines($projectName, ['status'=>['failed', 'success'], 'ref'=>$commitId]);
81
82
83
        //$builds = $this->client->repositories->commitBuilds($projectName, $commitId, ['failed', 'success']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% 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...
84
85
        if (!empty($pipelines)) {
86
            // TODO: check that builds are ordered in reverse date order!!!
87
            return $pipelines[0];
88
        }
89
90
        $numIter++;
91
        // Let's find a build in the last 10 commits.
92
        if ($numIter > 10) {
93
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
94
        }
95
96
        // Let's get the commit info
97
        $commit = $this->client->repositories->commit($projectName, $commitId);
98
        $parentIds = $commit['parent_ids'];
99
100
        if (count($parentIds) !== 1) {
101
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
102
        }
103
104
        // Not found? Let's recurse.
105
        return $this->getLatestPipelineFromCommitId($projectName, $parentIds[0], $numIter);
106
    }
107
108
    /**
109
     * @param string $projectName
110
     * @param string $branchName
111
     * @return array
112
     * @throws BuildNotFoundException
113
     */
114
    public function getLatestPipelineFromBranch(string $projectName, string $branchName) : array
115
    {
116
        $commitId = $this->getLatestCommitIdFromBranch($projectName, $branchName);
117
118
        try {
119
            return $this->getLatestPipelineFromCommitId($projectName, $commitId);
120
        } catch (BuildNotFoundException $e) {
121
            throw new BuildNotFoundException('Could not find a build for branch '.$projectName.':'.$branchName, 0, $e);
122
        }
123
    }
124
125
    public function dumpArtifact(string $projectName, string $buildRef, string $jobName, string $file)
126
    {
127
        $artifactContent = $this->client->jobs->artifactsByRefName($projectName, $buildRef, $jobName);
128
129
        $stream = StreamWrapper::getResource($artifactContent);
130
131
        $filesystem = new Filesystem();
132
        $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...
133
    }
134
135
    public function dumpArtifactFromBranch(string $projectName, string $branchName, string $jobStage, string $file)
136
    {
137
        $build = $this->getLatestPipelineFromBranch($projectName, $branchName);
138
        $this->dumpArtifact($projectName, $build['id'], $jobStage, $file);
139
    }
140
}
141