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 ( 7610c7...cbb3b0 )
by Sam
04:09
created

Module::getConsoleEntryScript()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 9
ccs 5
cts 6
cp 0.8333
rs 9.6666
cc 2
eloc 6
nc 2
nop 0
crap 2.0185
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\helpers\Console;
10
use yii\mutex\Mutex;
11
12
class Module extends \yii\base\Module
13
{
14
15
    /**
16
     * @var bool Whether the container should attempt to run migrations on launch.
17
     */
18
    public $runMigrations = false;
19
20
    /**
21
     * @var bool whether migrations should acquire a lock.
22
     * It must be configured in the 'mutex' component of this module or the application
23
     * Note that this mutex must be shared between all instances of your application.
24
     * Consider using something like redis or mysql mutex.
25
     */
26
    public $migrationsUseMutex = true;
27
28
    /**
29
     * The variables will be written to /runtime/env.json as JSON, where your application can read them.
30
     * @var string[] List of required environment variables. If one is missing the container will exit.
31
     *
32
     */
33
    public $environmentVariables = [];
34
35
    /**
36
     * @var array Pool directives
37
     * @see http://php.net/manual/en/install.fpm.configuration.php
38
     *
39
     */
40
    public $poolConfig = [
41
        'user' => 'nobody',
42
        'group' => 'nobody',
43
        'listen' => 9000,
44
        'pm' => 'dynamic',
45
        'pm.max_children' => 40,
46
        'pm.start_servers' => 3,
47
        'pm.min_spare_servers' => 1,
48
        'pm.max_spare_servers' => 3,
49
        'access.log' => '/proc/self/fd/2',
50
        'clear_env' => 'yes',
51
        'catch_workers_output' => 'yes'
52
    ];
53
54
    /**
55
     * @var array PHP configuration, supplied via php_admin_value in fpm config.
56
     */
57
    public $phpConfig = [
58
        'upload_max_filesize' => '20M',
59
        'post_max_size' => '25M'
60
    ];
61
62
    /**
63
     * @var array Global directives
64
     * @see http://php.net/manual/en/install.fpm.configuration.php
65
     *
66
     */
67
    public $fpmConfig = [
68
        'error_log' => '/proc/self/fd/2',
69
        'daemonize' => 'no',
70
    ];
71
72
    public $extensions = [
73
        'ctype',
74
        'gd',
75
        'iconv',
76
        'intl',
77
        'json',
78
        'mbstring',
79
        'session',
80
        'pdo_mysql',
81
        'session',
82
        'curl'
83
    ];
84
85
    /**
86
     * @var string The name of the created image.
87
     */
88
    public $image;
89
90
    /**
91
     * @var string The tag of the created image.
92
     */
93
    public $tag = 'latest';
94
95
    /**
96
     * @var bool wheter to push successful builds.
97
     */
98
    public $push = false;
99
100
    /**
101
     * @var string Location of composer.json / composer.lock
102
     */
103
    public $composerFilePath = '@app/../';
104
    /**
105
     * @return string A PHP-FPM config file.
106
     */
107 3
    protected function createFpmConfig()
108
    {
109 3
        $config = [];
110
        // Add global directives.
111 3
        if (!empty($this->fpmConfig)) {
112 3
            $config[] = '[global]';
113 3
            foreach ($this->fpmConfig as $key => $value) {
114 3
                $config[] = "$key = $value";
115
            }
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
        if (!empty($poolConfig)) {
125 3
            $config[] = '[www]';
126 3
            foreach ($poolConfig as $key => $value) {
127 3
                $config[] = "$key = $value";
128
            }
129
        }
130
131 3
        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 3
    protected function createEntrypoint(): string
138
    {
139
        // Get the route.
140 3
        $route = "{$this->getUniqueId()}/migrate/up";
141 3
        $script = "/project/{$this->getConsoleEntryScript()}";
142 3
        $result = [];
143 3
        $result[] = '#!/bin/sh';
144
        // Check for variables.
145 3
        foreach($this->environmentVariables as $name) {
146
            $result[] = \strtr('if [ -z "${name}" ]; then echo "Variable \${name} is required."; exit 1; fi', [
147
                '{name}' => $name
148
            ]);
149
        }
150
151
        // Check if runtime directory is writable.
152 3
        $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 3
        $message = Console::ansiFormat('/runtime should really be a tmpfs.', [Console::FG_RED]);
164 3
        $result[] = <<<SH
165
mount | grep '/runtime type tmpfs';
166
if [ $? -ne 0 ]; then
167 3
  echo $message; 
168
fi
169
SH;
170 3
        $result[] = 'jq -n env > /runtime/env.json';
171
172 3
        if ($this->runMigrations) {
173
            $result[] = <<<SH
174
ATTEMPTS=0
175
while [ \$ATTEMPTS -lt 10 ]; do
176
  # First run migrations.
177
  $script $route --interactive=0
178
  if [ $? -eq 0 ]; then
179
    echo "Migrations done";
180
    break;
181
  fi
182
  echo "Failed to run migrations, retrying in 10s.";
183
  sleep 10;
184
  let ATTEMPTS=ATTEMPTS+1
185
done
186
187
if [ \$ATTEMPTS -gt 9 ]; then
188
  echo "Migrations failed.."
189
  exit 1;
190
fi
191
SH;
192
        }
193
194 3
        $result[] = 'exec php-fpm7 --force-stderr --fpm-config /php-fpm.conf';
195 3
        return \implode("\n", $result);
196
    }
197
198 3
    public function createBuildContext(): Context
199
    {
200 3
        $builder = new ContextBuilder();
201
202
        /**
203
         * BEGIN COMPOSER
204
         */
205 3
        $builder->from('composer');
206 3
        $builder->addFile('/build/composer.json', \Yii::getAlias($this->composerFilePath) .'/composer.json');
207 3
        if (\file_exists(\Yii::getAlias($this->composerFilePath) . '/composer.lock')) {
208 3
            $builder->addFile('/build/composer.lock', \Yii::getAlias($this->composerFilePath) . '/composer.lock');
209
        }
210
211 3
        $builder->run('cd /build && composer install --no-dev --no-autoloader --ignore-platform-reqs --prefer-dist && rm -rf /root/.composer');
212
213
214
        // Add the actual source code.
215 3
        $root = \Yii::getAlias('@app');
216 3
        if (!\is_string($root)) {
217
            throw new \Exception('Alias @app must be defined.');
218
        }
219 3
        $builder->addFile('/build/' . \basename($root), $root);
220 3
        $builder->run('cd /build && composer dumpautoload -o');
221
        /**
222
         * END COMPOSER
223
         */
224
225
226 3
        $builder->from('alpine:edge');
227
        $packages = [
228 3
            'php7',
229
            'php7-fpm',
230
            'tini',
231
            'ca-certificates',
232
            /**
233
             * @see https://stedolan.github.io/jq/
234
             * This is used for converting the env to JSON.
235
             */
236
            'jq'
237
        ];
238 3
        foreach ($this->extensions as $extension) {
239
            $packages[] = "php7-$extension";
240
        }
241 3
        $builder->run('apk add --update --no-cache ' . \implode(' ', $packages));
242 3
        $builder->run('mkdir /runtime && chown nobody:nobody /runtime');
243 3
        $builder->volume('/runtime');
244 3
        $builder->copy('--from=0 /build', '/project');
245 3
        $builder->add('/entrypoint.sh', $this->createEntrypoint());
246 3
        $builder->run('chmod +x /entrypoint.sh');
247 3
        $builder->add('/php-fpm.conf', $this->createFpmConfig());
248 3
        $builder->run("php-fpm7 --force-stderr --fpm-config /php-fpm.conf -t");
249 3
        $builder->entrypoint('["/sbin/tini", "--", "/entrypoint.sh"]');
250
251
        // Test if we can run a console command.
252 3
        $script = "[ -f /project/{$this->getConsoleEntryScript()} ]";
253 3
        $builder->run($script);
254
255
256 3
        return $builder->getContext();
257
    }
258
259 3
    public function getLock(int $timeout = 0)
260
    {
261 3
        if ($this->has('mutex')) {
262 1
            $mutex = $this->get('mutex');
263 1
            if ($mutex instanceof Mutex
264 1
                && $mutex->acquire(__CLASS__, $timeout)
265
            ) {
266 1
                \register_shutdown_function(function() use ($mutex): void {
267
                    $mutex->release(__CLASS__);
268 1
                });
269 1
                return true;
270
            }
271
        }
272 3
        return false;
273
    }
274
275
    /**
276
     * @throws InvalidConfigException in case the app is not configured as expected
277
     * @return string the relative path of the (console) entry script with respect to the project (not app) root.
278
     */
279 3
    public function getConsoleEntryScript(): string
280
    {
281 3
        $full = \array_slice(\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), -1)[0]['file'];
282 3
        $relative = \strtr($full, [\dirname(\Yii::getAlias('@app')) => '']);
283 3
        if ($relative === $full){
284
            throw new InvalidConfigException("The console entry script must be located inside the @app directory.");
285
        }
286 3
        return \ltrim($relative, '/');
287
    }
288
}