GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 7dd1a3...36003d )
by Sam
03:06
created

Module::createBuildContext()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 52
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 5.0655

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 52
ccs 25
cts 29
cp 0.8621
rs 8.6868
cc 5
eloc 29
nc 10
nop 0
crap 5.0655

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace SamIT\Yii2\PhpFpm;
5
6
use Docker\Context\Context;
7
use Docker\Context\ContextBuilder;
8
use yii\base\InvalidConfigException;
9
use yii\base\UnknownPropertyException;
10
use yii\helpers\ArrayHelper;
11
use yii\helpers\Console;
12
use yii\mutex\Mutex;
13
14
/**
15
 * Class Module
16
 * @package SamIT\Yii2\PhpFpm
17
 * @property-write string[] $additionalPackages
18
 * @property-write string[] $additionalExtensions
19
 * @property-write string|int[] $additionalPoolConfig
20
 * @property-write string[] $additionalPhpConfig
21
 * @property-write string[] $additionalFpmConfig
22
 */
23
class Module extends \yii\base\Module
24
{
25
26
    /**
27
     * @var bool Whether the container should attempt to run migrations on launch.
28
     */
29
    public $runMigrations = false;
30
31
    /**
32
     * @var bool whether migrations should acquire a lock.
33
     * It must be configured in the 'mutex' component of this module or the application
34
     * Note that this mutex must be shared between all instances of your application.
35
     * Consider using something like redis or mysql mutex.
36
     */
37
    public $migrationsUseMutex = true;
38
39
    /**
40
     * The variables will be written to /runtime/env.json as JSON, where your application can read them.
41
     * @var string[] List of required environment variables. If one is missing the container will exit.
42
     *
43
     */
44
    public $environmentVariables = [];
45
46
    /**
47
     * @var array Pool directives
48
     * @see http://php.net/manual/en/install.fpm.configuration.php
49
     *
50
     */
51
    public $poolConfig = [
52
        'user' => 'nobody',
53
        'group' => 'nobody',
54
        'listen' => 9000,
55
        'pm' => 'dynamic',
56
        'pm.max_children' => 40,
57
        'pm.start_servers' => 3,
58
        'pm.min_spare_servers' => 1,
59
        'pm.max_spare_servers' => 3,
60
        'access.log' => '/proc/self/fd/2',
61
        'clear_env' => 'yes',
62
        'catch_workers_output' => 'yes'
63
    ];
64
65
    /**
66
     * @var array PHP configuration, supplied via php_admin_value in fpm config.
67
     */
68
    public $phpConfig = [
69
        'upload_max_filesize' => '20M',
70
        'post_max_size' => '25M'
71
    ];
72
73
    /**
74
     * @var array Global directives
75
     * @see http://php.net/manual/en/install.fpm.configuration.php
76
     *
77
     */
78
    public $fpmConfig = [
79
        'error_log' => '/proc/self/fd/2',
80
        'daemonize' => 'no',
81
    ];
82
83
    /**
84
     * List of OS packages to install
85
     */
86
    public $packages = [
87
        'php7',
88
        'php7-fpm',
89
        'tini',
90
        'ca-certificates',
91
        /**
92
         * @see https://stedolan.github.io/jq/
93
         * This is used for converting the env to JSON.
94
         */
95
        'jq'
96
    ];
97
98
    /**
99
     * List of php extensions to install
100
     */
101
    public $extensions = [
102
        'ctype',
103
        'gd',
104
        'iconv',
105
        'intl',
106
        'json',
107
        'mbstring',
108
        'session',
109
        'pdo_mysql',
110
        'session',
111
        'curl'
112
    ];
113
114
    /**
115
     * @var string The name of the created image.
116
     */
117
    public $image;
118
119
    /**
120
     * @var string The tag of the created image.
121
     */
122
    public $tag = 'latest';
123
124
    /**
125
     * @var bool wheter to push successful builds.
126
     */
127
    public $push = false;
128
129
    /**
130
     * @var string Location of composer.json / composer.lock
131
     */
132
    public $composerFilePath = '@app/../';
133
    /**
134
     * @return string A PHP-FPM config file.
135
     */
136 3
    protected function createFpmConfig()
137
    {
138 3
        $config = [];
139
        // Add global directives.
140 3
        $config[] = '[global]';
141 3
        foreach ($this->fpmConfig as $key => $value) {
142 3
            $config[] = "$key = $value";
143
        }
144
145
        // Add pool directives.
146 3
        $poolConfig = $this->poolConfig;
147 3
        foreach($this->phpConfig as $key => $value) {
148 3
            $poolConfig["php_admin_value[$key]"] = $value;
149
        }
150
151 3
        $config[] = '[www]';
152 3
        foreach ($poolConfig as $key => $value) {
153 3
            $config[] = "$key = $value";
154
        }
155
156 3
        return \implode("\n", $config);
157
    }
158
159
    /**
160
     * @return string A shell script that checks for existence of (non-empty) variables and runs php-fpm.
161
     */
162 3
    protected function createEntrypoint(): string
163
    {
164
        // Get the route.
165 3
        $route = "{$this->getUniqueId()}/migrate/up";
166 3
        $script = "/project/{$this->getConsoleEntryScript()}";
167 3
        $result = [];
168 3
        $result[] = '#!/bin/sh';
169
        // Check for variables.
170 3
        foreach($this->environmentVariables as $name) {
171
            $result[] = \strtr('if [ -z "${name}" ]; then echo "Variable \${name} is required."; exit 1; fi', [
172
                '{name}' => $name
173
            ]);
174
        }
175
176
        // Check if runtime directory is writable.
177 3
        $result[] = <<<SH
178
    su nobody -s /bin/touch /runtime/testfile && rm /runtime/testfile;
179
    if [ $? -ne 0 ]; then
180
      echo Runtime directory is not writable;
181
      exit 1
182
    fi
183
SH;
184
185
186
187
        // Check if runtime is a tmpfs.
188 3
        $message = Console::ansiFormat('/runtime should really be a tmpfs.', [Console::FG_RED]);
189 3
        $result[] = <<<SH
190
mount | grep '/runtime type tmpfs';
191
if [ $? -ne 0 ]; then
192 3
  echo $message; 
193
fi
194
SH;
195 3
        $result[] = 'jq -n env > /runtime/env.json';
196
197 3
        if ($this->runMigrations) {
198
            $result[] = <<<SH
199
ATTEMPTS=0
200
while [ \$ATTEMPTS -lt 10 ]; do
201
  # First run migrations.
202
  $script $route --interactive=0
203
  if [ $? -eq 0 ]; then
204
    echo "Migrations done";
205
    break;
206
  fi
207
  echo "Failed to run migrations, retrying in 10s.";
208
  sleep 10;
209
  let ATTEMPTS=ATTEMPTS+1
210
done
211
212
if [ \$ATTEMPTS -gt 9 ]; then
213
  echo "Migrations failed.."
214
  exit 1;
215
fi
216
SH;
217
        }
218
219 3
        $result[] = 'exec php-fpm7 --force-stderr --fpm-config /php-fpm.conf';
220 3
        return \implode("\n", $result);
221
    }
222
223 3
    public function createBuildContext(): Context
224
    {
225 3
        $builder = new ContextBuilder();
226
227
        /**
228
         * BEGIN COMPOSER
229
         */
230 3
        $builder->from('composer');
231 3
        $builder->addFile('/build/composer.json', \Yii::getAlias($this->composerFilePath) .'/composer.json');
232 3
        if (\file_exists(\Yii::getAlias($this->composerFilePath) . '/composer.lock')) {
233 3
            $builder->addFile('/build/composer.lock', \Yii::getAlias($this->composerFilePath) . '/composer.lock');
234
        }
235
236 3
        $builder->run('cd /build && composer install --no-dev --no-autoloader --ignore-platform-reqs --prefer-dist && rm -rf /root/.composer');
237
238
239
        // Add the actual source code.
240 3
        $root = \Yii::getAlias('@app');
241 3
        if (!\is_string($root)) {
242
            throw new \Exception('Alias @app must be defined.');
243
        }
244
245 3
        $builder->addFile('/build/' . \basename($root), $root);
246 3
        $builder->run('cd /build && composer dumpautoload -o');
247
        /**
248
         * END COMPOSER
249
         */
250
251
252 3
        $builder->from('alpine:edge');
253 3
        $packages = $this->packages;
254
255 3
        foreach ($this->extensions as $extension) {
256
            $packages[] = "php7-$extension";
257
        }
258 3
        $builder->run('apk add --update --no-cache ' . \implode(' ', $packages));
259 3
        $builder->run('mkdir /runtime && chown nobody:nobody /runtime');
260 3
        $builder->volume('/runtime');
261 3
        $builder->copy('--from=0 /build', '/project');
262 3
        $builder->add('/entrypoint.sh', $this->createEntrypoint());
263 3
        $builder->run('chmod +x /entrypoint.sh');
264 3
        $builder->add('/php-fpm.conf', $this->createFpmConfig());
265 3
        $builder->run("php-fpm7 --force-stderr --fpm-config /php-fpm.conf -t");
266 3
        $builder->entrypoint('["/sbin/tini", "--", "/entrypoint.sh"]');
267
268
        // Test if we can run a console command.
269 3
        if (stripos($this->getConsoleEntryScript(), 'codecept') == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing stripos($this->getConsol...ryScript(), 'codecept') of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
270
            $script = "[ -f /project/{$this->getConsoleEntryScript()} ]";
271
            $builder->run($script);
272
        }
273 3
        return $builder->getContext();
274
    }
275
276 3
    public function getLock(int $timeout = 0)
277
    {
278 3
        if ($this->has('mutex')) {
279 1
            $mutex = $this->get('mutex');
280 1
            if ($mutex instanceof Mutex
281 1
                && $mutex->acquire(__CLASS__, $timeout)
282
            ) {
283
                \register_shutdown_function(function() use ($mutex): void {
284
                    $mutex->release(__CLASS__);
285 1
                });
286 1
                return true;
287
            }
288
        }
289 3
        return false;
290
    }
291
292
    /**
293
     * @throws InvalidConfigException in case the app is not configured as expected
294
     * @return string the relative path of the (console) entry script with respect to the project (not app) root.
295
     */
296 3
    public function getConsoleEntryScript(): string
297
    {
298 3
        $full = \array_slice(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), -1)[0]['file'];
299 3
        $relative = \strtr($full, [\dirname(\Yii::getAlias('@app')) => '']);
300 3
        if ($relative === $full){
301
            throw new InvalidConfigException("The console entry script must be located inside the @app directory.");
302
        }
303 3
        return \ltrim($relative, '/');
304
    }
305
306
307 1
    public function __set($name, $value): void
308
    {
309 1
        if (\strncmp($name, 'additional', 10) === 0) {
310 1
            $this->add(\lcfirst(\substr($name, 10)), $value);
311
        } else {
312
            parent::__set($name, $value);
313
        }
314 1
    }
315
316 1
    private function add($name, array $value): void
317
    {
318 1
        if (!\property_exists($this, $name)) {
319
            throw new UnknownPropertyException("Unknown property $name");
320
        }
321 1
        $this->$name = ArrayHelper::merge($this->$name, $value);
322 1
    }
323
}
324