RunCommand::addFilesToMessage()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 4
1
<?php
2
namespace TheCodingMachine\WashingMachine\Commands;
3
4
use Gitlab\Client;
5
use Gitlab\Model\Project;
6
use Symfony\Component\Console\Command\Command;
7
use Symfony\Component\Console\Input\InputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use TheCodingMachine\WashingMachine\Clover\CloverFile;
11
use TheCodingMachine\WashingMachine\Clover\Crap4JFile;
12
use TheCodingMachine\WashingMachine\Clover\CrapMethodMerger;
13
use TheCodingMachine\WashingMachine\Clover\DiffService;
14
use TheCodingMachine\WashingMachine\Clover\EmptyCloverFile;
15
use TheCodingMachine\WashingMachine\Git\GitRepository;
16
use TheCodingMachine\WashingMachine\Gitlab\BuildNotFoundException;
17
use TheCodingMachine\WashingMachine\Gitlab\BuildService;
18
use TheCodingMachine\WashingMachine\Gitlab\MergeRequestNotFoundException;
19
use TheCodingMachine\WashingMachine\Gitlab\Message;
20
use TheCodingMachine\WashingMachine\Gitlab\SendCommentService;
21
22
class RunCommand extends Command
23
{
24
25
    protected function configure()
26
    {
27
        $this
28
            ->setName('run')
29
            ->setDescription('Analyses the coverage report files and upload the result to Gitlab')
30
            //->setHelp("This command allows you to create users...")
31
            ->addOption('clover',
32
                'c',
33
                InputOption::VALUE_REQUIRED,
34
                'The path to the clover.xml file generated by PHPUnit.',
35
                'clover.xml')
36
            ->addOption('crap4j',
37
                'j',
38
                InputOption::VALUE_REQUIRED,
39
                'The path to the crap4j.xml file generated by PHPUnit.',
40
                'crap4j.xml')
41
            ->addOption('gitlab-url',
42
                'u',
43
                InputOption::VALUE_REQUIRED,
44
                'The Gitlab URL. If not specified, it is deduced from the CI_BUILD_REPO environment variable.',
45
                null)
46
            ->addOption('gitlab-api-token',
47
                't',
48
                InputOption::VALUE_REQUIRED,
49
                'The Gitlab API token. If not specified, it is fetched from the GITLAB_API_TOKEN environment variable.',
50
                null)
51
            /*->addOption('gitlab-project-id',
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
52
                'p',
53
                InputOption::VALUE_REQUIRED,
54
                'The Gitlab project ID. If not specified, it is fetched from the CI_PROJECT_ID environment variable.',
55
                null)*/
56
            ->addOption('gitlab-project-name',
57
                'p',
58
                InputOption::VALUE_REQUIRED,
59
                'The Gitlab project name (in the form "group/name"). If not specified, it is deduced from the CI_PROJECT_DIR environment variable.',
60
                null)
61
            ->addOption('commit-sha',
62
                'r',
63
                InputOption::VALUE_REQUIRED,
64
                'The commit SHA. If not specified, it is deduced from the CI_COMMIT_SHA environment variable.',
65
                null)
66
            ->addOption('gitlab-job-id',
67
                'b',
68
                InputOption::VALUE_REQUIRED,
69
                'The Gitlab CI build/job id. If not specified, it is deduced from the CI_BUILD_ID environment variable.',
70
                null)
71
            ->addOption('job-stage',
72
                's',
73
                InputOption::VALUE_REQUIRED,
74
                'The Gitlab CI job stage. If not specified, it is deduced from the CI_JOB_ID environment variable (only available in Gitlab 9+).',
75
                null)
76
            ->addOption('file',
77
                'f',
78
                InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED,
79
                'Text file to be sent in the merge request comments (can be used multiple times).',
80
                [])
81
            ->addOption('open-issue',
82
                'i',
83
                InputOption::VALUE_NONE,
84
                'Opens an issue (if the build is not part of a merge request)')
85
        ;
86
    }
87
88
    protected function execute(InputInterface $input, OutputInterface $output)
89
    {
90
        $config = new Config($input);
91
92
        $cloverFilePath = $config->getCloverFilePath();
93
94
        $cloverFile = null;
95
        if (file_exists($cloverFilePath)) {
96
            $cloverFile = CloverFile::fromFile($cloverFilePath, getcwd());
97
            //$output->writeln(sprintf('Code coverage: %.2f%%', $cloverFile->getCoveragePercentage() * 100));
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
98
        }
99
100
        $crap4JFilePath = $config->getCrap4JFilePath();
101
102
        $crap4jFile = null;
103
        if (file_exists($crap4JFilePath)) {
104
            $crap4jFile = Crap4JFile::fromFile($crap4JFilePath);
105
        }
106
107
        $files = $config->getFiles();
108
109
        $methodsProvider = null;
110
        $codeCoverageProvider = null;
111
112
        if ($cloverFile !== null && $crap4jFile !== null) {
113
            $methodsProvider = new CrapMethodMerger($cloverFile, $crap4jFile);
114
            $codeCoverageProvider = $cloverFile;
115
        } elseif ($cloverFile !== null) {
116
            $methodsProvider = $cloverFile;
117
            $codeCoverageProvider = $cloverFile;
118
        } elseif ($crap4jFile !== null) {
119
            $methodsProvider = $crap4jFile;
120
        } elseif (empty($files)) {
121
            throw new \RuntimeException('Could not find neither clover file, nor crap4j file for analysis nor files to send in comments. Nothing done. Searched paths: '.$cloverFilePath.' and '.$crap4JFilePath);
122
        }
123
124
        $gitlabApiToken = $config->getGitlabApiToken();
125
126
        $gitlabUrl = $config->getGitlabUrl();
127
        $gitlabApiUrl = $config->getGitlabApiUrl();
128
129
130
        /*$projectId = $input->getOption('gitlab-project-id');
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
131
        if ($projectId === null) {
132
            $projectId = getenv('CI_PROJECT_ID');
133
            if ($projectId === false) {
134
                throw new \RuntimeException('Could not find the Gitlab project ID in the "CI_PROJECT_ID" environment variable (usually set by Gitlab CI). Either set this environment variable or pass the ID via the --gitlab-project-id command line option.');
135
            }
136
        }*/
137
138
        $projectName = $config->getGitlabProjectName();
139
140
        $commitSha = $config->getCommitSha();
141
142
        $currentBranchName = $config->getCurrentBranchName();
143
144
        $client = Client::create($gitlabApiUrl);
145
        $client->authenticate($gitlabApiToken);
146
147
        $diffService = new DiffService(1, 20);
148
149
        $sendCommentService = new SendCommentService($client, $diffService);
150
151
        // From CI_COMMIT_SHA, we can get the commit ( -> project -> build -> commit )
152
        // From the merge_requests API, we can get the list of commits for a single merge request
153
        // Hence, we can find the merge_request matching a build!
154
155
        $buildService = new BuildService($client);
156
157
        $inMergeRequest = false;
158
159
        try {
160
            $mergeRequest = $buildService->findMergeRequestByCommitSha($projectName, $commitSha);
161
162
            $repo = new GitRepository(getcwd());
163
            $targetCommit = $repo->getLatestCommitForBranch('origin/'.$mergeRequest['target_branch']);
164
            $lastCommonCommit = $repo->getMergeBase($targetCommit, $commitSha);
165
166
167
            list($previousCodeCoverageProvider, $previousMethodsProvider) = $this->getMeasuresFromCommit($buildService, $mergeRequest['target_project_id'], $lastCommonCommit, $cloverFilePath, $crap4JFilePath, $config->getJobStage());
168
            //list($previousCodeCoverageProvider, $previousMethodsProvider) = $this->getMeasuresFromBranch($buildService, $mergeRequest['target_project_id'], $mergeRequest['target_branch'], $cloverFilePath, $crap4JFilePath);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
169
170
            $message = new Message();
171
            if ($codeCoverageProvider !== null) {
172
                $message->addCoverageMessage($codeCoverageProvider, $previousCodeCoverageProvider);
173
            } else {
174
                $output->writeln('Could not find clover file for code coverage analysis.');
175
            }
176 View Code Duplication
            if ($methodsProvider !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
177
                $message->addDifferencesHtml($methodsProvider, $previousMethodsProvider, $diffService, $commitSha, $gitlabUrl, $projectName);
178
            } else {
179
                $output->writeln('Could not find clover file nor crap4j file for CRAP score analysis.');
180
            }
181
182
            $this->addFilesToMessage($message, $files, $output, $config);
183
184
            $client->merge_requests->addComment($projectName, $mergeRequest['id'], (string) $message);
185
186
            $inMergeRequest = true;
187
        } catch (MergeRequestNotFoundException $e) {
188
            // If there is no merge request attached to this build, let's skip the merge request comment. We can still make some comments on the commit itself!
189
            $output->writeln('It seems that this CI build is not part of a merge request.');
190
        }
191
192
        try {
193
            $targetProjectId = $mergeRequest['target_project_id'] ?? $projectName;
194
            list($lastCommitCoverage, $lastCommitMethodsProvider) = $this->getMeasuresFromBranch($buildService, $targetProjectId, $currentBranchName, $cloverFilePath, $crap4JFilePath, $config->getJobStage());
195
196
            $sendCommentService->sendDifferencesCommentsInCommit($methodsProvider, $lastCommitMethodsProvider, $projectName, $commitSha, $gitlabUrl);
0 ignored issues
show
Bug introduced by
It seems like $methodsProvider defined by null on line 109 can also be of type null; however, TheCodingMachine\Washing...encesCommentsInCommit() does only seem to accept object<TheCodingMachine\...MethodFetcherInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
197
198
199
            if ($config->isOpenIssue() && !$inMergeRequest) {
200
                $message = new Message();
201
202
                if ($codeCoverageProvider !== null) {
203
                    $message->addCoverageMessage($codeCoverageProvider, $lastCommitCoverage);
204
                } else {
205
                    $output->writeln('Could not find clover file for code coverage analysis.');
206
                }
207
208 View Code Duplication
                if ($methodsProvider !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
209
                    $message->addDifferencesHtml($methodsProvider, $lastCommitMethodsProvider, $diffService, $commitSha, $gitlabUrl, $projectName);
210
                } else {
211
                    $output->writeln('Could not find clover file nor crap4j file for CRAP score analysis.');
212
                }
213
214
                $this->addFilesToMessage($message, $files, $output, $config);
215
216
                $project = new Project($projectName, $client);
217
218
                $options = [
219
                    'description' => (string) $message
220
                ];
221
222
                $userId = $this->getCommiterId($client, $project, $commitSha);
223
                if ($userId !== null) {
224
                    $options['assignee_id'] = $userId;
225
                }
226
227
                $project->createIssue('Build failed', $options);
228
            }
229
        } catch (BuildNotFoundException $e) {
230
            $output->writeln('Unable to find a previous build for this branch. Skipping adding comments inside the commit. '.$e->getMessage());
231
        }
232
    }
233
234
    /**
235
     * Returns the user id of the committer.
236
     *
237
     * @param Client $client
238
     * @param Project $project
239
     * @param $commitRef
240
     * @return int|null
241
     */
242
    private function getCommiterId(Client $client, Project $project, $commitRef)
243
    {
244
245
        $commit = $project->commit($commitRef);
246
247
        $users = $client->users->search($commit->author_email);
248
249
        foreach ($users as $user) {
250
            if ($user['email'] === $commit->author_email) {
251
                return $user['id'];
252
            }
253
        }
254
255
        return null;
256
    }
257
258
    /**
259
     * @param BuildService $buildService
260
     * @param string $projectName
261
     * @param string $targetBranch
262
     * @param string $cloverPath
263
     * @param string $crap4JPath
264
     * @return array First element: code coverage, second element: list of methods.
265
     */
266
    public function getMeasuresFromBranch(BuildService $buildService, string $projectName, string $targetBranch, string $cloverPath, string $crap4JPath, string $jobStage) : array
267
    {
268
        try {
269
            $tmpFile = tempnam(sys_get_temp_dir(), 'art').'.zip';
270
271
            $buildService->dumpArtifactFromBranch($projectName, $targetBranch, $jobStage, $tmpFile);
272
            $zipFile = new \ZipArchive();
273
            if ($zipFile->open($tmpFile)!==true) {
274
                throw new \RuntimeException('Invalid ZIP archive '.$tmpFile);
275
            }
276
            return $this->getMeasuresFromZipFile($zipFile, $cloverPath, $crap4JPath);
277
        } catch (\RuntimeException $e) {
278 View Code Duplication
            if ($e->getCode() === 404) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
279
                // We could not find a previous clover file in the master branch.
280
                // Maybe this branch is the first to contain clover files?
281
                // Let's deal with this by generating a fake "empty" clover file.
282
                return [EmptyCloverFile::create(), EmptyCloverFile::create()];
283
            } else {
284
                throw $e;
285
            }
286
        }
287
    }
288
289
    public function getMeasuresFromCommit(BuildService $buildService, string $projectName, string $commitId, string $cloverPath, string $crap4JPath, string $jobStage) : array
290
    {
291
        try {
292
            $tmpFile = tempnam(sys_get_temp_dir(), 'art').'.zip';
293
294
            $build = $buildService->getLatestBuildFromCommitId($projectName, $commitId);
295
            $buildService->dumpArtifact($projectName, $build['id'], $jobStage, $tmpFile);
296
            $zipFile = new \ZipArchive();
297
            if ($zipFile->open($tmpFile)!==true) {
298
                throw new \RuntimeException('Invalid ZIP archive '.$tmpFile);
299
            }
300
            return $this->getMeasuresFromZipFile($zipFile, $cloverPath, $crap4JPath);
301
        } catch (\RuntimeException $e) {
302 View Code Duplication
            if ($e->getCode() === 404) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
303
                // We could not find a previous clover file in the give commit.
304
                // Maybe this branch is the first to contain clover files?
305
                // Let's deal with this by generating a fake "empty" clover file.
306
                return [EmptyCloverFile::create(), EmptyCloverFile::create()];
307
            } else {
308
                throw $e;
309
            }
310
        } catch (BuildNotFoundException $e) {
311
            // Maybe there is no .gitlab-ci.yml file on the target branch? In this case, there is no build.
312
            return [EmptyCloverFile::create(), EmptyCloverFile::create()];
313
        }
314
    }
315
316
    private function getMeasuresFromZipFile(\ZipArchive $zipFile, string $cloverPath, string $crap4JPath) : array
317
    {
318
        $cloverFileString = $zipFile->getFromName($cloverPath);
319
320
        $cloverFile = null;
321
        if ($cloverFileString !== false) {
322
            $cloverFile = CloverFile::fromString($cloverFileString, getcwd());
323
        }
324
325
        $crap4JString = $zipFile->getFromName($crap4JPath);
326
327
        $crap4JFile = null;
328
        if ($crap4JString !== false) {
329
            $crap4JFile = Crap4JFile::fromString($crap4JString);
330
        }
331
332
        $methodsProvider = null;
0 ignored issues
show
Unused Code introduced by
$methodsProvider is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
333
        $codeCoverageProvider = null;
334
335
        if ($cloverFile !== null && $crap4JFile !== null) {
336
            $methodsProvider = new CrapMethodMerger($cloverFile, $crap4JFile);
337
            $codeCoverageProvider = $cloverFile;
338
        } elseif ($cloverFile !== null) {
339
            $methodsProvider = $cloverFile;
340
            $codeCoverageProvider = $cloverFile;
341
        } elseif ($crap4JFile !== null) {
342
            $methodsProvider = $crap4JFile;
343
        } else {
344
            return [EmptyCloverFile::create(), EmptyCloverFile::create()];
345
        }
346
347
        return [$codeCoverageProvider, $methodsProvider];
348
    }
349
350
    private function addFilesToMessage(Message $message, array $files, OutputInterface $output, Config $config) {
351
        foreach ($files as $file) {
352
            if (!file_exists($file)) {
353
                $output->writeln('<error>Could not find file to send "'.$file.'". Skipping this file.</error>');
354
                continue;
355
            }
356
357
            $message->addFile(new \SplFileInfo($file), $config->getGitlabUrl(), $config->getGitlabProjectName(), $config->getGitlabBuildId());
358
        }
359
    }
360
}
361
362
/*
363
=================ENV IN A PR CONTEXT =========================
364
365
CI_BUILD_TOKEN=xxxxxx
366
HOSTNAME=runner-9431b96d-project-428-concurrent-0
367
PHP_INI_DIR=/usr/local/etc/php
368
PHP_ASC_URL=https://secure.php.net/get/php-7.0.15.tar.xz.asc/from/this/mirror
369
CI_BUILD_BEFORE_SHA=7af13f8e3bd090c7c34750e4badfc66a5f0af110
370
CI_SERVER_VERSION=
371
CI_BUILD_ID=109
372
OLDPWD=/
373
PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2
374
PHP_MD5=dca23412f3e3b3987e582091b751925d
375
CI_PROJECT_ID=428
376
PHPIZE_DEPS=autoconf 		file 		g++ 		gcc 		libc-dev 		make 		pkg-config 		re2c
377
PHP_URL=https://secure.php.net/get/php-7.0.15.tar.xz/from/this/mirror
378
CI_BUILD_REF_NAME=feature/js-ci
379
CI_BUILD_REF=7af13f8e3bd090c7c34750e4badfc66a5f0af110
380
PHP_LDFLAGS=-Wl,-O1 -Wl,--hash-style=both -pie
381
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
382
CI_BUILD_STAGE=test
383
CI_PROJECT_DIR=/builds/tcm-projects/uneo
384
PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2
385
GPG_KEYS=1A4E8B7277C42E53DBA9C7B9BCAA30EA9C0D5763 6E4F6AB321FDC07F2C332E3AC2BF0BC433CFC8B3
386
PWD=/builds/tcm-projects/uneo
387
CI_DEBUG_TRACE=false
388
CI_SERVER_NAME=GitLab CI
389
XDEBUG_VERSION=2.5.0
390
GITLAB_CI=true
391
CI_SERVER_REVISION=
392
CI_BUILD_NAME=test:app
393
HOME=/root
394
SHLVL=1
395
PHP_SHA256=300364d57fc4a6176ff7d52d390ee870ab6e30df121026649f8e7e0b9657fe93
396
CI_SERVER=yes
397
CI=true
398
CI_BUILD_REPO=http://gitlab-ci-token:[email protected]/tcm-projects/uneo.git
399
PHP_VERSION=7.0.15
400
401
===================ENV IN A COMMIT CONTEXT
402
403
CI_BUILD_TOKEN=xxxxxx
404
HOSTNAME=runner-9431b96d-project-447-concurrent-0
405
PHP_INI_DIR=/usr/local/etc/php
406
PHP_ASC_URL=https://secure.php.net/get/php-7.0.15.tar.xz.asc/from/this/mirror
407
CI_BUILD_BEFORE_SHA=42dd9686eafc2e8fb0a6b4d2c6785baec229c94a
408
CI_SERVER_VERSION=
409
CI_BUILD_ID=192
410
OLDPWD=/
411
PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2
412
PHP_MD5=dca23412f3e3b3987e582091b751925d
413
CI_PROJECT_ID=447
414
GITLAB_API_TOKEN=xxxxxxxxxxxxxxchangedmanually
415
PHPIZE_DEPS=autoconf 		file 		g++ 		gcc 		libc-dev 		make 		pkg-config 		re2c
416
PHP_URL=https://secure.php.net/get/php-7.0.15.tar.xz/from/this/mirror
417
CI_BUILD_REF_NAME=master
418
CI_BUILD_REF=42dd9686eafc2e8fb0a6b4d2c6785baec229c94a
419
PHP_LDFLAGS=-Wl,-O1 -Wl,--hash-style=both -pie
420
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
421
CI_BUILD_STAGE=test
422
CI_PROJECT_DIR=/builds/dan/washing-test
423
PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2
424
GPG_KEYS=1A4E8B7277C42E53DBA9C7B9BCAA30EA9C0D5763 6E4F6AB321FDC07F2C332E3AC2BF0BC433CFC8B3
425
PWD=/builds/dan/washing-test
426
CI_DEBUG_TRACE=false
427
CI_SERVER_NAME=GitLab CI
428
XDEBUG_VERSION=2.5.0
429
GITLAB_CI=true
430
CI_SERVER_REVISION=
431
CI_BUILD_NAME=test
432
HOME=/root
433
SHLVL=1
434
PHP_SHA256=300364d57fc4a6176ff7d52d390ee870ab6e30df121026649f8e7e0b9657fe93
435
CI_SERVER=yes
436
CI=true
437
CI_BUILD_REPO=http://gitlab-ci-token:[email protected]/dan/washing-test.git
438
PHP_VERSION=7.0.15
439
*/