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

eliashaeussler / composer-update-check / 20746055334

06 Jan 2026 10:51AM UTC coverage: 21.62%. First build
20746055334

Pull #130

github

web-flow
Merge pull request #212 from eliashaeussler/task/task-runner
Pull Request #130: [!!!][FEATURE] Modernize plugin

389 of 1877 new or added lines in 57 files covered. (20.72%)

411 of 1901 relevant lines covered (21.62%)

1.19 hits per line

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

0.0
/src/Reporter/MattermostReporter.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\Reporter;
25

26
use Composer\IO;
27
use EliasHaeussler\ComposerUpdateCheck\Entity;
28
use EliasHaeussler\TaskRunner;
29
use GuzzleHttp\Client;
30
use GuzzleHttp\Exception;
31
use GuzzleHttp\Psr7;
32
use GuzzleHttp\RequestOptions;
33
use Symfony\Component\Console;
34
use Symfony\Component\OptionsResolver;
35

36
use function assert;
37
use function is_string;
38

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

49
    private OptionsResolver\OptionsResolver $resolver;
50
    private TaskRunner\TaskRunner $taskRunner;
51

NEW
52
    public function __construct(
×
53
        private Client $client,
54
        private IO\IOInterface $io,
55
    ) {
NEW
56
        $this->resolver = $this->createOptionsResolver();
×
NEW
57
        $this->taskRunner = new TaskRunner\TaskRunner($this->io);
×
58
    }
59

NEW
60
    public function report(Entity\Result\UpdateCheckResult $result, array $options): bool
×
61
    {
62
        // Early return if no packages are outdated
NEW
63
        if (!$result->hasOutdatedPackages()) {
×
NEW
64
            $this->io->writeError('🚫 Skipped Mattermost report', true, IO\IOInterface::VERBOSE);
×
65

NEW
66
            return true;
×
67
        }
68

69
        // Resolve configuration options
NEW
70
        ['url' => $url, 'channel' => $channel, 'username' => $username] = $this->resolver->resolve($options);
×
71

72
        // Make PHPStan happy
73
        assert(is_string($url));
74
        assert(is_string($channel));
75
        assert(is_string($username) || null === $username);
76

77
        // Create report
NEW
78
        $report = Entity\Report\MattermostReport::create($channel, $username, $result);
×
79

80
        // Send report
NEW
81
        return $this->taskRunner->run(
×
NEW
82
            '📤 Sending report to Mattermost',
×
NEW
83
            function (TaskRunner\RunnerContext $context) use ($url, $report) {
×
84
                try {
NEW
85
                    $response = $this->client->post($url, [
×
NEW
86
                        RequestOptions::JSON => $report,
×
NEW
87
                    ]);
×
NEW
88
                    $context->successful = 200 === $response->getStatusCode();
×
NEW
89
                } catch (Exception\GuzzleException) {
×
NEW
90
                    $context->successful = false;
×
91
                }
92

NEW
93
                return $context->successful;
×
NEW
94
            },
×
NEW
95
            Console\Output\OutputInterface::VERBOSITY_VERBOSE,
×
NEW
96
        );
×
97
    }
98

99
    /**
100
     * @throws OptionsResolver\Exception\ExceptionInterface
101
     */
NEW
102
    public function validateOptions(array $options): void
×
103
    {
NEW
104
        $this->resolver->resolve($options);
×
105
    }
106

NEW
107
    public static function getName(): string
×
108
    {
NEW
109
        return self::NAME;
×
110
    }
111

NEW
112
    private function createOptionsResolver(): OptionsResolver\OptionsResolver
×
113
    {
NEW
114
        $resolver = new OptionsResolver\OptionsResolver();
×
115

NEW
116
        $resolver->define('channel')
×
NEW
117
            ->allowedTypes('string')
×
NEW
118
            ->required()
×
NEW
119
        ;
×
120

NEW
121
        $resolver->define('url')
×
NEW
122
            ->allowedTypes('string')
×
NEW
123
            ->required()
×
NEW
124
            ->normalize(
×
NEW
125
                static fn (OptionsResolver\OptionsResolver $resolver, string $url) => new Psr7\Uri($url),
×
NEW
126
            )
×
NEW
127
        ;
×
128

NEW
129
        $resolver->define('username')
×
NEW
130
            ->allowedTypes('string', 'null')
×
NEW
131
            ->default(null)
×
NEW
132
        ;
×
133

NEW
134
        return $resolver;
×
135
    }
136
}
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