Passed
Pull Request — master (#29)
by Ronan
03:55
created

ApiController   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 15
eloc 96
c 1
b 0
f 0
dl 0
loc 161
ccs 0
cts 137
cp 0
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A events() 0 40 5
C webhookDeploy() 0 99 10
1
<?php
2
3
namespace App\Controller\Project;
4
5
use App\Controller\Traits\ApiTrait;
6
use App\Controller\Traits\ProjectTrait;
7
use App\Facades\Log;
8
use App\Facades\Provider;
9
use App\Facades\Security;
10
use App\Model\Deployment;
11
use App\Model\Event;
12
use App\Model\Project;
13
use App\Queue\DeployJob;
14
use Exception;
15
use Psr\Http\Message\ResponseInterface;
16
use Psr\Http\Message\ServerRequestInterface;
17
use Ronanchilvers\Foundation\Facade\Queue;
18
use Ronanchilvers\Orm\Orm;
19
use RuntimeException;
20
21
/**
22
 * API Controller supporting the project UI
23
 *
24
 * @author Ronan Chilvers <[email protected]>
25
 */
26
class ApiController
27
{
28
    use ProjectTrait;
29
    use ApiTrait;
30
31
    /**
32
     * Get the event data for a project
33
     *
34
     * @param ServerRequestInterface $request
35
     * @param ResponseInterface $response
36
     * @param array $args
37
     * @return ResponseInterface
38
     * @author Ronan Chilvers <[email protected]>
39
     */
40
    public function events(
41
        ServerRequestInterface $request,
42
        ResponseInterface $response,
43
        array $args
44
    ) {
45
        if (!$project = $this->projectFromArgs($args)) {
46
            return $this->apiError(
47
                $response,
48
                'Invalid project'
49
            );
50
        }
51
        if (!isset($args['number']) || 0 == (int) $args['number']) {
52
            return $this->apiError(
53
                $response,
54
                'Invalid deployment number'
55
            );
56
        }
57
        $number = (int) $args['number'];
58
        $deployment = Orm::finder(Deployment::class)->forProjectIdAndNumber(
59
            $project->id,
60
            $number
61
        );
62
        if (!$deployment instanceof Deployment) {
63
            return $this->apiError(
64
                $response,
65
                'Deployment not found for project'
66
            );
67
        }
68
        $data = [
69
            // 'project' => $project->toArray(),
70
            'deployment' => $deployment->toArray(),
71
        ];
72
        $events = Orm::finder(Event::class)->arrayForDeploymentId(
73
            $deployment->id
74
        );
75
        $data['events'] = $events;
76
77
        return $this->apiResponse(
78
            $response,
79
            $data
80
        );
81
    }
82
83
    /**
84
     * Trigger a build of a project specified by the project token
85
     *
86
     * @author Ronan Chilvers <[email protected]>
87
     */
88
    public function webhookDeploy(
89
        ServerRequestInterface $request,
90
        ResponseInterface $response,
91
        $args
92
    ) {
93
        try {
94
            $project = Orm::finder(Project::class)->forToken($args['token']);
95
            if (!$project instanceof Project) {
96
                throw new RuntimeException(
97
                    'Invalid or unknown project token',
98
                    400
99
                );
100
            }
101
            if (!$project->isDeployable()) {
102
                throw new RuntimeException(
103
                    'Project is not deployable at the moment',
104
                    400
105
                );
106
            }
107
            Log::debug('Queueing project from webhook', [
108
                'project' => $project->toArray(),
109
            ]);
110
            $provider = Provider::forProject(
111
                $project
112
            );
113
            $finder = Orm::finder(Event::class);
114
            Orm::transaction(function() use ($project, $provider, $finder) {
115
                try {
116
                    $deployment = Orm::finder(Deployment::class)->nextForProject(
117
                        $project
118
                    );
119
                    $deployment->source = 'webhook'; //Security::email();
120
                    if (!$deployment->save()) {
121
                        Log::debug('Unable to create new deployment object', [
122
                            'project' => $project->toArray(),
123
                        ]);
124
                        throw new RuntimeException('Unable to create new deployment');
125
                    }
126
                    $finder->event(
127
                        'info',
128
                        $deployment,
129
                        'Initialise',
130
                        sprintf("Querying %s for head commit data", $provider->getLabel())
131
                    );
132
                    $head = $provider->getHeadInfo($project->repository, $project->branch);
133
                    $finder->event(
134
                        'info',
135
                        $deployment,
136
                        'Initialise',
137
                        "Commit data : " . json_encode($head, JSON_PRETTY_PRINT)
138
                    );
139
                    Log::debug('Updating deployment commit information', $head);
140
                    $deployment->sha       = $head['sha'];
141
                    $deployment->author    = $head['author'];
142
                    $deployment->committer = $head['committer'];
143
                    $deployment->message   = $head['message'];
144
                    if (!$deployment->save()) {
145
                        throw new RuntimeException(
146
                            'Unable to create new deployment',
147
                            500
148
                        );
149
                    }
150
                    if (!$project->markDeploying()) {
151
                        throw new RuntimeException(
152
                            'Unable to mark project as deploying',
153
                            500
154
                        );
155
                    }
156
                    Queue::dispatch(
157
                        new DeployJob($deployment)
158
                    );
159
                } catch (Exception $ex) {
160
                    if (isset($deployment) && $deployment instanceof Deployment) {
161
                        $finder->event(
162
                            'error',
163
                            $deployment,
164
                            'Initialise',
165
                            $ex->getMessage()
166
                        );
167
                    }
168
                    throw $ex;
169
                }
170
            });
171
172
            Log::error('Queued deployment from webhook', [
173
                'project' => $project->toArray(),
174
            ]);
175
            return $this->apiResponse(
176
                $response,
177
                []
178
            );
179
        } catch (Exception $ex) {
180
            Log::error('Failed to initialise new deployment', [
181
                'exception' => $ex,
182
            ]);
183
            return $this->apiError(
184
                $response,
185
                $ex->getMessage(),
186
                $ex->getCode()
187
            );
188
        }
189
    }
190
}
191