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

eliashaeussler / composer-update-check / 12289048626

12 Dec 2024 12:25AM UTC coverage: 20.582%. First build
12289048626

Pull #130

github

web-flow
[TASK] Update all dependencies
Pull Request #130: [!!!][FEATURE] Modernize plugin

356 of 1828 new or added lines in 57 files covered. (19.47%)

382 of 1856 relevant lines covered (20.58%)

1.11 hits per line

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

0.0
/src/IO/Formatter/GitLabFormatter.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-2024 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\IO\Formatter;
25

26
use Composer\Factory;
27
use Composer\Util;
28
use DateTimeImmutable;
29
use DateTimeInterface;
30
use EliasHaeussler\ComposerUpdateCheck\Entity;
31
use Symfony\Component\Console;
32
use Symfony\Component\Filesystem;
33

34
use function count;
35
use function json_encode;
36
use function md5;
37
use function sprintf;
38

39
/**
40
 * GitLabFormatter.
41
 *
42
 * @author Elias Häußler <elias@haeussler.dev>
43
 * @license GPL-3.0-or-later
44
 */
45
final class GitLabFormatter implements Formatter
46
{
47
    public const FORMAT = 'gitlab';
48

NEW
49
    public function __construct(
×
50
        private ?Console\Style\SymfonyStyle $io = null,
NEW
51
    ) {}
×
52

NEW
53
    public function formatResult(Entity\Result\UpdateCheckResult $result): void
×
54
    {
55
        // Early return if IO is missing
NEW
56
        if (null === $this->io) {
×
NEW
57
            return;
×
58
        }
59

NEW
60
        $this->renderCodeQualityArtifact(
×
NEW
61
            $this->buildDescription($result),
×
NEW
62
            $this->calculateSeverity($result),
×
NEW
63
            $result,
×
NEW
64
        );
×
65
    }
66

NEW
67
    private function buildDescription(Entity\Result\UpdateCheckResult $result): string
×
68
    {
NEW
69
        $numberOfOutdatedPackages = count($result->getOutdatedPackages());
×
NEW
70
        $numberOfExcludedPackages = count($result->getExcludedPackages());
×
71

NEW
72
        if ($numberOfExcludedPackages > 0) {
×
NEW
73
            $additionalInformation = sprintf(
×
NEW
74
                ' (skipped %d package%s)',
×
NEW
75
                $numberOfExcludedPackages,
×
NEW
76
                1 !== $numberOfExcludedPackages ? 's' : '',
×
NEW
77
            );
×
78
        } else {
NEW
79
            $additionalInformation = '';
×
80
        }
81

NEW
82
        if (0 === $numberOfOutdatedPackages) {
×
NEW
83
            return sprintf('All packages are up to date%s.', $additionalInformation);
×
84
        }
85

NEW
86
        if (1 === $numberOfOutdatedPackages) {
×
NEW
87
            return sprintf('1 package is outdated%s.', $additionalInformation);
×
88
        }
89

NEW
90
        return sprintf('%d packages are outdated%s.', $numberOfOutdatedPackages, $additionalInformation);
×
91
    }
92

NEW
93
    private function calculateSeverity(Entity\Result\UpdateCheckResult $result): string
×
94
    {
NEW
95
        if ([] === $result->getOutdatedPackages()) {
×
NEW
96
            return 'info';
×
97
        }
98

NEW
99
        $securityAdvisories = $result->getSecurityAdvisories();
×
100

NEW
101
        if ([] === $securityAdvisories) {
×
NEW
102
            return 'minor';
×
103
        }
104

NEW
105
        $severityLevels = array_map(
×
NEW
106
            static fn (Entity\Security\SecurityAdvisory $securityAdvisory) => $securityAdvisory->getSeverity(),
×
NEW
107
            $securityAdvisories,
×
NEW
108
        );
×
NEW
109
        $highestSeverityLevel = Entity\Security\SeverityLevel::getHighestSeverityLevel(...$severityLevels);
×
110

111
        return match ($highestSeverityLevel) {
NEW
112
            Entity\Security\SeverityLevel::High => 'critical',
×
NEW
113
            default => 'major',
×
114
        };
115
    }
116

NEW
117
    private function renderCodeQualityArtifact(
×
118
        string $description,
119
        string $severity,
120
        Entity\Result\UpdateCheckResult $result,
121
    ): void {
122
        // Early return if output is quiet
NEW
123
        if (false !== $this->io?->isQuiet()) {
×
NEW
124
            return;
×
125
        }
126

127
        // Resolve path to composer.json file
NEW
128
        $composerFile = Filesystem\Path::makeRelative(
×
NEW
129
            (string) realpath(Factory::getComposerFile()),
×
NEW
130
            Util\Platform::getCwd(),
×
NEW
131
        );
×
132

NEW
133
        $flags = JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR;
×
134

135
        // Pretty-print JSON on verbose output
NEW
136
        if ($this->io->isVerbose()) {
×
NEW
137
            $flags |= JSON_PRETTY_PRINT;
×
138
        }
139

NEW
140
        $this->io->writeln(
×
NEW
141
            json_encode(
×
NEW
142
                [
×
NEW
143
                    'description' => $description,
×
NEW
144
                    'check_name' => 'composer-update-check',
×
NEW
145
                    'fingerprint' => $this->calculateFingerprint($result),
×
NEW
146
                    'severity' => $severity,
×
NEW
147
                    'location' => [
×
NEW
148
                        'path' => $composerFile,
×
NEW
149
                        'lines' => [
×
NEW
150
                            'begin' => 1,
×
NEW
151
                        ],
×
NEW
152
                    ],
×
NEW
153
                ],
×
NEW
154
                $flags,
×
NEW
155
            ),
×
NEW
156
        );
×
157
    }
158

NEW
159
    private function calculateFingerprint(Entity\Result\UpdateCheckResult $result): string
×
160
    {
NEW
161
        $json = json_encode(
×
NEW
162
            [
×
NEW
163
                'outdatedPackages' => $result->getOutdatedPackages(),
×
NEW
164
                'excludedPackages' => $result->getExcludedPackages(),
×
NEW
165
                'reportDate' => (new DateTimeImmutable())->format(DateTimeInterface::ATOM),
×
NEW
166
            ],
×
NEW
167
            JSON_THROW_ON_ERROR,
×
NEW
168
        );
×
169

NEW
170
        return md5($json);
×
171
    }
172

NEW
173
    public function setIO(Console\Style\SymfonyStyle $io): void
×
174
    {
NEW
175
        $this->io = $io;
×
176
    }
177

NEW
178
    public static function getFormat(): string
×
179
    {
NEW
180
        return self::FORMAT;
×
181
    }
182
}
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

© 2025 Coveralls, Inc