Passed
Pull Request — master (#23)
by Ronan
05:57 queued 10s
created

ProjectController::projectFromArgs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 8
ccs 0
cts 7
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace App\Controller;
4
5
use App\Controller\Traits\ProjectTrait;
6
use App\Facades\Log;
7
use App\Facades\Provider;
8
use App\Facades\Router;
9
use App\Facades\Security;
10
use App\Facades\Session;
11
use App\Facades\View;
12
use App\Model\Deployment;
13
use App\Model\Event;
14
use App\Model\Project;
15
use App\Queue\DeployJob;
16
use App\Queue\ReactivateJob;
17
use Exception;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
use Ronanchilvers\Foundation\Facade\Queue;
21
use Ronanchilvers\Foundation\Queue\Exception\FailedDispatchException;
22
use Ronanchilvers\Orm\Orm;
23
use Ronanchilvers\Utility\Str;
24
use RuntimeException;
25
26
/**
27
 * Controller for the index
28
 *
29
 * @author Ronan Chilvers <[email protected]>
30
 */
31
class ProjectController
32
{
33
    use ProjectTrait;
34
35
    /**
36
     * Index action
37
     *
38
     * @author Ronan Chilvers <[email protected]>
39
     */
40
    public function index(
41
        ServerRequestInterface $request,
42
        ResponseInterface $response
43
    ) {
44
        $user = Security::user();
45
        $all = Orm::finder(Project::class)->all();
46
47
        $userFavourites = $user->preference('favourites', []);
48
        $favourites = $projects = [];
49
        foreach ($all as $project) {
50
            if (in_array($project->id, $userFavourites)) {
51
                $favourites[] = $project;
52
                continue;
53
            }
54
            $projects[] = $project;
55
        }
56
57
        return View::render(
58
            $response,
59
            'project/index.html.twig',
60
            [
61
                'favourites' => $favourites,
62
                'projects'   => $projects
63
            ]
64
        );
65
    }
66
67
    /**
68
     * View a project dashboard
69
     *
70
     * @author Ronan Chilvers <[email protected]>
71
     */
72
    public function view(
73
        ServerRequestInterface $request,
74
        ResponseInterface $response,
75
        $args
76
    ) {
77
        if (!$project = $this->projectFromArgs($args)) {
78
            return $response->withRedirect(
0 ignored issues
show
Bug introduced by
The method withRedirect() does not exist on Psr\Http\Message\ResponseInterface. It seems like you code against a sub-type of Psr\Http\Message\ResponseInterface such as Slim\Http\Response. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

78
            return $response->/** @scrutinizer ignore-call */ withRedirect(
Loading history...
79
                Router::pathFor('project.index')
80
            );
81
        }
82
83
        $finder = Orm::finder(Deployment::class);
84
        $deployments = $finder->forProject($project);
85
86
        $selected_number = $request->getQueryParam(
0 ignored issues
show
Bug introduced by
The method getQueryParam() does not exist on Psr\Http\Message\ServerRequestInterface. Did you maybe mean getQueryParams()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

86
        /** @scrutinizer ignore-call */ 
87
        $selected_number = $request->getQueryParam(

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...
87
            'deployment',
88
            (0 < count($deployments)) ? $deployments[0]->number : false
89
        );
90
        $selectedDeployment = (0 < count($deployments)) ? $deployments[0] : false;
91
        foreach ($deployments as $deployment) {
92
            if ($deployment->number == $selected_number) {
93
                $selectedDeployment = $deployment;
94
                break;
95
            }
96
        }
97
        $events = [];
98
        if ($selectedDeployment) {
99
            $events = Orm::finder(Event::class)->arrayForDeploymentId(
100
                $selectedDeployment->id
101
            );
102
            // $events = $selectedDeployment->events;
103
        }
104
105
        return View::render(
106
            $response,
107
            'project/view.html.twig',
108
            [
109
                'project'             => $project,
110
                'deployments'         => $deployments,
111
                'selected_deployment' => $selectedDeployment,
112
                'events'              => $events,
113
            ]
114
        );
115
    }
116
117
    /**
118
     * Add a project
119
     *
120
     * @author Ronan Chilvers <[email protected]>
121
     */
122
    public function add(
123
        ServerRequestInterface $request,
124
        ResponseInterface $response
125
    ) {
126
        $project = new Project;
127
        if ($request->isMethod('POST')) {
128
            $data = $request->getParsedBody()['project'];
129
            $project->fromArray($data);
130
            if ($project->saveWithValidation()) {
131
                Session::flash([
132
                    'heading' => 'Project added'
133
                ], 'success');
134
                return $response->withRedirect(
135
                    Router::pathFor('project.view', ['key' => $project->key])
136
                );
137
            }
138
            Log::debug('Project add failed', [
139
                'errors' => $project->getErrors()
140
            ]);
141
        }
142
143
        return View::render(
144
            $response,
145
            'project/add.html.twig',
146
            [
147
                'project' => $project,
148
                'providers' => Provider::getOptions(),
149
            ]
150
        );
151
    }
152
153
    /**
154
     * Edit action
155
     *
156
     * @author Ronan Chilvers <[email protected]>
157
     */
158
    public function edit(
159
        ServerRequestInterface $request,
160
        ResponseInterface $response,
161
        $args
162
    ) {
163
        if (!$project = $this->projectFromArgs($args)) {
164
            return $response->withRedirect(
165
                Router::pathFor('project.index')
166
            );
167
        }
168
        if ($request->isMethod('POST')) {
169
            $data = $request->getParsedBody()['project'];
170
            $project->fromArray($data);
171
            if ($project->saveWithValidation()) {
172
                Session::flash([
173
                    'heading' => 'Project saved'
174
                ]);
175
                return $response->withRedirect(
176
                    Router::pathFor('project.edit', [
177
                        'key' => $project->key
178
                    ])
179
                );
180
            }
181
        }
182
183
        return View::render(
184
            $response,
185
            'project/edit.html.twig',
186
            [
187
                'project' => $project,
188
                'providers' => Provider::getOptions(),
189
            ]
190
        );
191
    }
192
193
    /**
194
     * Prepare a deployment
195
     *
196
     * @author Ronan Chilvers <[email protected]>
197
     */
198
    public function prepareDeploy(
199
        ServerRequestInterface $request,
200
        ResponseInterface $response,
201
        $args
202
    ) {
203
        if (!$project = $this->projectFromArgs($args)) {
204
            return $response->withRedirect(
205
                Router::pathFor('project.index')
206
            );
207
        }
208
209
        return View::render(
210
            $response,
211
            'project/prepare-deploy.html.twig',
212
            [
213
                'project' => $project,
214
            ]
215
        );
216
    }
217
218
    /**
219
     * Trigger a deploy for a project
220
     *
221
     * @author Ronan Chilvers <[email protected]>
222
     */
223
    public function deploy(
224
        ServerRequestInterface $request,
225
        ResponseInterface $response,
226
        $args
227
    ) {
228
        try {
229
            if (!$project = $this->projectFromArgs($args)) {
230
                return $response->withRedirect(
231
                    Router::pathFor('project.index')
232
                );
233
            }
234
            $input  = $request->getParsedBodyParam('project', []);
0 ignored issues
show
Bug introduced by
The method getParsedBodyParam() does not exist on Psr\Http\Message\ServerRequestInterface. Did you maybe mean getParsedBody()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

234
            /** @scrutinizer ignore-call */ 
235
            $input  = $request->getParsedBodyParam('project', []);

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...
235
            $branch = (!isset($input['branch']) || empty($input['branch'])) ? 'master' : $input['branch'];
236
            $provider = Provider::forProject(
237
                $project
238
            );
239
            Orm::transaction(function() use ($project, $provider, $branch, $response) {
240
                $deployment = Orm::finder(Deployment::class)->nextForProject(
241
                    $project
242
                );
243
                $deployment->source = Security::email();
244
                if (!$deployment->save()) {
245
                    Log::debug('Unable to create new deployment object', [
246
                        'project' => $project->toArray(),
247
                    ]);
248
                    throw new RuntimeException('Unable to create new deployment');
249
                }
250
                $finder = Orm::finder(Event::class);
251
                $head = $provider->getHeadInfo(
252
                    $project->repository,
253
                    $branch,
254
                    function($type, $detail = '') use ($finder, $deployment) {
255
                        $finder->event(
256
                            $type,
257
                            $deployment,
258
                            'Initialise',
259
                            $detail
260
                        );
261
                    }
262
                );
263
                Log::debug('Updating deployment commit information', $head);
264
                $deployment->sha       = $head['sha'];
265
                $deployment->author    = $head['author'];
266
                $deployment->committer = $head['committer'];
267
                $deployment->message   = $head['message'];
268
                if (!$deployment->save()) {
269
                    return $response->withRedirect(
270
                        Router::pathFor('project.view', [
271
                            'key' => $project->key
272
                        ])
273
                    );
274
                }
275
                if (!$project->markDeploying()) {
276
                    throw new RuntimeException('Unable to mark project as deploying');
277
                }
278
                Queue::dispatch(
279
                    new DeployJob($deployment)
280
                );
281
            });
282
283
            Session::flash([
284
                'heading' => 'Deploy queued successfully'
285
            ]);
286
        } catch (Exception $ex) {
287
            $message = [$ex->getMessage()];
288
            if ($previous = $ex->getPrevious()) {
289
                $message[] = $previous->getMessage();
290
            }
291
            $message = implode(' - ', $message);
292
            Session::flash(
293
                [
294
                    'heading' => 'Failed to initialise new deployment',
295
                    'content' => $message,
296
                ],
297
                'error'
298
            );
299
            Log::error('Failed to initialise new deployment', [
300
                'exception' => $ex,
301
            ]);
302
        }
303
304
        return $response->withRedirect(
305
            Router::pathFor('project.view', [
306
                'key' => $project->key
307
            ])
308
        );
309
    }
310
311
    /**
312
     * Trigger a deploy for a project
313
     *
314
     * @author Ronan Chilvers <[email protected]>
315
     */
316
    public function redeploy(
317
        ServerRequestInterface $request,
318
        ResponseInterface $response,
319
        $args
320
    ) {
321
        try {
322
            if (!$project = $this->projectFromArgs($args)) {
323
                return $response->withRedirect(
324
                    Router::pathFor('project.index')
325
                );
326
            }
327
            Orm::transaction(function() use ($project, $args) {
328
                $dummy = Orm::finder(Deployment::class)->nextForProject(
329
                    $project
330
                );
331
                $original = Orm::finder(Deployment::class)->one(
332
                    $args['deployment']
333
                );
334
                if (!$original instanceof Deployment) {
335
                    throw new RuntimeException('Invalid attempt to re-deploy non-existant deployment');
336
                }
337
                $deployment           = clone $original;
338
                $deployment->original = $original;
339
                $deployment->number   = $dummy->number;
340
                if (!$deployment->save()) {
341
                    Log::debug('Unable to create deployment object', [
342
                        'project' => $project->toArray(),
343
                    ]);
344
                    throw new RuntimeException('Unable to create new deployment');
345
                }
346
                if (!$project->markDeploying()) {
347
                    throw new RuntimeException('Unable to mark project as deploying');
348
                }
349
                Queue::dispatch(
350
                    new ReactivateJob($original, $deployment)
351
                );
352
            });
353
            Session::flash([
354
                'heading' => 'Re-deploy queued successfully'
355
            ]);
356
        } catch (Exception $ex) {
357
            Session::flash(
358
                [
359
                    'heading' => 'Failed to initialise re-deployment',
360
                    'content' => $ex->getMessage(),
361
                ],
362
                'error'
363
            );
364
            Log::error('Failed to initialise re-deployment', [
365
                'exception' => $ex,
366
            ]);
367
        }
368
369
        return $response->withRedirect(
370
            Router::pathFor('project.view', [
371
                'key' => $project->key
372
            ])
373
        );
374
    }
375
}
376