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 ( c90021...83c566 )
by Sam
03:27 queued 02:21
created

Module::add()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
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 name of the base image to use for the container. Should contain php-fpm
89
     */
90
    public string $baseImage = 'php:7.4-fpm-alpine';
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
91
    /**
92
     * @var string The tag of the created image.
93
     */
94
    public $tag = 'latest';
95
96
    /**
97
     * @var bool wheter to push successful builds.
98
     */
99
    public $push = false;
100
101
    /**
102
     * @var string Location of composer.json / composer.lock
103
     */
104
    public $composerFilePath = '@app/../';
105
106
    /**
107
     * @var string[] List of console commands that are executed upon container launch.
108
     */
109
    public $initializationCommands = [];
110
    /**
111
     * @return string A PHP-FPM config file.
112
     */
113 4
    protected function createFpmConfig()
114
    {
115 4
        $config = [];
116
        // Add global directives.
117 4
        $config[] = '[global]';
118 4
        foreach ($this->fpmConfig as $key => $value) {
119 4
            $config[] = "$key = $value";
120
        }
121
122
        // Add pool directives.
123 4
        $poolConfig = $this->poolConfig;
124 4
        foreach ($this->phpConfig as $key => $value) {
125 4
            $poolConfig["php_admin_value[$key]"] = $value;
126
        }
127
128 4
        $config[] = '[www]';
129 4
        foreach ($poolConfig as $key => $value) {
130 4
            $config[] = "$key = $value";
131
        }
132
133 4
        return \implode("\n", $config);
134
    }
135
136
    /**
137
     * @return string A shell script that checks for existence of (non-empty) variables and runs php-fpm.
138
     */
139 4
    private function createEntrypoint(string $entryScript): string
140
    {
141
        // Get the route.
142 4
        $result = [];
143 4
        $result[] = '#!/bin/sh';
144
        // Check for variables.
145 4
        foreach ($this->environmentVariables as $name) {
146 1
            $result[] = \strtr('if [ -z "${name}" -a ! -f "$SECRET_DIR/{name}" ]; then echo "Variable \${name} is required."; exit 1; fi', [
147 1
                '{name}' => $name
148
            ]);
149
        }
150
151
        // Check if runtime directory is writable.
152 4
        $result[] = <<<SH
153
su nobody -s /bin/touch /runtime/testfile && rm /runtime/testfile;
154
if [ $? -ne 0 ]; then
155
  echo Runtime directory is not writable;
156
  exit 1
157
fi
158
SH;
159
160
161
162
        // Check if runtime is a tmpfs.
163 4
        $message = Console::ansiFormat('/runtime should really be a tmpfs.', [Console::FG_RED]);
164 4
        $result[] = <<<SH
165 4
grep 'tmpfs /runtime' /proc/mounts;
166
if [ $? -ne 0 ]; then
167 4
  echo $message;
168
fi
169
SH;
170 4
        $result[] = <<<SH
171
su nobody -s /bin/touch /runtime/env.json
172
(test -d \$SECRET_DIR && cd \$SECRET_DIR && find * -type f -exec jq -sR '{(input_filename):.}' {} \; ) | jq -s 'env+add' > /runtime/env.json
173
if [ $? -ne 0 ]; then
174
  echo "failed to store env in /runtime/env.json";
175
  exit 1
176
fi
177
SH;
178
179
180 4
        foreach ($this->initializationCommands as $route) {
181 1
            $result[] = "$entryScript $route --interactive=0 || exit";
182
        }
183 4
        $result[] = 'exec php-fpm --force-stderr --fpm-config /php-fpm.conf';
184 4
        return \implode("\n", $result);
185
    }
186
187
    /**
188
     * @param Context $context The context to use
189
     * @param string $version This is stored in the VERSION environment variable.
190
     * @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
191
     * @throws InvalidConfigException
192
     */
193 6
    public function createBuildContext(
194
        Context $context,
195
        string $version,
196
        string $sourcePath
197
    ): void {
198 6
        if (!is_dir($sourcePath)) {
199 1
            throw new \InvalidArgumentException("$sourcePath does not exist or is not a directory");
200
        }
201
202 5
        $entryScript = "/project/{$this->getConsoleEntryScript($sourcePath)}";
203
204
        /**
205
         * BEGIN COMPOSER
206
         */
207 4
        $context->command('FROM composer');
208 4
        $context->addFile('/build/composer.json', \Yii::getAlias($this->composerFilePath) .'/composer.json');
209
210 4
        if (\file_exists(\Yii::getAlias($this->composerFilePath) . '/composer.lock')) {
211 4
            $context->addFile('/build/composer.lock', \Yii::getAlias($this->composerFilePath) . '/composer.lock');
212
        }
213
214 4
        $context->run('cd /build && composer install --no-dev --no-autoloader --ignore-platform-reqs --prefer-dist');
215
216
        // Add the actual source code.
217 4
        $context->addFile('/build/' . \basename($sourcePath), $sourcePath);
218 4
        $context->run('cd /build && composer dumpautoload -o --no-dev');
219
        /**
220
         * END COMPOSER
221
         */
222
223 4
        $context->from($this->baseImage);
224 4
        $context->run('apk add --update --no-cache jq');
225 4
        $context->addUrl("/usr/local/bin/", "https://raw.githubusercontent.com/mlocati/docker-php-extension-installer/master/install-php-extensions");
226 4
        $context->run("chmod +x /usr/local/bin/install-php-extensions");
227 4
        $context->run('install-php-extensions ' . implode(' ', $this->extensions));
228 4
        $context->run('mkdir /runtime && chown nobody:nobody /runtime');
229 4
        $context->volume('/runtime');
230 4
        $context->copyFromLayer("/project", "0", "/build");
231
232 4
        $context->add('/entrypoint.sh', $this->createEntrypoint($entryScript));
233
234 4
        $context->run('chmod +x /entrypoint.sh');
235
236 4
        $context->add('/php-fpm.conf', $this->createFpmConfig());
237
238 4
        $context->run("php-fpm --force-stderr --fpm-config /php-fpm.conf -t");
239
240 4
        $context->entrypoint(["/entrypoint.sh"]);
241
242 4
        $context->env('VERSION', $version);
243
        // Test if we can run a console command.
244 4
        $context->run("[ -f $entryScript ]");
245 4
    }
246
247
    /**
248
     * @throws \InvalidArgumentException in case the app is not configured as expected
249
     * @param string $sourcePath the path to the soruce files
250
     * @return string the relative path of the (console) entry script with respect to the project (not app) root.
251
     */
252 5
    private function getConsoleEntryScript(string $sourcePath): string
253
    {
254 5
        $full = \array_slice(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), -1)[0]['file'];
255 5
        $projectRoot = dirname($sourcePath);
256 5
        if (strncmp($projectRoot, $full, strlen($projectRoot)) !== 0) {
257 1
            throw new \InvalidArgumentException("The console entry script must be located inside the project root; $full is not in $projectRoot");
258
        }
259 4
        return \ltrim(substr($full, strlen($projectRoot)), '/');
260
    }
261
262
263 3
    public function __set($name, $value): void
264
    {
265 3
        if (\strncmp($name, 'additional', 10) !== 0) {
266 1
            parent::__set($name, $value);
267 1
            return;
268
        }
269
270
271 3
        $this->add(\lcfirst(\substr($name, 10)), $value);
272 2
    }
273
274 3
    private function add($name, array $value): void
275
    {
276 3
        if (!\property_exists($this, $name)) {
277 1
            throw new UnknownPropertyException("Unknown property $name");
278
        }
279 2
        $this->$name = ArrayHelper::merge($this->$name, $value);
280 2
    }
281
}
282