BuildService   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

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

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getCommitId() 0 5 1
A findMergeRequestByCommitSha() 0 17 3
A getLatestCommitIdFromBranch() 0 5 1
B getLatestBuildFromCommitId() 0 26 4
A getLatestBuildFromBranch() 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);
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 last 50 merge requests (since our build was triggered recently, it should definitely be there)
46
        $mergeRequests = $this->client->merge_requests->all($projectName, 1, 50, 'updated_at', 'desc');
47
48
        foreach ($mergeRequests as $mergeRequest) {
49
            $commits = $this->client->merge_requests->commits($projectName, $mergeRequest['id']);
50
            // 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)
51
52
            // Note: strangely, the "id" column of the commit is the build ref and not the commit id... weird!
53
            if ($commits[0]['id'] === $commitSha) {
54
                return $mergeRequest;
55
            }
56
        }
57
58
        throw new MergeRequestNotFoundException('Could not find a PR (in the 50 last PRs) whose last commit/buildRef ID is '.$commitSha);
59
    }
60
61
    public function getLatestCommitIdFromBranch(string $projectName, string $branchName) : string
62
    {
63
        $branch = $this->client->repositories->branch($projectName, $branchName);
64
        return $branch['commit']['id'];
65
    }
66
67
    /**
68
     * Recursive function that attempts to find a build in the previous commits.
69
     *
70
     * @param string $projectName
71
     * @param string $commitId
72
     * @param int $numIter
73
     * @return array
74
     * @throws BuildNotFoundException
75
     */
76
    public function getLatestBuildFromCommitId(string $projectName, string $commitId, int $numIter = 0) : array
77
    {
78
        $builds = $this->client->repositories->commitBuilds($projectName, $commitId, ['failed', 'success']);
0 ignored issues
show
Documentation introduced by
array('failed', 'success') is of type array<integer,string,{"0":"string","1":"string"}>, but the function expects a string|null.

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...
79
80
        if (!empty($builds)) {
81
            // TODO: check that builds are ordered in reverse date order!!!
82
            return $builds[0];
83
        }
84
85
        $numIter++;
86
        // Let's find a build in the last 10 commits.
87
        if ($numIter > 10) {
88
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
89
        }
90
91
        // Let's get the commit info
92
        $commit = $this->client->repositories->commit($projectName, $commitId);
93
        $parentIds = $commit['parent_ids'];
94
95
        if (count($parentIds) !== 1) {
96
            throw new BuildNotFoundException('Could not find a build for commit '.$projectName.':'.$commitId);
97
        }
98
99
        // Not found? Let's recurse.
100
        return $this->getLatestBuildFromCommitId($projectName, $parentIds[0], $numIter);
101
    }
102
103
    /**
104
     * @param string $projectName
105
     * @param string $branchName
106
     * @return array
107
     * @throws BuildNotFoundException
108
     */
109
    public function getLatestBuildFromBranch(string $projectName, string $branchName) : array
110
    {
111
        $commitId = $this->getLatestCommitIdFromBranch($projectName, $branchName);
112
113
        try {
114
            return $this->getLatestBuildFromCommitId($projectName, $commitId);
115
        } catch (BuildNotFoundException $e) {
116
            throw new BuildNotFoundException('Could not find a build for branch '.$projectName.':'.$branchName, 0, $e);
117
        }
118
    }
119
120
    public function dumpArtifact(string $projectName, string $buildRef, string $jobName, string $file)
121
    {
122
        $artifactContent = $this->client->jobs->artifactsByRefName($projectName, $buildRef, $jobName);
123
124
        $stream = StreamWrapper::getResource($artifactContent);
125
126
        $filesystem = new Filesystem();
127
        $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...
128
    }
129
130
    public function dumpArtifactFromBranch(string $projectName, string $branchName, string $jobStage, string $file)
131
    {
132
        $build = $this->getLatestBuildFromBranch($projectName, $branchName);
133
        $this->dumpArtifact($projectName, $build['id'], $jobStage, $file);
134
    }
135
}
136