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

cweagans / composer-patches / 4153806457

pending completion
4153806457

push

github

GitHub
Merge pull request #465 from cweagans/docs-4

21 of 21 new or added lines in 1 file covered. (100.0%)

482 of 730 relevant lines covered (66.03%)

2.69 hits per line

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

2.21
/src/Command/DoctorCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace cweagans\Composer\Command;
6

7
use Composer\DependencyResolver\Operation\UninstallOperation;
8
use cweagans\Composer\Capability\Patcher\PatcherProvider;
9
use cweagans\Composer\Patcher\PatcherInterface;
10
use Symfony\Component\Console\Input\ArrayInput;
11
use Symfony\Component\Console\Input\InputInterface;
12
use Symfony\Component\Console\Output\OutputInterface;
13

14
class DoctorCommand extends PatchesCommandBase
15
{
16
    protected function configure(): void
17
    {
18
        $this->setName('patches-doctor');
1✔
19
        $this->setDescription('Run a series of checks to ensure that Composer Patches has a usable environment.');
1✔
20
        $this->setAliases(['pd']);
1✔
21
    }
22

23
    protected function execute(InputInterface $input, OutputInterface $output): int
24
    {
25
        $plugin = $this->getPatchesPluginInstance();
×
26
        if (is_null($plugin)) {
×
27
            return 1;
×
28
        }
29
        $plugin->loadLockedPatches();
×
30

31
        $composer = $this->requireComposer();
×
32
        $io = $this->getIO();
×
33
        $plugin_manager = $composer->getPluginManager();
×
34
        $capabilities = $plugin_manager->getPluginCapabilities(
×
35
            PatcherProvider::class,
×
36
            ['composer' => $composer, 'io' => $this->getIO()]
×
37
        );
×
38

39
        $suggestions = [];
×
40

41
        $io->write("");
×
42
        $io->write("<info>System information</info>");
×
43
        $io->write("================================================================================");
×
44
        $io->write(
×
45
            str_pad("Composer version: ", 72) . "<info>" . str_pad(
×
46
                $this->getApplication()->getVersion(),
×
47
                8,
×
48
                " ",
×
49
                STR_PAD_LEFT
×
50
            ) . "</info>"
×
51
        );
×
52

53
        $system_issues = false;
×
54

55
        if (!str_starts_with($this->getApplication()->getVersion(), "2")) {
×
56
            $system_issues = true;
×
57
        }
58

59
        $io->write(str_pad("PHP version: ", 72) . "<info>" . str_pad(PHP_VERSION, 8, " ", STR_PAD_LEFT) . "</info>");
×
60
        if (PHP_VERSION_ID < 80000) {
×
61
            $system_issues = true;
×
62
        }
63

64
        if ($system_issues) {
×
65
            $suggestions[] = [
×
66
                "message" => "Upgrade Composer and/or PHP to a more modern/supported version",
×
67
                "link" => "https://docs.cweagans.net/composer-patches/troubleshooting/guide#upgrade-system-software"
×
68
            ];
×
69
        }
70

71
        $io->write("");
×
72
        $io->write("<info>Available patchers</info>");
×
73
        $io->write("================================================================================");
×
74
        $has_usable_patcher = false;
×
75
        foreach ($capabilities as $capability) {
×
76
            /** @var PatcherProvider $capability */
77
            $newPatchers = $capability->getPatchers();
×
78
            foreach ($newPatchers as $i => $patcher) {
×
79
                if (!$patcher instanceof PatcherInterface) {
×
80
                    throw new \UnexpectedValueException(
×
81
                        'Plugin capability ' . get_class($capability) . ' returned an invalid value.'
×
82
                    );
×
83
                }
84

85
                $usable = $patcher->canUse();
×
86
                $has_usable_patcher = $has_usable_patcher || $usable;
×
87
                $io->write(
×
88
                    str_pad(get_class($patcher) . " usable: ", 77) .
×
89
                    ($usable ? "<info>yes</info>" : " no")
×
90
                );
×
91
            }
92
        }
93

94
        $io->write(
×
95
            str_pad(
×
96
                "Has usable patchers: ",
×
97
                77
×
98
            ) . ($has_usable_patcher ? "<info>yes</info>" : " <error>no</error>")
×
99
        );
×
100

101
        if (!$has_usable_patcher) {
×
102
            $suggestions[] = [
×
103
                "message" => "Install software dependencies for applying patches",
×
104
                "link" => "https://docs.cweagans.net/composer-patches/troubleshooting/guide#install-patching-software"
×
105
            ];
×
106
        }
107

108

109
        $io->write("");
×
110
        $io->write("<info>Common configuration issues</info>");
×
111
        $io->write("================================================================================");
×
112
        $preferred_install_issues = false;
×
113
        $pi = $composer->getConfig()->get('preferred-install');
×
114
        $io->write(
×
115
            str_pad("preferred-install is set:", 77) . (is_null($pi) ? " <warning>no</warning>" : "<info>yes</info>")
×
116
        );
×
117

118
        if (is_null($pi)) {
×
119
            $preferred_install_issues = true;
×
120
        }
121

122
        if (is_string($pi)) {
×
123
            $io->write(
×
124
                str_pad("preferred-install set to 'source' for all/some packages:", 77) .
×
125
                ($pi === "source" ? "<info>yes</info>" : " <warning>no</warning>")
×
126
            );
×
127
        }
128

129
        if (is_string($pi) && $pi !== "source") {
×
130
            $preferred_install_issues = true;
×
131
        }
132

133
        if (is_array($pi)) {
×
134
            $patched_packages = $plugin->getPatchCollection()->getPatchedPackages();
×
135
            foreach ($patched_packages as $package) {
×
136
                if (in_array($package, array_values($pi))) {
×
137
                    $io->write(
×
138
                        str_pad("preferred-install set to 'source' for $package:", 77) . "<info>yes</info>"
×
139
                    );
×
140
                    continue;
×
141
                }
142

143
                foreach ($pi as $pattern => $value) {
×
144
                    $pattern = strtr($pattern, ['*' => '.*', '/' => '\/']);
×
145
                    if (preg_match("/$pattern/", $package)) {
×
146
                        $io->write(
×
147
                            str_pad("preferred-install set to 'source' for $package:", 77) .
×
148
                            ($value === "source" ? "<info>yes</info>" : " <warning>no</warning>")
×
149
                        );
×
150

151
                        if ($value !== "source") {
×
152
                            $preferred_install_issues = true;
×
153
                        }
154

155
                        break 2;
×
156
                    }
157
                }
158

159
                $preferred_install_issues = true;
×
160
            }
161
        }
162

163
        if ($preferred_install_issues) {
×
164
            $suggestions[] = [
×
165
                "message" => "Setting 'preferred-install' to 'source' either globally or for each patched dependency " .
×
166
                    "is highly recommended for consistent results",
×
167
                "link" =>
×
168
                    "https://docs.cweagans.net/composer-patches/troubleshooting/guide#set-preferred-install-to-source"
×
169
            ];
×
170
        }
171

172
        $has_http_urls = false;
×
173
        foreach ($plugin->getPatchCollection()->getPatchedPackages() as $package) {
×
174
            foreach ($plugin->getPatchCollection()->getPatchesForPackage($package) as $patch) {
×
175
                if (str_starts_with($patch->url, 'http://')) {
×
176
                    $has_http_urls = true;
×
177
                    break 2;
×
178
                }
179
            }
180
        }
181

182
        $io->write(
×
183
            str_pad("has plain http patch URLs:", 77) . ($has_http_urls ? "<warning>yes</warning>" : " <info>no</info>")
×
184
        );
×
185
        if ($has_http_urls) {
×
186
            $sh = $composer->getConfig()->get('secure-http');
×
187
            $io->write(
×
188
                str_pad('secure-http disabled:', 77) . ($sh ? " <error>no</error>" : "<info>yes</info>")
×
189
            );
×
190

191
            if ($sh) {
×
192
                $suggestions[] = [
×
193
                    "message" => "Patches must either be downloaded securely or 'secure-http' must be disabled",
×
194
                    "link" =>
×
195
                        "https://docs.cweagans.net/composer-patches/troubleshooting/guide#download-patches-securely"
×
196
                ];
×
197
            }
198
        }
199

200
        if (!empty($suggestions)) {
×
201
            $io->write("");
×
202
            $io->write("<info>Suggestions</info>");
×
203
            $io->write("================================================================================");
×
204
            foreach ($suggestions as $suggestion) {
×
205
                $io->write(" - " . $suggestion['message']);
×
206
                $io->write("   More information: " . $suggestion['link']);
×
207
            }
208
        }
209

210

211
        return 0;
×
212
    }
213
}
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