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

eliashaeussler / composer-update-check / 30671619636

31 Jul 2026 04:41PM UTC coverage: 21.308%. First build
30671619636

Pull #130

github

web-flow
[TASK] Update eliashaeussler/gha action to v0.9.3

| datasource  | package            | from  | to    |
| ----------- | ------------------ | ----- | ----- |
| github-tags | eliashaeussler/gha | 0.9.2 | 0.9.3 |
Pull Request #130: [!!!][FEATURE] Modernize plugin

384 of 1874 new or added lines in 57 files covered. (20.49%)

404 of 1896 relevant lines covered (21.31%)

1.18 hits per line

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

93.0
/src/Composer/Installer.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "eliashaeussler/composer-update-check".
7
 *
8
 * Copyright (C) 2020-2026 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\ComposerUpdateCheck\Composer;
25

26
use Composer\Advisory\AuditConfig;
27
use Composer\Composer;
28
use Composer\DependencyResolver;
29
use Composer\Factory;
30
use Composer\Installer as ComposerInstaller;
31
use Composer\IO;
32
use Composer\Package;
33
use Composer\Repository;
34
use EliasHaeussler\ComposerUpdateCheck\Entity;
35

36
use function array_map;
37
use function array_values;
38
use function method_exists;
39

40
/**
41
 * Installer.
42
 *
43
 * @author Elias Häußler <elias@haeussler.dev>
44
 * @license GPL-3.0-or-later
45
 *
46
 * @internal
47
 */
48
final readonly class Installer
49
{
50
    public function __construct(
5✔
51
        private Composer $composer,
52
    ) {}
5✔
53

54
    public function runInstall(?IO\IOInterface $io = null): int
5✔
55
    {
56
        $io ??= new IO\NullIO();
5✔
57

58
        $composer = $this->buildComposer($io);
5✔
59
        $preferredInstall = $composer->getConfig()->get('preferred-install');
5✔
60
        $installer = ComposerInstaller::create($io, $composer)
5✔
61
            ->setPreferSource('source' === $preferredInstall)
5✔
62
            ->setPreferDist('dist' === $preferredInstall)
5✔
63
            ->setDevMode()
5✔
64
        ;
5✔
65

66
        $this->disableAudit($installer, $composer);
5✔
67

68
        return $installer->run();
5✔
69
    }
70

71
    /**
72
     * @param list<Entity\Package\Package> $packages
73
     */
74
    public function runUpdate(array $packages, ?IO\IOInterface $io = null): Entity\Result\ComposerUpdateResult
4✔
75
    {
76
        $io ??= new IO\NullIO();
4✔
77

78
        $outdatedPackages = [];
4✔
79
        $allowedPackageNames = array_map(
4✔
80
            static fn (Entity\Package\Package $package) => $package->getName(),
4✔
81
            $packages,
4✔
82
        );
4✔
83

84
        // Inject installer logger
85
        $composer = $this->buildComposer($io);
4✔
86
        $composer->getInstallationManager()->addInstaller(
4✔
87
            $this->mockInstaller($allowedPackageNames, $outdatedPackages),
4✔
88
        );
4✔
89

90
        // Disable writing of package updates in local repository
91
        $composer->getRepositoryManager()->setLocalRepository(
4✔
92
            $this->mockLocalRepository($composer->getRepositoryManager()->getLocalRepository()),
4✔
93
        );
4✔
94

95
        // Disable lock file management
96
        $composer->getConfig()->merge([
4✔
97
            'config' => [
4✔
98
                'lock' => false,
4✔
99
            ],
4✔
100
        ]);
4✔
101

102
        $preferredInstall = $composer->getConfig()->get('preferred-install');
4✔
103
        $installer = ComposerInstaller::create($io, $composer)
4✔
104
            ->setPreferSource('source' === $preferredInstall)
4✔
105
            ->setPreferDist('dist' === $preferredInstall)
4✔
106
            ->setDevMode()
4✔
107
            ->setUpdate(true)
4✔
108
            ->setDumpAutoloader(false)
4✔
109
            ->setUpdateAllowList($allowedPackageNames)
4✔
110
            ->setUpdateAllowTransitiveDependencies(DependencyResolver\Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS)
4✔
111
        ;
4✔
112

113
        $this->disableAudit($installer, $composer);
4✔
114

115
        return new Entity\Result\ComposerUpdateResult(
4✔
116
            $installer->run(),
4✔
117
            array_values($outdatedPackages),
4✔
118
        );
4✔
119
    }
120

121
    /**
122
     * @param list<non-empty-string>                                  $allowedPackageNames
123
     * @param array<non-empty-string, Entity\Package\OutdatedPackage> $outdatedPackages
124
     */
125
    private function mockInstaller(
4✔
126
        array $allowedPackageNames,
127
        array &$outdatedPackages,
128
    ): ComposerInstaller\InstallerInterface {
129
        return new class($allowedPackageNames, $outdatedPackages) extends ComposerInstaller\NoopInstaller {
4✔
130
            /**
131
             * @param list<non-empty-string>                                  $allowedPackageNames
132
             * @param array<non-empty-string, Entity\Package\OutdatedPackage> $outdatedPackages
133
             */
134
            public function __construct(
135
                private readonly array $allowedPackageNames,
136
                private array &$outdatedPackages,
137
            ) {}
4✔
138

139
            public function update(
140
                Repository\InstalledRepositoryInterface $repo,
141
                Package\PackageInterface $initial,
142
                Package\PackageInterface $target,
143
            ) {
144
                $promise = parent::update($repo, $initial, $target);
4✔
145
                /** @var non-empty-string $name */
146
                $name = $initial->getName();
4✔
147

148
                if ($this->isSuitableUpdate($initial, $target)) {
4✔
149
                    $includeSha1 = $initial->getPrettyVersion() === $target->getPrettyVersion();
3✔
150

151
                    $this->outdatedPackages[$name] = new Entity\Package\OutdatedPackage(
3✔
152
                        $name,
3✔
153
                        new Entity\Version(
3✔
154
                            $initial->getPrettyVersion(),
3✔
155
                            $includeSha1 ? ($initial->getDistReference() ?? $initial->getSourceReference()) : null,
3✔
156
                        ),
3✔
157
                        new Entity\Version(
3✔
158
                            $target->getPrettyVersion(),
3✔
159
                            $includeSha1 ? ($target->getDistReference() ?? $target->getSourceReference()) : null,
3✔
160
                        ),
3✔
161
                    );
3✔
162
                }
163

164
                return $promise;
4✔
165
            }
166

167
            private function isSuitableUpdate(
168
                Package\PackageInterface $initial,
169
                Package\PackageInterface $target,
170
            ): bool {
171
                $name = $initial->getName();
4✔
172

173
                if (!in_array($name, $this->allowedPackageNames, true)) {
4✔
174
                    return false;
3✔
175
                }
176

177
                if (array_key_exists($name, $this->outdatedPackages)) {
3✔
NEW
178
                    return false;
×
179
                }
180

181
                if ($initial->getPrettyVersion() !== $target->getPrettyVersion()) {
3✔
182
                    return true;
2✔
183
                }
184

185
                if ($initial->getSourceReference() !== $target->getSourceReference()) {
1✔
186
                    return true;
1✔
187
                }
188

NEW
189
                if ($initial->getDistReference() !== $target->getDistReference()) {
×
NEW
190
                    return true;
×
191
                }
192

NEW
193
                return false;
×
194
            }
195
        };
4✔
196
    }
197

198
    private function mockLocalRepository(
4✔
199
        Repository\InstalledRepositoryInterface $repository,
200
    ): Repository\InstalledRepositoryInterface {
201
        $newRepository = new Repository\InstalledArrayRepository();
4✔
202
        $newRepository->setDevPackageNames($repository->getDevPackageNames());
4✔
203

204
        foreach ($repository->getPackages() as $package) {
4✔
205
            $newPackage = clone $package;
4✔
206
            $newPackage->setId($package->getId());
4✔
207
            $newRepository->addPackage($newPackage);
4✔
208
        }
209

210
        return $newRepository;
4✔
211
    }
212

213
    private function buildComposer(IO\IOInterface $io): Composer
5✔
214
    {
215
        $composer = Factory::create($io, $this->composer->getConfig()->getConfigSource()->getName(), true);
5✔
216
        $composer->getEventDispatcher()->setRunScripts(false);
5✔
217
        $composer->getAutoloadGenerator()->setRunScripts(false);
5✔
218

219
        return $composer;
5✔
220
    }
221

222
    private function disableAudit(ComposerInstaller $installer, Composer $composer): void
5✔
223
    {
224
        if (method_exists($installer, 'setAuditConfig')) {
5✔
225
            if (method_exists(AuditConfig::class, 'fromConfig')) {
5✔
226
                // Composer 2.9
NEW
227
                $auditConfig = AuditConfig::fromConfig($composer->getConfig(), false);
×
228
            } else {
229
                // Composer >= 2.10
230
                $auditConfig = new AuditConfig(false);
5✔
231
            }
232

233
            $installer->setAuditConfig($auditConfig);
5✔
NEW
234
        } elseif (method_exists($installer, 'setAudit')) {
×
235
            // Composer < 2.9
NEW
236
            $installer->setAudit(false);
×
237
        }
238
    }
239
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc