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

eliashaeussler / composer-update-check / 15182034191

22 May 2025 03:06AM UTC coverage: 20.538%. First build
15182034191

Pull #130

github

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

356 of 1832 new or added lines in 57 files covered. (19.43%)

382 of 1860 relevant lines covered (20.54%)

1.11 hits per line

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

0.0
/src/IO/Formatter/TextFormatter.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-2025 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 EliasHaeussler\ComposerUpdateCheck\Entity;
27
use Symfony\Component\Console;
28

29
use function count;
30
use function sprintf;
31

32
/**
33
 * TextFormatter.
34
 *
35
 * @author Elias Häußler <elias@haeussler.dev>
36
 * @license GPL-3.0-or-later
37
 */
38
final class TextFormatter implements Formatter
39
{
40
    public const FORMAT = 'text';
41

NEW
42
    public function __construct(
×
43
        private ?Console\Style\SymfonyStyle $io = null,
NEW
44
    ) {}
×
45

NEW
46
    public function formatResult(Entity\Result\UpdateCheckResult $result): void
×
47
    {
48
        // Early return if IO is missing
NEW
49
        if (null === $this->io) {
×
NEW
50
            return;
×
51
        }
52

NEW
53
        $outdatedPackages = $result->getOutdatedPackages();
×
NEW
54
        $excludedPackages = $result->getExcludedPackages();
×
NEW
55
        $numberOfOutdatedPackages = count($outdatedPackages);
×
56

57
        // Print message if no packages are outdated
NEW
58
        if ([] === $outdatedPackages) {
×
NEW
59
            $this->renderUpToDateMessage($excludedPackages);
×
60

NEW
61
            return;
×
62
        }
63

64
        // Print header
NEW
65
        if (1 === $numberOfOutdatedPackages) {
×
NEW
66
            $this->io->warning('1 package is outdated.');
×
67
        } else {
NEW
68
            $this->io->warning(
×
NEW
69
                sprintf('%d packages are outdated.', $numberOfOutdatedPackages),
×
NEW
70
            );
×
71
        }
72

NEW
73
        $this->renderTable($outdatedPackages);
×
NEW
74
        $this->renderSecurityAdvisories($outdatedPackages);
×
75
    }
76

77
    /**
78
     * @param list<Entity\Package\Package> $excludedPackages
79
     */
NEW
80
    private function renderUpToDateMessage(array $excludedPackages): void
×
81
    {
NEW
82
        $numberOfExcludedPackages = count($excludedPackages);
×
83

NEW
84
        if ($numberOfExcludedPackages > 0) {
×
NEW
85
            $additionalInformation = sprintf(
×
NEW
86
                ' (skipped %d package%s)',
×
NEW
87
                $numberOfExcludedPackages,
×
NEW
88
                1 !== $numberOfExcludedPackages ? 's' : '',
×
NEW
89
            );
×
90
        } else {
NEW
91
            $additionalInformation = '';
×
92
        }
93

NEW
94
        $this->io?->success(
×
NEW
95
            sprintf('All packages are up to date%s.', $additionalInformation),
×
NEW
96
        );
×
97
    }
98

99
    /**
100
     * @param list<Entity\Package\OutdatedPackage> $outdatedPackages
101
     */
NEW
102
    private function renderTable(array $outdatedPackages): void
×
103
    {
NEW
104
        $tableRows = [];
×
105

106
        // Parse table rows
NEW
107
        foreach ($outdatedPackages as $outdatedPackage) {
×
NEW
108
            $report = [
×
NEW
109
                $outdatedPackage->getName(),
×
NEW
110
                $outdatedPackage->getOutdatedVersion()->toString(),
×
NEW
111
                $outdatedPackage->getNewVersion()->toString(),
×
NEW
112
            ];
×
113

NEW
114
            if ($outdatedPackage->isInsecure()) {
×
NEW
115
                $report[1] .= ' <fg=red;options=bold>insecure</>';
×
116
            }
117

NEW
118
            $tableRows[] = $report;
×
119
        }
120

121
        // Print table
NEW
122
        $this->io?->table(['Package', 'Outdated version', 'New version'], $tableRows);
×
123
    }
124

125
    /**
126
     * @param list<Entity\Package\OutdatedPackage> $outdatedPackages
127
     */
NEW
128
    private function renderSecurityAdvisories(array $outdatedPackages): void
×
129
    {
NEW
130
        if (true !== $this->io?->isVerbose()) {
×
NEW
131
            return;
×
132
        }
133

NEW
134
        foreach ($outdatedPackages as $outdatedPackage) {
×
NEW
135
            if (!$outdatedPackage->isInsecure()) {
×
NEW
136
                continue;
×
137
            }
138

NEW
139
            $this->io->title(
×
NEW
140
                sprintf('Security advisories for "%s"', $outdatedPackage->getName()),
×
NEW
141
            );
×
142

NEW
143
            foreach ($outdatedPackage->getSecurityAdvisories() as $securityAdvisory) {
×
NEW
144
                $link = $securityAdvisory->getLink();
×
145

NEW
146
                $this->io->section($securityAdvisory->getSanitizedTitle());
×
147

NEW
148
                $definitionList = [
×
NEW
149
                    ['ID' => $securityAdvisory->getAdvisoryId()],
×
NEW
150
                    ['Reported at' => $securityAdvisory->getReportedAt()->format('Y-m-d')],
×
NEW
151
                    ['Severity' => $securityAdvisory->getSeverity()->value],
×
NEW
152
                    ['CVE' => $securityAdvisory->getCVE() ?? '<fg=gray>Unknown</>'],
×
NEW
153
                ];
×
154

NEW
155
                if (null !== $link) {
×
NEW
156
                    $definitionList[] = new Console\Helper\TableSeparator();
×
NEW
157
                    $definitionList[] = ['Read more' => (string) $link];
×
158
                }
159

NEW
160
                $this->io->definitionList(...$definitionList);
×
161
            }
162
        }
163
    }
164

NEW
165
    public function setIO(Console\Style\SymfonyStyle $io): void
×
166
    {
NEW
167
        $this->io = $io;
×
168
    }
169

NEW
170
    public static function getFormat(): string
×
171
    {
NEW
172
        return self::FORMAT;
×
173
    }
174
}
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