Passed
Push — master ( 709665...38fa98 )
by Emmanuel
04:15
created

RoboFile::startPHP()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 16
nc 4
nop 2
1
<?php
2
/**
3
 * This is project's console commands configuration for Robo task runner.
4
 *
5
 * @see http://robo.li/
6
 */
7
8
class RoboFile extends \Robo\Tasks
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
9
{
10
    /**
11
     * A test command just to make sure robo works on that computer
12
     */
13
    public function dockertest()
14
    {
15
        $this->stopOnFail(true);
16
17
        $this->taskDockerStop('robo_test')->run();
18
19
        $this->taskDockerRun('edyan/php:7.1')
20
             ->name('robo_test')
21
             ->detached()
22
             ->option('--rm')
23
             ->run();
24
25
        $this->taskDockerExec('robo_test')
26
             ->interactive()
27
             ->exec($this->taskExec('php -v'))
28
             ->run();
29
30
        $this->taskDockerStop('robo_test')->run();
31
    }
32
33
34
    /**
35
     * Run All Unit Test
36
     * @param  array  $opts
37
     */
38
    public function test(
39
        $opts = ['php' => '7.1', 'db' => 'mysql', 'keep-cts' => false, 'wait' => 5]
40
    ) {
41
        $this->stopOnFail(true);
42
43
        $this->setupDocker($opts['php'], $opts['db'], $opts['wait']);
44
45
        // Run the tests
46
        $this->taskDockerExec('robo_php')
47
            ->interactive()
48
            ->option('--user', 'www-data')
49
            ->exec($this->taskExec('/bin/bash -c "cd /var/www/html ; vendor/bin/phpunit"'))
50
            ->run();
51
52
        if ($opts['keep-cts'] === false) {
53
            $this->destroyDocker();
54
        }
55
    }
56
57
58
    /**
59
     * Build an executable phar
60
     */
61
    public function phar()
62
    {
63
        // Create a collection builder to hold the temporary
64
        // directory until the pack phar task runs.
65
        $collection = $this->collectionBuilder();
66
        $workDir = $collection->tmpDir();
67
        $buildDir = "$workDir/neuralyzer";
68
69
        $prepTasks = $this->collectionBuilder();
70
        $preparationResult = $prepTasks
71
            ->taskFilesystemStack()
72
                ->mkdir($workDir)
73
                ->taskCopyDir([__DIR__ . '/src' => $buildDir . '/src'])
74
            ->taskFilesystemStack()
75
                ->copy(__DIR__ . '/bin/neuralyzer', $buildDir . '/bin/neuralyzer')
76
                ->copy(__DIR__ . '/composer.json', $buildDir . '/composer.json')
77
                ->copy(__DIR__ . '/composer.lock', $buildDir . '/composer.lock')
78
                ->copy(__DIR__ . '/LICENSE', $buildDir . '/LICENSE')
79
                ->copy(__DIR__ . '/README.md', $buildDir . '/README.md')
80
81
            ->taskComposerInstall()
82
                ->dir($buildDir)
83
                ->noDev()
84
                ->noScripts()
85
                ->printOutput(true)
86
                ->optimizeAutoloader()
87
                ->run();
88
89
        // Exit if the preparation step failed
90
        if (!$preparationResult->wasSuccessful()) {
91
            return $preparationResult;
92
        }
93
94
        // Decide which files we're going to pack
95
        $files = \Symfony\Component\Finder\Finder::create()->ignoreVCS(true)
96
            ->files()
97
            ->name('*.php')
98
            ->name('*.exe') // for 1symfony/console/Resources/bin/hiddeninput.exe
99
            ->path('src')
100
            ->path('vendor')
101
            ->notPath('docs')
102
            ->notPath('/vendor\/.*\/[Tt]est/')
103
            ->in(is_dir($buildDir) ? $buildDir : __DIR__);
104
105
        // Build the phar
106
        return $collection
107
            ->taskPackPhar('neuralyzer.phar')
108
                ->compress()
109
                ->addFile('bin/neuralyzer', 'bin/neuralyzer')
110
                ->addFiles($files)
111
                ->executable('bin/neuralyzer')
112
            ->taskFilesystemStack()
113
                ->chmod(__DIR__ . '/neuralyzer.phar', 0755)
114
            ->run();
115
    }
116
117
118
    public function release()
119
    {
120
        $this->stopOnFail(true);
121
122
        $version = null;
123
        $currentVersion = \Edyan\Neuralyzer\Console\Application::VERSION;
124
        while (empty($version)) {
125
            $version = $this->ask("Whats the version number ? (current : $currentVersion)");
126
        }
127
        $this->say("Preparing version $version");
128
129
        // Verify there is no file changed
130
        $modifiedFiles = $this->taskGitStack()->exec('git status -s')->run();
131
var_dump($modifiedFiles); die();
0 ignored issues
show
Security Debugging Code introduced by
var_dump($modifiedFiles); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
Coding Style Compatibility introduced by
The method release() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
132
        // Verify everything is pulled
133
return;
0 ignored issues
show
Unused Code introduced by
return; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
134
        // Patch the right files
135
        $this->taskReplaceInFile(__DIR__ . '/src/Console/Application.php')
0 ignored issues
show
Unused Code introduced by
$this->taskReplaceInFile...'{$version}';")->run(); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
136
             ->from("const VERSION = '$currentVersion';")
137
             ->to("const VERSION = '$version';")
138
             ->run();
139
140
        // Commit a bump version
141
142
        // Create a tag
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% 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...
143
/*
144
        $this->taskGitHubRelease($version)
145
          ->uri('consolidation-org/Robo')
146
          ->description('Add stuff people need.')
147
          ->change('Fix #123')
148
          ->change('Add frobulation method to all widgets')
149
          ->run();
150
*/
151
152
        $this->say('Release ready, you can push');
153
    }
154
155
156
    private function setupDocker(
157
        string $php = '7.1',
158
        string $dbType = 'mysql',
159
        int $wait = 10
160
    ) {
161
        $this->destroyDocker();
162
163
        if (!in_array($dbType, ['mysql', 'postgres', 'sqlsrv'])) {
164
            throw new \InvalidArgumentException('Database can be only mysql, postgres or sqlsrv');
165
        }
166
167
        $this->startDb($dbType);
168
        $this->say("Waiting $wait seconds $dbType to start");
169
        sleep($wait);
170
        // Now create a DB For SQL Server as there is no option in the docker image
171
        if ($dbType === 'sqlsrv') {
172
            $this->createSQLServerDB();
173
        }
174
175
        $this->startPHP($php, $dbType);
176
    }
177
178
    private function startDb($type)
179
    {
180
        $image = $type;
181
        if ($type === 'sqlsrv') {
182
            $image = 'microsoft/mssql-server-linux:2017-latest';
183
        }
184
185
        $dbCt = $this->taskDockerRun($image)->detached()->name('robo_db')->option('--rm');
186
        if ($type === 'mysql') {
187
            $dbCt = $dbCt->env('MYSQL_ROOT_PASSWORD', 'rootRoot44root')->env('MYSQL_DATABASE', 'test_db');
188
        } elseif ($type === 'postgres') {
189
            $dbCt = $dbCt->env('POSTGRES_PASSWORD', 'rootRoot44root')->env('POSTGRES_DB', 'test_db');
190
        } elseif ($type === 'sqlsrv') {
191
            $dbCt = $dbCt->env('ACCEPT_EULA', 'Y')->env('SA_PASSWORD', 'rootRoot44root');
192
        }
193
194
        $dbCt->run();
195
    }
196
197
198
    private function createSQLServerDB()
199
    {
200
        $createSqlQuery = '/opt/mssql-tools/bin/sqlcmd -U sa -P rootRoot44root ';
201
        $createSqlQuery.= '-S localhost -Q "CREATE DATABASE test_db"';
202
        $this->taskDockerExec('robo_db')
203
             ->interactive()
204
             ->exec($this->taskExec($createSqlQuery))
205
             ->run();
206
    }
207
208
209
    private function startPHP(string $version, string $dbType)
210
    {
211
        if (!in_array($version, ['7.1', '7.2'])) {
212
            throw new \InvalidArgumentException('PHP Version must be 7.1 or 7.2');
213
        }
214
215
        $dbUser = 'root';
216
        if ($dbType === 'postgres') {
217
            $dbUser = 'postgres';
218
        } elseif ($dbType === 'sqlsrv') {
219
            $dbUser = 'sa';
220
        }
221
222
        $this->taskDockerRun('edyan/php:' . $version . '-sqlsrv')
223
            ->detached()->name('robo_php')->option('--rm')
224
            ->env('FPM_UID', getmyuid())->env('FPM_GID', getmygid())
225
            ->env('DB_HOST', 'robo_db')->env('DB_DRIVER', $dbType)
226
            ->env('DB_PASSWORD', 'rootRoot44root')->env('DB_USER', $dbUser)
227
            ->volume(__DIR__, '/var/www/html')
228
            ->link('robo_db', 'robo_db')
229
            ->run();
230
    }
231
232
233
    private function destroyDocker()
234
    {
235
        $cts = ['robo_db', 'robo_php'];
236
        foreach ($cts as $ct) {
237
            $this->stopContainer($ct);
238
        }
239
    }
240
241
242
    private function stopContainer(string $ct)
243
    {
244
        $process = new \Symfony\Component\Process\Process("docker ps | grep $ct | wc -l");
245
        $process->run();
246
247
        if ((int)$process->getOutput() === 0) {
248
            return;
249
        }
250
251
        $this->say('Destroying container ' . $ct);
252
        $this->taskDockerStop($ct)->run();
253
    }
254
}
255