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

CPS-IT / frontend-asset-handler / 15251341592

26 May 2025 10:12AM UTC coverage: 99.233%. Remained the same
15251341592

Pull #659

github

web-flow
Merge c6e7b1587 into 8b95d2cff
Pull Request #659: [TASK] Update phpunit/phpunit to v12

2459 of 2478 relevant lines covered (99.23%)

15.09 hits per line

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

99.09
/src/Command/InspectAssetsCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "cpsit/frontend-asset-handler".
7
 *
8
 * Copyright (C) 2021 Elias Häußler <e.haeussler@familie-redlich.de>
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 CPSIT\FrontendAssetHandler\Command;
25

26
use CPSIT\FrontendAssetHandler\Asset;
27
use CPSIT\FrontendAssetHandler\Config;
28
use CPSIT\FrontendAssetHandler\DependencyInjection;
29
use CPSIT\FrontendAssetHandler\Exception;
30
use CPSIT\FrontendAssetHandler\Helper;
31
use CPSIT\FrontendAssetHandler\Processor;
32
use CPSIT\FrontendAssetHandler\Provider;
33
use CPSIT\FrontendAssetHandler\Vcs;
34
use Symfony\Component\Console;
35

36
use function array_pop;
37
use function count;
38
use function sprintf;
39

40
/**
41
 * InspectAssetsCommand.
42
 *
43
 * @author Elias Häußler <e.haeussler@familie-redlich.de>
44
 * @license GPL-3.0-or-later
45
 */
46
final class InspectAssetsCommand extends BaseAssetsCommand
47
{
48
    private const SUCCESSFUL = 0;
49

50
    private const DIFF_UP_TO_DATE = '<info>(✓)</info>';
51
    private const DIFF_NEEDS_UPDATE = '<error>(↓)</error>';
52
    private const DIFF_UNKNOWN = '<comment>(?)</comment>';
53

54
    private Console\Style\SymfonyStyle $io;
55

56
    public function __construct(
9✔
57
        DependencyInjection\Cache\ContainerCache $cache,
58
        Config\ConfigFacade $configFacade,
59
        Config\Parser\Parser $configParser,
60
        private readonly Vcs\VcsProviderFactory $vcsProviderFactory,
61
        private readonly Asset\Revision\RevisionProvider $revisionProvider,
62
        private readonly Asset\Definition\AssetDefinitionFactory $assetDefinitionFactory,
63
        private readonly Provider\ProviderFactory $providerFactory,
64
        private readonly Processor\ProcessorFactory $processorFactory,
65
    ) {
66
        parent::__construct('inspect', $cache, $configFacade, $configParser);
9✔
67
    }
68

69
    protected function configure(): void
9✔
70
    {
71
        $this->setDescription(
9✔
72
            'Inspects frontend assets for the requested branch, including active deployments',
9✔
73
        );
9✔
74

75
        $this->setHelp(implode(PHP_EOL, [
9✔
76
            'Revision diff legend:',
9✔
77
            '',
9✔
78
            sprintf('<error>%s Needs update</error>', self::DIFF_NEEDS_UPDATE),
9✔
79
            sprintf('<info>%s Up-to-date</info>', self::DIFF_UP_TO_DATE),
9✔
80
            sprintf('<comment>%s Unknown</comment>', self::DIFF_UNKNOWN),
9✔
81
        ]));
9✔
82

83
        $this->addArgument(
9✔
84
            'branch',
9✔
85
            Console\Input\InputArgument::OPTIONAL,
9✔
86
            'Optional branch name, will be resolved to an asset environment and overrides default environment derived from current branch.',
9✔
87
            Helper\VcsHelper::getCurrentBranch(),
9✔
88
        );
9✔
89
        $this->addOption(
9✔
90
            'wait-for-deployments',
9✔
91
            'w',
9✔
92
            Console\Input\InputOption::VALUE_NONE,
9✔
93
            'Waits until active deployments for the requested branch are finished',
9✔
94
        );
9✔
95
    }
96

97
    protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
9✔
98
    {
99
        $this->io = new Console\Style\SymfonyStyle($input, $output);
9✔
100

101
        $branch = $input->getArgument('branch');
9✔
102
        $wait = $input->getOption('wait-for-deployments');
9✔
103

104
        // Handle missing or invalid environments
105
        if (null === $branch) {
9✔
106
            throw Exception\UnsupportedEnvironmentException::forMissingVCS();
1✔
107
        }
108
        if ('' === trim($branch)) {
8✔
109
            throw Exception\UnsupportedEnvironmentException::forInvalidEnvironment($branch);
1✔
110
        }
111

112
        // Fetch asset definitions
113
        $config = $this->loadConfig(['vcs', 'source', 'target', 'environments']);
7✔
114
        $assetDefinitions = $config['frontend-assets'];
7✔
115
        $assetCount = is_countable($assetDefinitions) ? count($assetDefinitions) : 0;
7✔
116

117
        // Show project branch
118
        $this->io->writeln(sprintf('Project branch: <info>%s</info>', $branch));
7✔
119

120
        // Check for active deployments
121
        foreach ($assetDefinitions as $key => $assetDefinition) {
7✔
122
            if ($assetCount > 1) {
7✔
123
                $this->io->section(sprintf('Inspecting <info>asset definition #%d</info>', $key + 1));
7✔
124
            }
125

126
            // Create source, target and VCS
127
            $source = $this->assetDefinitionFactory->buildSource($assetDefinition, $branch);
7✔
128
            $target = $this->assetDefinitionFactory->buildTarget($assetDefinition);
7✔
129
            $vcs = $this->assetDefinitionFactory->buildVcs($assetDefinition, $branch);
7✔
130

131
            // Show asset definition as JSON
132
            $this->io->writeln(
7✔
133
                [
7✔
134
                    '<info>Definition:</info>',
7✔
135
                    json_encode(
7✔
136
                        [
7✔
137
                            '<comment>source</comment>' => $source->getConfig(),
7✔
138
                            '<comment>target</comment>' => $target->getConfig(),
7✔
139
                            '<comment>vcs</comment>' => $vcs?->getConfig(),
7✔
140
                        ],
7✔
141
                        JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR,
7✔
142
                    ),
7✔
143
                    '',
7✔
144
                ],
7✔
145
                Console\Output\OutputInterface::VERBOSITY_VERBOSE,
7✔
146
            );
7✔
147

148
            $this->describeAsset($source, $target, $vcs);
7✔
149

150
            if (!$wait || null === $vcs) {
7✔
151
                continue;
6✔
152
            }
153

154
            $vcsProvider = $this->vcsProviderFactory->get($vcs->getType(), $vcs);
1✔
155

156
            // Continue loop if VCS provider is not deployable
157
            if (!($vcsProvider instanceof Vcs\DeployableVcsProviderInterface)) {
1✔
158
                continue;
×
159
            }
160

161
            while ([] !== $vcsProvider->getActiveDeployments()) {
1✔
162
                $this->io->writeln('Waiting for the Frontend assets to be deployed ...');
1✔
163
                sleep(10);
1✔
164
            }
165
        }
166

167
        return self::SUCCESSFUL;
7✔
168
    }
169

170
    private function describeAsset(
7✔
171
        Asset\Definition\Source $source,
172
        Asset\Definition\Target $target,
173
        ?Asset\Definition\Vcs $vcs = null,
174
    ): void {
175
        $definitionList = [
7✔
176
            ['Asset environment' => $source->getEnvironment()],
7✔
177
            new Console\Helper\TableSeparator(),
7✔
178
        ];
7✔
179

180
        // Fetch source and target revision
181
        $sourceRevision = $this->revisionProvider->getRevision($source);
7✔
182
        $targetRevision = $this->revisionProvider->getRevision($target);
7✔
183

184
        // Define revision diff symbol
185
        $unknown = '<comment>Unknown</comment>';
7✔
186
        $revisionDiffSymbol = $this->getRevisionDiffSymbol($sourceRevision, $targetRevision);
7✔
187

188
        // Instantiate provider and processor to access asset URLs
189
        $provider = $this->providerFactory->get($source->getType());
7✔
190
        $processor = $this->processorFactory->get($target->getType());
7✔
191
        $vcsProvider = null;
7✔
192

193
        // Show VCS revision and URL
194
        if (null !== $vcs) {
7✔
195
            $vcsProvider = $this->vcsProviderFactory->get($vcs->getType(), $vcs);
7✔
196
            $vcsRevision = $vcsProvider->getLatestRevision();
7✔
197

198
            $definitionList[] = ['VCS revision' => $vcsRevision ?? $unknown];
7✔
199
            $definitionList[] = ['VCS url' => $vcsProvider->getSourceUrl()];
7✔
200
            $definitionList[] = new Console\Helper\TableSeparator();
7✔
201
        }
202

203
        // Show revisions and asset URLs
204
        $definitionList[] = ['Source revision' => $sourceRevision ?? $unknown];
7✔
205
        $definitionList[] = ['Source url' => $provider->getAssetUrl($source)];
7✔
206
        $definitionList[] = new Console\Helper\TableSeparator();
7✔
207
        $definitionList[] = ['Target revision' => sprintf('%s %s', $targetRevision ?? $unknown, $revisionDiffSymbol)];
7✔
208
        $definitionList[] = ['Target path' => $processor->getAssetPath(new Asset\Asset($source, $target))];
7✔
209

210
        // Show definition list
211
        $this->io->definitionList(...$definitionList);
7✔
212

213
        // Show active deployments
214
        if ($vcsProvider instanceof Vcs\DeployableVcsProviderInterface
7✔
215
            && [] !== ($deployments = $vcsProvider->getActiveDeployments())
7✔
216
        ) {
217
            $this->io->writeln('Active deployments:');
1✔
218
            $this->io->definitionList(...$this->decorateDeployments($deployments));
1✔
219
        }
220
    }
221

222
    private function getRevisionDiffSymbol(
7✔
223
        ?Asset\Revision\Revision $sourceRevision,
224
        ?Asset\Revision\Revision $targetRevision,
225
    ): string {
226
        if (null === $sourceRevision || null === $targetRevision) {
7✔
227
            return self::DIFF_UNKNOWN;
7✔
228
        }
229

230
        if ($sourceRevision->equals($targetRevision)) {
2✔
231
            return self::DIFF_UP_TO_DATE;
1✔
232
        }
233

234
        return self::DIFF_NEEDS_UPDATE;
1✔
235
    }
236

237
    /**
238
     * @param list<Vcs\Dto\Deployment> $deployments
239
     *
240
     * @return list<array<string, string>|Console\Helper\TableSeparator>
241
     */
242
    private function decorateDeployments(array $deployments): array
1✔
243
    {
244
        $decoratedDeployments = [];
1✔
245

246
        foreach ($deployments as $deployment) {
1✔
247
            $decoratedDeployments[] = ['Revision' => $deployment->getRevision()->get()];
1✔
248
            $decoratedDeployments[] = ['Deployment url' => (string) $deployment->getUri()];
1✔
249
            $decoratedDeployments[] = new Console\Helper\TableSeparator();
1✔
250
        }
251

252
        array_pop($decoratedDeployments);
1✔
253

254
        return $decoratedDeployments;
1✔
255
    }
256
}
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