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 ( 4d52fb...40ae8e )
by Sam
01:27
created

Module::createBuildContext()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 53
ccs 27
cts 27
cp 1
rs 9.0254
c 0
b 0
f 0
cc 3
nc 3
nop 3
crap 3

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 SamIT\Docker\Context;
7
use yii\base\InvalidConfigException;
8
use yii\base\UnknownPropertyException;
9
use yii\helpers\ArrayHelper;
10
use yii\helpers\Console;
11
12
/**
13
 * Class Module
14
 * @package SamIT\Yii2\PhpFpm
15
 * @property-write string[] $additionalExtensions
16
 * @property-write string|int[] $additionalPoolConfig
17
 * @property-write string[] $additionalPhpConfig
18
 * @property-write string[] $additionalFpmConfig
19
 */
20
class Module extends \yii\base\Module
21
{
22
    /**
23
     * The variables will be written to /runtime/env.json as JSON, where your application can read them.
24
     * @var string[] List of required environment variables. If one is missing the container will exit.
25
     *
26
     */
27
    public $environmentVariables = [];
28
29
    /**
30
     * @var array Pool directives
31
     * @see http://php.net/manual/en/install.fpm.configuration.php
32
     *
33
     */
34
    public $poolConfig = [
35
        'user' => 'nobody',
36
        'group' => 'nobody',
37
        'listen' => 9000,
38
        'pm' => 'dynamic',
39
        'pm.max_children' => 40,
40
        'pm.start_servers' => 3,
41
        'pm.min_spare_servers' => 1,
42
        'pm.max_spare_servers' => 3,
43
        'access.log' => '/proc/self/fd/2',
44
        'clear_env' => 'yes',
45
        'catch_workers_output' => 'yes'
46
    ];
47
48
    /**
49
     * @var array PHP configuration, supplied via php_admin_value in fpm config.
50
     */
51
    public $phpConfig = [
52
        'upload_max_filesize' => '20M',
53
        'post_max_size' => '25M'
54
    ];
55
56
    /**
57
     * @var array Global directives
58
     * @see http://php.net/manual/en/install.fpm.configuration.php
59
     *
60
     */
61
    public $fpmConfig = [
62
        'error_log' => '/proc/self/fd/2',
63
        'daemonize' => 'no',
64
    ];
65
66
    /**
67
     * List of php extensions to install
68
     */
69
    public $extensions = [
70
        'ctype',
71
        'gd',
72
        'iconv',
73
        'intl',
74
        'json',
75
        'mbstring',
76
        'session',
77
        'pdo_mysql',
78
        'session',
79
        'curl'
80
    ];
81
82
    /**
83
     * @var string The name of the created image.
84
     */
85
    public $image;
86
87
    /**
88
     * @var string The tag of the created image.
89
     */
90
    public $tag = 'latest';
91
92
    /**
93
     * @var bool wheter to push successful builds.
94
     */
95
    public $push = false;
96
97
    /**
98
     * @var string Location of composer.json / composer.lock
99
     */
100
    public $composerFilePath = '@app/../';
101
102
    /**
103
     * @var string[] List of console commands that are executed upon container launch.
104
     */
105
    public $initializationCommands = [];
106
    /**
107
     * @return string A PHP-FPM config file.
108
     */
109 3
    protected function createFpmConfig()
110
    {
111 3
        $config = [];
112
        // Add global directives.
113 3
        $config[] = '[global]';
114 3
        foreach ($this->fpmConfig as $key => $value) {
115 3
            $config[] = "$key = $value";
116
        }
117
118
        // Add pool directives.
119 3
        $poolConfig = $this->poolConfig;
120 3
        foreach ($this->phpConfig as $key => $value) {
121 3
            $poolConfig["php_admin_value[$key]"] = $value;
122
        }
123
124 3
        $config[] = '[www]';
125 3
        foreach ($poolConfig as $key => $value) {
126 3
            $config[] = "$key = $value";
127
        }
128
129 3
        return \implode("\n", $config);
130
    }
131
132
    /**
133
     * @return string A shell script that checks for existence of (non-empty) variables and runs php-fpm.
134
     */
135 3
    private function createEntrypoint(string $entryScript): string
136
    {
137
        // Get the route.
138 3
        $result = [];
139 3
        $result[] = '#!/bin/sh';
140
        // Check for variables.
141 3
        foreach ($this->environmentVariables as $name) {
142 1
            $result[] = \strtr('if [ -z "${name}" -a ! -f "$SECRET_DIR/{name}" ]; then echo "Variable \${name} is required."; exit 1; fi', [
143 1
                '{name}' => $name
144
            ]);
145
        }
146
147
        // Check if runtime directory is writable.
148 3
        $result[] = <<<SH
149
su nobody -s /bin/touch /runtime/testfile && rm /runtime/testfile;
150
if [ $? -ne 0 ]; then
151
  echo Runtime directory is not writable;
152
  exit 1
153
fi
154
SH;
155
156
157
158
        // Check if runtime is a tmpfs.
159 3
        $message = Console::ansiFormat('/runtime should really be a tmpfs.', [Console::FG_RED]);
160 3
        $result[] = <<<SH
161 3
grep 'tmpfs /runtime' /proc/mounts;
162
if [ $? -ne 0 ]; then
163 3
  echo $message;
164
fi
165
SH;
166 3
        $result[] = <<<SH
167
su nobody -s /bin/touch /runtime/env.json
168
(test -d \$SECRET_DIR && cd \$SECRET_DIR && find * -type f -exec jq -sR '{(input_filename):.}' {} \; ) | jq -s 'env+add' > /runtime/env.json
169
if [ $? -ne 0 ]; then
170
  echo "failed to store env in /runtime/env.json";
171
  exit 1
172
fi
173
SH;
174
175
176 3
        foreach ($this->initializationCommands as $route) {
177 1
            $result[] = "$entryScript $route --interactive=0 || exit";
178
        }
179 3
        $result[] = 'exec php-fpm --force-stderr --fpm-config /php-fpm.conf';
180 3
        return \implode("\n", $result);
181
    }
182
183
    /**
184
     * @param Context $context The context to use
185
     * @param string $version This is stored in the VERSION environment variable.
186
     * @param string $sourcePath This is the path where app source is stored, it must be a top level dir, the project root is derived from it
187
     * @throws InvalidConfigException
188
     */
189 5
    public function createBuildContext(
190
        Context $context,
191
        string $version,
192
        string $sourcePath
193
    ): void {
194 5
        if (!is_dir($sourcePath)) {
195 1
            throw new \InvalidArgumentException("$sourcePath does not exist or is not a directory");
196
        }
197
198 4
        $entryScript = "/project/{$this->getConsoleEntryScript($sourcePath)}";
199
200
        /**
201
         * BEGIN COMPOSER
202
         */
203 3
        $context->command('FROM composer');
204 3
        $context->addFile('/build/composer.json', \Yii::getAlias($this->composerFilePath) .'/composer.json');
205
206 3
        if (\file_exists(\Yii::getAlias($this->composerFilePath) . '/composer.lock')) {
207 3
            $context->addFile('/build/composer.lock', \Yii::getAlias($this->composerFilePath) . '/composer.lock');
208
        }
209
210 3
        $context->run('cd /build && composer install --no-dev --no-autoloader --ignore-platform-reqs --prefer-dist');
211
212
        // Add the actual source code.
213 3
        $context->addFile('/build/' . \basename($sourcePath), $sourcePath);
214 3
        $context->run('cd /build && composer dumpautoload -o --no-dev');
215
        /**
216
         * END COMPOSER
217
         */
218
219 3
        $context->from('php:7.4-fpm-alpine');
220 3
        $context->run('apk add --update --no-cache jq');
221 3
        $context->addUrl("/usr/local/bin/", "https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions");
222 3
        $context->run("chmod +x /usr/local/bin/install-php-extensions");
223 3
        $context->run('install-php-extensions ' . implode(' ', $this->extensions));
224 3
        $context->run('mkdir /runtime && chown nobody:nobody /runtime');
225 3
        $context->volume('/runtime');
226 3
        $context->copyFromLayer("/project", "0", "/build");
227
228 3
        $context->add('/entrypoint.sh', $this->createEntrypoint($entryScript));
229
230 3
        $context->run('chmod +x /entrypoint.sh');
231
232 3
        $context->add('/php-fpm.conf', $this->createFpmConfig());
233
234 3
        $context->run("php-fpm --force-stderr --fpm-config /php-fpm.conf -t");
235
236 3
        $context->entrypoint(["/entrypoint.sh"]);
237
238 3
        $context->env('VERSION', $version);
239
        // Test if we can run a console command.
240 3
        $context->run("[ -f $entryScript ]");
241 3
    }
242
243
    /**
244
     * @throws \InvalidArgumentException in case the app is not configured as expected
245
     * @param string $sourcePath the path to the soruce files
246
     * @return string the relative path of the (console) entry script with respect to the project (not app) root.
247
     */
248 4
    private function getConsoleEntryScript(string $sourcePath): string
249
    {
250 4
        $full = \array_slice(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), -1)[0]['file'];
251 4
        $projectRoot = dirname($sourcePath);
252 4
        if (strncmp($projectRoot, $full, strlen($projectRoot)) !== 0) {
253 1
            throw new \InvalidArgumentException("The console entry script must be located inside the project root; $full is not in $projectRoot");
254
        }
255 3
        return \ltrim(substr($full, strlen($projectRoot)), '/');
256
    }
257
258
259 3
    public function __set($name, $value): void
260
    {
261 3
        if (\strncmp($name, 'additional', 10) !== 0) {
262 1
            parent::__set($name, $value);
263 1
            return;
264
        }
265
266
267 3
        $this->add(\lcfirst(\substr($name, 10)), $value);
268 2
    }
269
270 3
    private function add($name, array $value): void
271
    {
272 3
        if (!\property_exists($this, $name)) {
273 1
            throw new UnknownPropertyException("Unknown property $name");
274
        }
275 2
        $this->$name = ArrayHelper::merge($this->$name, $value);
276 2
    }
277
}
278