Passed
Push — master ( c3d659...ab3de1 )
by Allan
03:38
created

InfoCommand::resolveVersion()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 3
1
<?php
2
/**
3
 * Copyright © Vaimo Group. All rights reserved.
4
 * See LICENSE_VAIMO.txt for license details.
5
 */
6
namespace Vaimo\ComposerChangelogs\Commands;
7
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use Vaimo\ComposerChangelogs\Exceptions\PackageResolverException;
11
12
use Vaimo\ComposerChangelogs\Factories;
13
14
/**
15
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
16
 */
17
class InfoCommand extends \Composer\Command\BaseCommand
18
{
19
    protected function configure()
20
    {
21
        $this->setName('changelog:info');
22
23
        $this->setDescription('Generates summary of a given release');
24
25
        $this->addArgument(
26
            'name',
27
            \Symfony\Component\Console\Input\InputArgument::OPTIONAL,
28
            'Targeted package name. Default: root package'
29
        );
30
31
        $this->addOption(
32
            '--from-source',
33
            null,
34
            \Symfony\Component\Console\Input\InputOption::VALUE_NONE,
35
            'Extract configuration from vendor package instead of using global installation data'
36
        );
37
38
        $this->addOption(
39
            '--brief',
40
            null,
41
            \Symfony\Component\Console\Input\InputOption::VALUE_NONE,
42
            'Output overview on the targeted release'
43
        );
44
45
        $this->addOption(
46
            '--release',
47
            null,
48
            \Symfony\Component\Console\Input\InputOption::VALUE_OPTIONAL,
49
            'Target specific release in the changelog. Default: latest valid versioned release'
50
        );
51
52
        $this->addOption(
53
            '--branch',
54
            null,
55
            \Symfony\Component\Console\Input\InputOption::VALUE_OPTIONAL,
56
            'Match release branch (if provided in changelog item)'
57
        );
58
59
        $pluginConfig = new \Vaimo\ComposerChangelogs\Composer\Plugin\Config();
60
61
        $this->addOption(
62
            '--format',
63
            null,
64
            \Symfony\Component\Console\Input\InputOption::VALUE_OPTIONAL,
65
            sprintf('Format of the output (%s)', implode(', ', $pluginConfig->getAvailableFormats())),
66
            'json'
67
        );
68
69
        $this->addOption(
70
            '--upcoming',
71
            null,
72
            \Symfony\Component\Console\Input\InputOption::VALUE_NONE,
73
            'Show upcoming version (if there is one)'
74
        );
75
    }
76
77
    protected function execute(InputInterface $input, OutputInterface $output)
78
    {
79
        $packageName = $input->getArgument('name');
80
81
        $fromSource = $input->getOption('from-source');
82
        $briefMode = $input->getOption('brief');
83
        $version = $input->getOption('release');
84
        $format = $input->getOption('format');
85
        $branch = $input->getOption('branch');
86
        $showUpcoming = $input->getOption('upcoming');
87
88
        $composerRuntime = $this->getComposer();
89
90
        try {
91
            $package = $this->resolvePackage(is_string($packageName) ? $packageName : '');
92
        } catch (PackageResolverException $exception) {
93
            $this->printException($exception, $output);
94
95
            return 1;
96
        }
97
98
        $chLogLoaderFactory = new Factories\Changelog\LoaderFactory($composerRuntime);
99
        $chLogLoader = $chLogLoaderFactory->create($fromSource);
100
101
        $validator = new \Vaimo\ComposerChangelogs\Validators\ChangelogValidator($chLogLoader, array(
102
            'failure' => '<error>%s</error>',
103
            'success' => '<info>%s</info>'
104
        ));
105
106
        $result = $validator->validateForPackage($package, $output->getVerbosity());
107
108
        if (!$result()) {
109
            array_map(array($output, 'writeln'), $result->getMessages());
110
111
            return 1;
112
        }
113
114
        $changelog = $chLogLoader->load($package);
115
116
        if (!$version) {
117
            $version = $this->resolveVersion($changelog, $branch, $showUpcoming);
118
        }
119
120
        if (!$version || !isset($changelog[$version])) {
121
            return 0;
122
        }
123
124
        $groups = $this->resolveOutputGroups(
125
            $changelog[$version],
126
            $briefMode
127
        );
128
129
        try {
130
            $result = $this->generateOutput($groups, $format, $fromSource);
131
        } catch (\Exception $exception) {
132
            $output->writeln(
133
                sprintf('<error>%s</error>', $exception->getMessage())
134
            );
135
136
            return 1;
137
        }
138
139
        $output->writeln($result);
140
141
        return 0;
142
    }
143
144
    /**
145
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
146
     *
147
     * @param array $details
148
     * @param bool $briefMode
149
     * @return array
150
     */
151
    private function resolveOutputGroups(array $details, $briefMode = false)
152
    {
153
        $detailsResolver = new \Vaimo\ComposerChangelogs\Resolvers\ReleaseDetailsResolver();
154
155
        $generalInfo = $detailsResolver->resolveOverview($details);
156
        $groups = $detailsResolver->resolveChangeGroups($details);
157
158
        if ($briefMode) {
159
            $summary = array_map(function ($key, $group) {
160
                return sprintf('%s (%s)', $key, count($group));
161
            }, array_keys($groups), $groups);
162
163
            $generalInfo = $detailsResolver->resolveOverview($details);
164
165
            $groups = array(
166
                'overview' => $generalInfo['overview'],
167
                'summary' => sprintf('Includes: %s', implode(', ', $summary))
168
            );
169
        } elseif ($generalInfo['overview']) {
170
            $groups = array_merge(
171
                $groups,
172
                array('overview' => $generalInfo['overview'])
173
            );
174
        }
175
176
        return $groups;
177
    }
178
179
    private function generateOutput($groups, $format, $fromSource)
180
    {
181
        $composerRuntime = $this->getComposer();
182
183
        if ($format === 'json') {
184
            $jsonEncoder = new \Camspiers\JsonPretty\JsonPretty();
185
186
            return $jsonEncoder->prettify($groups, null, '    ');
187
        }
188
189
        $confResolverFactory = new Factories\Changelog\ConfigResolverFactory($composerRuntime);
190
191
        $confResolver = $confResolverFactory->create($fromSource);
192
193
        $templates = $confResolver->resolveOutputTemplates();
194
195
        $renderCtxGenerator = new \Vaimo\ComposerChangelogs\Generators\Changelog\RenderContextGenerator();
196
        $templateRenderer = new \Vaimo\ComposerChangelogs\Generators\TemplateOutputGenerator();
197
198
        $ctxData = $renderCtxGenerator->generate(
199
            array('' => $groups)
200
        );
201
202
        if (!isset($templates[$format])) {
203
            throw new \Vaimo\ComposerChangelogs\Exceptions\GeneratorException(sprintf(
204
                'Unknown format: %s; available options: %s',
205
                $format,
206
                implode(', ', array_merge(array('json'), array_keys($templates)))
207
            ));
208
        }
209
210
        return $templateRenderer->generateOutput(
211
            reset($ctxData['releases']),
212
            array('root' => $templates[$format]['release'])
213
        );
214
    }
215
216
    private function printException($exception, OutputInterface $output)
217
    {
218
        $errorOutputGenerator = new \Vaimo\ComposerChangelogs\Console\OutputGenerator();
219
220
        \array_map(
221
            array($output, 'writeln'),
222
            $errorOutputGenerator->generateForResolverException($exception)
223
        );
224
    }
225
226
    /**
227
     * @param string $packageName
228
     * @return \Composer\Package\PackageInterface
229
     * @throws PackageResolverException
230
     */
231
    private function resolvePackage($packageName)
232
    {
233
        $composerRuntime = $this->getComposer();
234
235
        if (!$packageName) {
236
            $packageName = $composerRuntime->getPackage()->getName();
237
        }
238
239
        $packageRepoFactory = new Factories\PackageRepositoryFactory($composerRuntime);
240
241
        $packageRepository = $packageRepoFactory->create();
242
243
        return $packageRepository->getByName($packageName);
244
    }
245
246
    private function resolveVersion($changelog, $branch, $showUpcoming)
247
    {
248
        $releaseResolver = new \Vaimo\ComposerChangelogs\Resolvers\ChangelogReleaseResolver();
249
250
        if (!$showUpcoming) {
251
            return $releaseResolver->resolveLatestVersionedRelease($changelog, $branch);
252
        }
253
254
        return $releaseResolver->resolveUpcomingRelease($changelog, $branch);
255
    }
256
}
257