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

eliashaeussler / composer-update-check / 10285821446

07 Aug 2024 02:02PM UTC coverage: 25.504%. First build
10285821446

Pull #130

github

web-flow
Merge ed00778d6 into 7d4f7bd74
Pull Request #130: [!!!][FEATURE] Modernize plugin

328 of 1362 new or added lines in 47 files covered. (24.08%)

354 of 1388 relevant lines covered (25.5%)

1.34 hits per line

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

0.0
/src/Entity/Report/SlackReport.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\Entity\Report;
25

26
use EliasHaeussler\ComposerUpdateCheck\Entity;
27
use JsonSerializable;
28

29
use function count;
30
use function implode;
31
use function sprintf;
32

33
/**
34
 * SlackReport.
35
 *
36
 * @author Elias Häußler <elias@haeussler.dev>
37
 * @license GPL-3.0-or-later
38
 */
39
final class SlackReport implements JsonSerializable
40
{
41
    private const MAX_BLOCKS = 45;
42

43
    /**
44
     * @param list<Dto\SlackBlock> $blocks
45
     */
NEW
46
    private function __construct(
×
47
        public readonly array $blocks,
NEW
48
    ) {}
×
49

NEW
50
    public static function create(
×
51
        Entity\Result\UpdateCheckResult $result,
52
        string $rootPackageName = null,
53
    ): self {
NEW
54
        $remainingBlocks = self::MAX_BLOCKS;
×
NEW
55
        $remainingPackages = count($result->getOutdatedPackages());
×
56

57
        // Create header block
NEW
58
        $blocks = [
×
NEW
59
            self::createHeaderBlock($result),
×
NEW
60
        ];
×
61

62
        // Create package name block
NEW
63
        if (null !== $rootPackageName) {
×
NEW
64
            $blocks[] = self::createPackageNameBlock($rootPackageName);
×
65
        }
66

67
        // Create outdated package blocks
NEW
68
        foreach ($result->getOutdatedPackages() as $outdatedPackage) {
×
NEW
69
            if (--$remainingBlocks > 0) {
×
NEW
70
                $blocks[] = self::createOutdatedPackageBlock($outdatedPackage);
×
71
            } else {
72
                // Slack allows only a limited number of blocks, therefore
73
                // we have to omit the remaining packages and show a message instead
NEW
74
                $blocks[] = self::createMoreBlock($remainingPackages);
×
75
            }
76

NEW
77
            --$remainingPackages;
×
78
        }
79

80
        // Create security advisories block
NEW
81
        if ($remainingBlocks > 4) {
×
NEW
82
            $remainingSecurityAdvisories = count($result->getSecurityAdvisories());
×
NEW
83
            $remainingBlocks -= 2;
×
NEW
84
            $blocks[] = Dto\SlackBlock::header(
×
NEW
85
                Dto\SlackBlockElement::plainText('Security advisories'),
×
NEW
86
            );
×
87

NEW
88
            foreach ($result->getSecurityAdvisories() as $securityAdvisory) {
×
NEW
89
                if (--$remainingBlocks > 1) {
×
NEW
90
                    $blocks[] = self::createSecurityAdvisoryBlock($securityAdvisory);
×
91
                } else {
92
                    // Slack allows only a limited number of blocks, therefore
93
                    // we have to omit the remaining security advisories and show a message instead
NEW
94
                    $blocks[] = self::createMoreBlock($remainingSecurityAdvisories);
×
95
                }
96

NEW
97
                --$remainingSecurityAdvisories;
×
98
            }
99
        }
100

NEW
101
        return new self($blocks);
×
102
    }
103

NEW
104
    private static function createHeaderBlock(Entity\Result\UpdateCheckResult $result): Dto\SlackBlock
×
105
    {
NEW
106
        $numberOfOutdatedPackages = 0;
×
NEW
107
        $numberOfInsecurePackages = 0;
×
108

109
        // Count outdated and insecure packages
NEW
110
        foreach ($result->getOutdatedPackages() as $outdatedPackage) {
×
NEW
111
            ++$numberOfOutdatedPackages;
×
112

NEW
113
            if ($outdatedPackage->isInsecure()) {
×
NEW
114
                ++$numberOfInsecurePackages;
×
115
            }
116
        }
117

NEW
118
        return Dto\SlackBlock::header(
×
NEW
119
            Dto\SlackBlockElement::plainText(
×
NEW
120
                sprintf(
×
NEW
121
                    '%d outdated%s package%s',
×
NEW
122
                    $numberOfOutdatedPackages,
×
NEW
123
                    $numberOfInsecurePackages > 0 ? sprintf(' (%d insecure)', $numberOfInsecurePackages) : '',
×
NEW
124
                    1 !== $numberOfOutdatedPackages ? 's' : '',
×
NEW
125
                ),
×
NEW
126
            ),
×
NEW
127
        );
×
128
    }
129

NEW
130
    private static function createPackageNameBlock(string $rootPackageName): Dto\SlackBlock
×
131
    {
NEW
132
        return Dto\SlackBlock::section(
×
NEW
133
            Dto\SlackBlockElement::markdown(
×
NEW
134
                sprintf('Project: *%s*', $rootPackageName),
×
NEW
135
            ),
×
NEW
136
        );
×
137
    }
138

NEW
139
    private static function createOutdatedPackageBlock(Entity\Package\OutdatedPackage $outdatedPackage): Dto\SlackBlock
×
140
    {
NEW
141
        $highestSeverityLevel = $outdatedPackage->getHighestSeverityLevel();
×
142

NEW
143
        return Dto\SlackBlock::section(
×
NEW
144
            fields: [
×
NEW
145
                Dto\SlackBlockElement::markdown(
×
NEW
146
                    sprintf(
×
NEW
147
                        '<%s|%s>%s',
×
NEW
148
                        $outdatedPackage->getProviderLink(),
×
NEW
149
                        $outdatedPackage->getName(),
×
NEW
150
                        null !== $highestSeverityLevel
×
NEW
151
                            ? sprintf(
×
NEW
152
                                "\n%s `%s`",
×
NEW
153
                                self::getEmojiForSeverityLevel($highestSeverityLevel),
×
NEW
154
                                $highestSeverityLevel->value,
×
NEW
155
                            ) : '',
×
NEW
156
                    ),
×
NEW
157
                ),
×
NEW
158
                Dto\SlackBlockElement::markdown(
×
NEW
159
                    sprintf(
×
NEW
160
                        "*Current version:* %s\n*New version:* %s",
×
NEW
161
                        $outdatedPackage->getOutdatedVersion()->toString(),
×
NEW
162
                        $outdatedPackage->getNewVersion()->toString(),
×
NEW
163
                    ),
×
NEW
164
                ),
×
NEW
165
            ],
×
NEW
166
        );
×
167
    }
168

NEW
169
    private static function createSecurityAdvisoryBlock(
×
170
        Entity\Security\SecurityAdvisory $securityAdvisory,
171
    ): Dto\SlackBlock {
NEW
172
        $textParts = [
×
NEW
173
            sprintf('*%s*', $securityAdvisory->getSanitizedTitle()),
×
NEW
174
            sprintf('• Package: `%s`', $securityAdvisory->getPackageName()),
×
NEW
175
            sprintf(
×
NEW
176
                '• Reported at: `<!date^%d^{date}|%s>`',
×
NEW
177
                $securityAdvisory->getReportedAt()->getTimestamp(),
×
NEW
178
                $securityAdvisory->getReportedAt()->format('Y-m-d'),
×
NEW
179
            ),
×
NEW
180
        ];
×
181

NEW
182
        if (null !== $securityAdvisory->getCVE()) {
×
NEW
183
            $textParts[] = sprintf('• CVE: `%s`', $securityAdvisory->getCVE());
×
184
        }
185

NEW
186
        if (null !== $securityAdvisory->getLink()) {
×
NEW
187
            $textParts[] = sprintf('<%s|Read more>', $securityAdvisory->getLink());
×
188
        }
189

NEW
190
        return Dto\SlackBlock::section(
×
NEW
191
            Dto\SlackBlockElement::markdown(
×
NEW
192
                implode(PHP_EOL, $textParts),
×
NEW
193
            ),
×
NEW
194
        );
×
195
    }
196

NEW
197
    private static function createMoreBlock(int $remaining): Dto\SlackBlock
×
198
    {
NEW
199
        return Dto\SlackBlock::section(
×
NEW
200
            Dto\SlackBlockElement::markdown(
×
NEW
201
                sprintf('_... and %d more_', $remaining),
×
NEW
202
            ),
×
NEW
203
        );
×
204
    }
205

NEW
206
    private static function getEmojiForSeverityLevel(Entity\Security\SeverityLevel $severityLevel): string
×
207
    {
NEW
208
        return match ($severityLevel) {
×
NEW
209
            Entity\Security\SeverityLevel::Low => ':white_circle:',
×
NEW
210
            Entity\Security\SeverityLevel::Medium => ':large_yellow_circle:',
×
NEW
211
            Entity\Security\SeverityLevel::High => ':large_orange_circle:',
×
NEW
212
            Entity\Security\SeverityLevel::Critical => ':red_circle:',
×
NEW
213
        };
×
214
    }
215

216
    /**
217
     * @return array{
218
     *     blocks: list<Dto\SlackBlock>,
219
     * }
220
     */
NEW
221
    public function jsonSerialize(): array
×
222
    {
NEW
223
        return [
×
NEW
224
            'blocks' => $this->blocks,
×
NEW
225
        ];
×
226
    }
227
}
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