Completed
Push — master ( d83206...aa4419 )
by Marco
10s
created

ApiCompare   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 139
c 0
b 0
f 0
rs 10
wmc 7

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A parseRevisionFromInput() 0 5 1
B execute() 0 33 3
A determineFromRevisionFromRepository() 0 9 1
A configure() 0 12 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Roave\ApiCompare\Command;
5
6
use Assert\Assert;
7
use Roave\ApiCompare\Comparator;
8
use Roave\ApiCompare\Factory\DirectoryReflectorFactory;
9
use Roave\ApiCompare\Formatter\SymfonyConsoleTextFormatter;
10
use Roave\ApiCompare\Git\CheckedOutRepository;
11
use Roave\ApiCompare\Git\GetVersionCollection;
12
use Roave\ApiCompare\Git\ParseRevision;
13
use Roave\ApiCompare\Git\PerformCheckoutOfRevision;
14
use Roave\ApiCompare\Git\PickVersionFromVersionCollection;
15
use Roave\ApiCompare\Git\Revision;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputArgument;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Input\InputOption;
20
use Symfony\Component\Console\Output\OutputInterface;
21
use Symfony\Component\Process\Process;
22
use Version\VersionsCollection;
23
24
final class ApiCompare extends Command
25
{
26
    /** @var PerformCheckoutOfRevision */
27
    private $git;
28
29
    /**
30
     * @var DirectoryReflectorFactory
31
     */
32
    private $reflectorFactory;
33
34
    /**
35
     * @var ParseRevision
36
     */
37
    private $parseRevision;
38
39
    /**
40
     * @var GetVersionCollection
41
     */
42
    private $getVersions;
43
44
    /**
45
     * @var PickVersionFromVersionCollection
46
     */
47
    private $pickFromVersion;
48
49
    /**
50
     * @param PerformCheckoutOfRevision $git
51
     * @param DirectoryReflectorFactory $reflectorFactory
52
     * @param ParseRevision $parseRevision
53
     * @param PickVersionFromVersionCollection $pickFromVersion
54
     * @throws \Symfony\Component\Console\Exception\LogicException
55
     */
56
    public function __construct(
57
        PerformCheckoutOfRevision $git,
58
        DirectoryReflectorFactory $reflectorFactory,
59
        ParseRevision $parseRevision,
60
        GetVersionCollection $getVersions,
61
        PickVersionFromVersionCollection $pickFromVersion
62
    ) {
63
        parent::__construct();
64
        $this->git = $git;
65
        $this->reflectorFactory = $reflectorFactory;
66
        $this->parseRevision = $parseRevision;
67
        $this->getVersions = $getVersions;
68
        $this->pickFromVersion = $pickFromVersion;
69
    }
70
71
    /**
72
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
73
     */
74
    protected function configure() : void
75
    {
76
        $this
77
            ->setName('api-compare:compare')
78
            ->setDescription('List comparisons between class APIs')
79
            ->addOption('from', null, InputOption::VALUE_OPTIONAL)
80
            ->addOption('to', null, InputOption::VALUE_REQUIRED, '', 'HEAD')
81
            ->addArgument(
82
                'sources-path',
83
                InputArgument::OPTIONAL,
84
                'Path to the sources, relative to the repository root',
85
                'src'
86
            )
87
        ;
88
    }
89
90
    /**
91
     * @param InputInterface $input
92
     * @param OutputInterface $output
93
     * @throws \Symfony\Component\Process\Exception\LogicException
94
     * @throws \Symfony\Component\Process\Exception\RuntimeException
95
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
96
     * @throws \Roave\BetterReflection\SourceLocator\Exception\InvalidFileInfo
97
     * @throws \Roave\BetterReflection\SourceLocator\Exception\InvalidDirectory
98
     */
99
    public function execute(InputInterface $input, OutputInterface $output) : void
100
    {
101
        // @todo fix flaky assumption about the path of the source repo...
102
        $sourceRepo = CheckedOutRepository::fromPath(getcwd());
103
104
        $fromRevision = $input->hasOption('from') && null !== $input->getOption('from')
105
            ? $this->parseRevisionFromInput($input, $sourceRepo)
106
            : $this->determineFromRevisionFromRepository($sourceRepo, $output);
107
108
        $toRevision = $this->parseRevision->fromStringForRepository($input->getOption('to'), $sourceRepo);
109
        $sourcesPath = $input->getArgument('sources-path');
110
111
        $output->writeln(sprintf('Comparing from %s to %s...', (string)$fromRevision, (string)$toRevision));
112
113
        $fromPath = $this->git->checkout($sourceRepo, $fromRevision);
114
        $toPath = $this->git->checkout($sourceRepo, $toRevision);
115
116
        try {
117
            $fromSources = $fromPath . '/' . $sourcesPath;
118
            $toSources   = $toPath . '/' . $sourcesPath;
119
120
            Assert::that($fromSources)->directory();
121
            Assert::that($toSources)->directory();
122
123
            (new SymfonyConsoleTextFormatter($output))->write(
124
                (new Comparator())->compare(
125
                    $this->reflectorFactory->__invoke((string)$fromPath . '/' . $sourcesPath),
126
                    $this->reflectorFactory->__invoke((string)$toPath . '/' . $sourcesPath)
127
                )
128
            );
129
        } finally {
130
            $this->git->remove($fromPath);
131
            $this->git->remove($toPath);
132
        }
133
    }
134
135
    /**
136
     * @param InputInterface $input
137
     * @param CheckedOutRepository $repository
138
     * @return Revision
139
     * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
140
     */
141
    private function parseRevisionFromInput(InputInterface $input, CheckedOutRepository $repository) : Revision
142
    {
143
        return $this->parseRevision->fromStringForRepository(
144
            (string)$input->getOption('from'),
145
            $repository
146
        );
147
    }
148
149
    /**
150
     * @param CheckedOutRepository $repository
151
     * @param OutputInterface $output
152
     * @return Revision
153
     */
154
    private function determineFromRevisionFromRepository(CheckedOutRepository $repository, OutputInterface $output) : Revision
155
    {
156
        $versionString = $this->pickFromVersion->forVersions(
157
            $this->getVersions->fromRepository($repository)
158
        )->getVersionString();
159
        $output->writeln(sprintf('Detected last minor version: %s', $versionString));
160
        return $this->parseRevision->fromStringForRepository(
161
            $versionString,
162
            $repository
163
        );
164
    }
165
}
166