• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sanmai / console / 15923155543

27 Jun 2025 09:35AM UTC coverage: 84.127% (-15.9%) from 100.0%
15923155543

Pull #6

github

web-flow
Merge 43fe10c72 into 33fd65b55
Pull Request #6: Custom bootstrap script

27 of 37 new or added lines in 1 file covered. (72.97%)

53 of 63 relevant lines covered (84.13%)

6.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.97
/src/ConfigLoader.php
1
<?php
2

3
/**
4
 * Copyright 2025 Alexey Kopytko <alexey@kopytko.com>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18

19
declare(strict_types=1);
20

21
namespace ConsoleApp;
22

23
use Composer\Autoload\ClassLoader;
24
use Composer\InstalledVersions;
25
use RuntimeException;
26

27
use function class_exists;
28
use function file_exists;
29
use function file_get_contents;
30
use function fwrite;
31
use function getcwd;
32
use function is_readable;
33
use function is_array;
34
use function json_decode;
35

36
use const STDERR;
37

38
final class ConfigLoader
39
{
40
    public function __construct(
41
        private readonly string $workingDirectory = ''
42
    ) {}
24✔
43

44
    /**
45
     * Loads configuration from the root package composer.json
46
     *
47
     * @return array<string, mixed>
48
     */
49
    public function loadConfig(): array
50
    {
51
        if (!class_exists(InstalledVersions::class)) {
4✔
NEW
52
            return [];
×
53
        }
54

55
        // Get the install path for the root package
56
        $rootPackage = InstalledVersions::getRootPackage();
4✔
57
        $installPath = $rootPackage['install_path'];
4✔
58

59
        $composerJsonPath = $installPath . '/composer.json';
4✔
60

61
        if (!file_exists($composerJsonPath) || !is_readable($composerJsonPath)) {
4✔
NEW
62
            return [];
×
63
        }
64

65
        $content = file_get_contents($composerJsonPath);
4✔
66
        if (false === $content) {
4✔
NEW
67
            return [];
×
68
        }
69

70
        $composer = json_decode($content, true);
4✔
71
        if (!is_array($composer)) {
4✔
NEW
72
            return [];
×
73
        }
74

75
        if (!isset($composer['extra']) || !is_array($composer['extra'])) {
4✔
NEW
76
            return [];
×
77
        }
78

79
        if (!isset($composer['extra']['console']) || !is_array($composer['extra']['console'])) {
4✔
80
            return [];
4✔
81
        }
82

83
        /** @var array<string, mixed> */
NEW
84
        return $composer['extra']['console'];
×
85
    }
86

87
    /**
88
     * Loads a custom bootstrap script
89
     *
90
     * Similar to PHPUnit, bootstrap scripts are included for their side effects.
91
     * They can optionally return a ClassLoader instance to use for command discovery.
92
     */
93
    public function loadCustomInit(
94
        ClassLoader $initialLoader,
95
        string $initScript
96
    ): ?ClassLoader {
97
        $initPath = $this->getWorkingDirectory() . '/' . $initScript;
20✔
98

99
        if (!file_exists($initPath)) {
20✔
100
            $this->writeWarning("Bootstrap script not found: $initScript");
4✔
101
            return null;
4✔
102
        }
103

104
        if (!is_readable($initPath)) {
16✔
105
            $this->writeWarning("Bootstrap script not readable: $initScript");
4✔
106
            return null;
4✔
107
        }
108

109
        // Load the custom bootstrap script (like PHPUnit does)
110
        $result = require $initPath;
12✔
111

112
        // If bootstrap returns a ClassLoader, use it
113
        // Otherwise, return null to indicate the initial loader should be used
114
        if ($result instanceof ClassLoader) {
8✔
115
            return $result;
4✔
116
        }
117

118
        return null;
4✔
119
    }
120

121
    private function getWorkingDirectory(): string
122
    {
123
        if ($this->workingDirectory) {
20✔
124
            return $this->workingDirectory;
20✔
125
        }
126

NEW
127
        $cwd = getcwd();
×
NEW
128
        if (false === $cwd) {
×
NEW
129
            throw new RuntimeException('Unable to determine current working directory');
×
130
        }
131

NEW
132
        return $cwd;
×
133
    }
134

135
    private function writeWarning(string $message): void
136
    {
137
        fwrite(STDERR, "Warning: $message\n");
8✔
138
    }
139
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc