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 ( 74761d...9c0a76 )
by Sam
08:32
created

Module::createEntrypoint()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 3.0077

Importance

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