Completed
Push — master ( 25f226...cc0a72 )
by Morgan
03:23
created

DeployController::composer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 14
ccs 11
cts 11
cp 1
rs 9.4286
cc 1
eloc 11
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Morphatic\AutoDeploy\Controllers;
4
5
use Log;
6
use Mail;
7
use Monolog\Logger;
8
use Illuminate\Http\Request;
9
use Illuminate\Routing\Controller;
10
use AdamBrett\ShellWrapper\Command\Builder as Command;
11
use AdamBrett\ShellWrapper\Command\CommandInterface;
12
use AdamBrett\ShellWrapper\Runners\Exec;
13
use Monolog\Formatter\HtmlFormatter;
14
use Monolog\Handler\SwiftMailerHandler;
15
use Morphatic\AutoDeploy\Origins\OriginInterface;
16
17
class DeployController extends Controller
18
{
19
    /**
20
     * The origin of the webhook request.
21
     *
22
     * @var Morphatic\AutoDeploy\Origins\OriginInterface
23
     */
24
    private $origin;
25
26
    /**
27
     * The URL of the repo to be cloned.
28
     *
29
     * @var string
30
     */
31
    private $repo_url;
0 ignored issues
show
Coding Style introduced by
$repo_url does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
32
33
    /**
34
     * The absolute path of the directory on the server that contains the project.
35
     *
36
     * @var string
37
     */
38
    private $webroot;
39
40
    /**
41
     * The absolute path of the directory where the new deployment will be set up.
42
     *
43
     * @var string
44
     */
45
    private $install_dir;
0 ignored issues
show
Coding Style introduced by
$install_dir does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
46
47
    /**
48
     * A log of the results of the entire deploy process.
49
     *
50
     * @var Monolog\Logger
51
     */
52
    private $log;
53
54
    /**
55
     * The commit ID for this commit.
56
     *
57
     * @var string
58
     */
59
    private $commit_id;
0 ignored issues
show
Coding Style introduced by
$commit_id does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
60
61
    /**
62
     * The commit ID for this commit.
63
     *
64
     * @var AdamBrett\ShellWrapper\Runners\Exec
65
     */
66
    private $shell;
67
68
    /**
69
     * The result of this commit.
70
     *
71
     * @var array
72
     */
73
    private $result;
74
75
    /**
76
     * Create a new DeployController instance.
77
     *
78
     * @param Morphatic\AutoDeploy\Origins\OriginInterface $origin The origin of the webhook
1 ignored issue
show
Documentation introduced by
Should the type for parameter $origin not be OriginInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
79
     * @param AdamBrett\ShellWrapper\Runners\Exec          $exec   The shell command execution class
1 ignored issue
show
Documentation introduced by
Should the type for parameter $exec not be Exec?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
80
     */
81 36
    public function __construct(OriginInterface $origin, Exec $exec)
82
    {
83
        // set class variables related to the webhook origin
84 36
        $this->origin = $origin;
1 ignored issue
show
Documentation Bug introduced by
It seems like $origin of type object<Morphatic\AutoDep...rigins\OriginInterface> is incompatible with the declared type object<Morphatic\AutoDep...rigins\OriginInterface> of property $origin.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
85 36
        $this->repo_url = $this->origin->getRepoUrl();
86 36
        $this->commit_id = $this->origin->getCommitId();
87
88
        // create an instance of the shell exec
89 36
        $this->shell = $exec;
1 ignored issue
show
Documentation Bug introduced by
It seems like $exec of type object<AdamBrett\ShellWrapper\Runners\Exec> is incompatible with the declared type object<Morphatic\AutoDep...llWrapper\Runners\Exec> of property $shell.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
90 36
    }
91
92
    /**
93
     * Handles incoming webhook requests.
94
     */
95 12
    public function index()
96
    {
97
        // get the parameters for the event we're handling
98 12
        $config_key = "auto-deploy.{$this->origin->name}.{$this->origin->event()}";
0 ignored issues
show
Coding Style introduced by
$config_key does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
99 12
        $this->webroot = config("$config_key.webroot");
0 ignored issues
show
Coding Style introduced by
$config_key does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
100 12
        $this->install_dir = dirname($this->webroot).'/'.date('Y-m-d').'_'.$this->commit_id;
101 12
        $steps = config("$config_key.steps");
0 ignored issues
show
Coding Style introduced by
$config_key does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
102
103
        // set up logging to email
104 12
        $domain = parse_url(config('app.url'), PHP_URL_HOST);
105 12
        $msg = \Swift_Message::newInstance('Project Deployed')
106 12
                ->setFrom(["do_not_reply@$domain" => 'Laravel Auto-Deploy[$domain]'])
107 12
                ->setTo(config('auto-deploy.notify'))
108 12
                ->setBody('', 'text/html');
109 12
        $handler = new SwiftMailerHandler(Mail::getSwiftMailer(), $msg, Logger::NOTICE);
110 12
        $handler->setFormatter(new HtmlFormatter());
111 12
        $this->log = Log::getMonolog();
112 12
        $this->log->pushHandler($handler);
113
114
        // execute the configured steps
115 12
        $this->result = [
116 12
            'Commit_ID' => $this->commit_id,
117 12
            'Timestamp' => date('r'),
118 12
            'output' => '',
119
        ];
120 12
        $whitelist = ['backupDatabase','pull','composer','npm','migrate','seed','deploy'];
121 12
        foreach ($steps as $step) {
122 12
            if (in_array($step, $whitelist) && !$this->{$step}()) {
0 ignored issues
show
Security Code Execution introduced by
$step can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
123 4
                $this->log->error('Deploy failed.', $this->result);
124
125 8
                return;
126
            }
127 5
        }
128 8
        $this->log->notice('Deploy succeeded!', $this->result);
129 8
    }
130
131
    /**
132
     * Runs a shell command, logs, and handles the result.
133
     *
134
     * @param AdamBrett\ShellWrapper\CommandInterface $cmd The text of the command to be run
1 ignored issue
show
Documentation introduced by
Should the type for parameter $cmd not be CommandInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
135
     *
136
     * @return bool True if the command was successful, false on error
137
     */
138 12
    private function ex(CommandInterface $cmd)
1 ignored issue
show
Coding Style introduced by
function ex() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
139
    {
140
        // try to run the command
141 12
        $this->shell->run($cmd);
142 12
        $output = $this->shell->getOutput();
143 12
        $return_var = $this->shell->getReturnValue();
0 ignored issues
show
Coding Style introduced by
$return_var does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
144
145
        // record the result
146 12
        $output = count($output) ? implode("\n", $output)."\n" : '';
147 12
        $this->result['output'] .= "$cmd\n$output";
148
149
        // return a boolean
150 12
        return 0 === $return_var;
0 ignored issues
show
Coding Style introduced by
$return_var does not seem to conform to the naming convention (^[a-z][a-zA-Z0-9]*$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
151
    }
152
153
    /**
154
     * Backup the database.
155
     *
156
     * @return bool True if the database was successfully backed up. False on error.
157
     */
158 12
    private function backupDatabase()
1 ignored issue
show
Coding Style introduced by
function backupDatabase() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
159
    {
160
        // get the name of the DB to backed up and the connection to use
161 12
        $dbdir = database_path();
162 12
        $dbconn = config('database.default');
163 12
        $dbname = config("database.connections.$dbconn.database");
164
165
        // make a directory for the backup file and switch into that directory
166 12
        $cmd = new Command('cd');
167 12
        $cmd->addParam($dbdir)
168 12
            ->addSubCommand('&&')
169 12
            ->addSubCommand('mkdir')
170 12
            ->addParam('backups');
171 12
        if ($this->ex($cmd)) {
172 12
            $cmd = new Command('cd');
173 12
            $cmd->addParam($dbdir.'/backups')
174 12
                ->addSubCommand('&&');
175
            switch ($dbconn) {
176 12
                case 'sqlite':
177 2
                    $cmd->addSubCommand('cp');
178 2
                    $cmd->addParam($dbname)
179 2
                        ->addParam('.');
180
181 2
                    return $this->ex($cmd);
182 5
                case 'mysql':
183 6
                    $cmd->addSubCommand('mysqldump');
184 6
                    $cmd->addParam($dbname)
185 6
                        ->addParam('>')
186 6
                        ->addParam("$dbname.sql");
187
188 6
                    return $this->ex($cmd);
189 3
                case 'pgsql':
190 2
                    $cmd->addSubCommand('pg_dump');
191 2
                    $cmd->addParam($dbname)
192 2
                        ->addParam('>')
193 2
                        ->addParam("$dbname.sql");
194
195 2
                    return $this->ex($cmd);
196
            }
197 1
        }
198
199 2
        return false;
200
    }
201
202
    /**
203
     * Create a new directory parallel to the webroot and clone the project into that directory.
204
     *
205
     * @return bool True if the clone is successful. False otherwise.
206
     */
207 10
    private function pull()
1 ignored issue
show
Coding Style introduced by
function pull() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
208
    {
209 10
        if (is_writable(dirname($this->install_dir))) {
210 8
            $cmd = new Command('mkdir');
211 8
            $cmd->addFlag('p')
212 8
                ->addParam($this->install_dir);
213 8
            if ($this->ex($cmd)) {
214 8
                $cmd = new Command('cd');
215 8
                $cmd->addParam($this->install_dir)
216 8
                    ->addSubCommand('&&')
217 8
                    ->addSubCommand('git')
218 8
                    ->addSubCommand('clone')
219 8
                    ->addParam($this->repo_url)
220 8
                    ->addParam('.');
221
222 8
                return $this->ex($cmd);
223
            }
224
        }
225
226 2
        return false;
227
    }
228
229
    /**
230
     * Update composer and run composer update.
231
     *
232
     * @return bool True if the update is successful. False otherwise.
233
     */
234 8
    private function composer()
1 ignored issue
show
Coding Style introduced by
function composer() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
235
    {
236 8
        $cmd = new Command('cd');
237 8
        $cmd->addParam($this->install_dir)
238 8
            ->addSubCommand('&&')
239 8
            ->addSubCommand('composer')
240 8
            ->addParam('self-update')
241 8
            ->addSubCommand('&&')
242 8
            ->addSubCommand('composer')
243 8
            ->addParam('update')
244 8
            ->addArgument('no-interaction');
245
246 8
        return $this->ex($cmd);
247
    }
248
249
    /**
250
     * Run npm update.
251
     *
252
     * @return bool True if npm is successful. False otherwise.
253
     */
254 8
    private function npm()
1 ignored issue
show
Coding Style introduced by
function npm() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
255
    {
256 8
        $cmd = new Command('cd');
257 8
        $cmd->addParam($this->install_dir)
258 8
            ->addSubCommand('&&')
259 8
            ->addSubCommand('npm')
260 8
            ->addParam('update');
261
262 8
        return $this->ex($cmd);
263
    }
264
265
    /**
266
     * Run any necessary database migrations.
267
     *
268
     * @return bool True if the migration is successful. False otherwise.
269
     */
270 8
    private function migrate()
1 ignored issue
show
Coding Style introduced by
function migrate() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
271
    {
272 8
        $cmd = new Command('cd');
273 8
        $cmd->addParam($this->install_dir)
274 8
            ->addSubCommand('&&')
275 8
            ->addSubCommand('php')
276 8
            ->addSubCommand('artisan')
277 8
            ->addParam('migrate')
278 8
            ->addArgument('force')
279 8
            ->addArgument('no-interaction');
280
281 8
        return $this->ex($cmd);
282
    }
283
284
    /**
285
     * Run any necessary database migrations.
286
     *
287
     * @return bool True if the migration is successful. False otherwise.
288
     */
289 8
    private function seed()
1 ignored issue
show
Coding Style introduced by
function seed() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
290
    {
291 8
        $cmd = new Command('cd');
292 8
        $cmd->addParam($this->install_dir)
293 8
            ->addSubCommand('&&')
294 8
            ->addSubCommand('php')
295 8
            ->addSubCommand('artisan')
296 8
            ->addParam('db:seed');
297
298 8
        return $this->ex($cmd);
299
    }
300
301
    /**
302
     * Symlinks the new deploy directory to the webroot.
303
     *
304
     * @return bool True if the symlink is successful. False otherwise.
305
     */
306 8
    private function deploy()
1 ignored issue
show
Coding Style introduced by
function deploy() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
307
    {
308 8
        $cmd = new Command('cd');
309 8
        $cmd->addParam(dirname($this->webroot))
310 8
            ->addSubCommand('&&')
311 8
            ->addSubCommand('ln')
312 8
            ->addFlag('fs')
313 8
            ->addParam($this->install_dir)
314 8
            ->addParam($this->webroot);
315
316 8
        return $this->ex($cmd);
317
    }
318
}
319