StaticSiteCommand::doConfigure()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 0
dl 0
loc 18
rs 9.7333
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Cocotte\Command;
4
5
use Cocotte\Console\AbstractCommand;
6
use Cocotte\Console\DocumentedCommand;
7
use Cocotte\Console\Style;
8
use Cocotte\DigitalOcean\ApiToken;
9
use Cocotte\DigitalOcean\ApiTokenOptionProvider;
10
use Cocotte\DigitalOcean\NetworkingConfigurator;
11
use Cocotte\Environment\LazyEnvironment;
12
use Cocotte\Help\DefaultExamples;
13
use Cocotte\Host\HostMount;
14
use Cocotte\Host\HostMountRequired;
15
use Cocotte\Machine\MachineIp;
16
use Cocotte\Machine\MachineName;
17
use Cocotte\Machine\MachineNameOptionProvider;
18
use Cocotte\Machine\MachineRequired;
19
use Cocotte\Machine\MachineState;
20
use Cocotte\Machine\MachineStoragePath;
21
use Cocotte\Shell\ProcessRunner;
22
use Cocotte\Template\StaticSite\StaticSiteCreator;
23
use Cocotte\Template\StaticSite\StaticSiteDeploymentValidator;
24
use Cocotte\Template\StaticSite\StaticSiteHostname;
25
use Cocotte\Template\StaticSite\StaticSiteHostnameOptionProvider;
26
use Cocotte\Template\StaticSite\StaticSiteNamespace;
27
use Cocotte\Template\StaticSite\StaticSiteNamespaceOptionProvider;
28
use Symfony\Component\Console\Input\InputInterface;
29
use Symfony\Component\Console\Input\InputOption;
30
use Symfony\Component\Console\Output\OutputInterface;
31
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
32
use Symfony\Component\Process\Process;
33
34
final class StaticSiteCommand extends AbstractCommand implements
35
    LazyEnvironment,
36
    HostMountRequired,
37
    DocumentedCommand,
38
    MachineRequired
39
{
40
    /**
41
     * @var StaticSiteCreator
42
     */
43
    private $staticSiteCreator;
44
45
    /**
46
     * @var NetworkingConfigurator
47
     */
48
    private $networkingConfigurator;
49
50
    /**
51
     * @var StaticSiteHostname
52
     */
53
    private $staticSiteHostname;
54
55
    /**
56
     * @var Style
57
     */
58
    private $style;
59
60
    /**
61
     * @var ProcessRunner
62
     */
63
    private $processRunner;
64
65
    /**
66
     * @var EventDispatcherInterface
67
     */
68
    private $eventDispatcher;
69
70
    /**
71
     * @var MachineState
72
     */
73
    private $machineState;
74
    /**
75
     * @var StaticSiteNamespace
76
     */
77
    private $staticSiteNamespace;
78
    /**
79
     * @var HostMount
80
     */
81
    private $hostMount;
82
    /**
83
     * @var StaticSiteDeploymentValidator
84
     */
85
    private $staticSiteDeploymentValidator;
86
    /**
87
     * @var MachineIp
88
     */
89
    private $machineIp;
90
91
    public function __construct(
92
        StaticSiteCreator $staticSiteCreator,
93
        NetworkingConfigurator $networkingConfigurator,
94
        StaticSiteHostname $staticSiteHostname,
95
        Style $style,
96
        ProcessRunner $processRunner,
97
        EventDispatcherInterface $eventDispatcher,
98
        MachineState $machineState,
99
        StaticSiteNamespace $staticSiteNamespace,
100
        HostMount $hostMount,
101
        StaticSiteDeploymentValidator $staticSiteDeploymentValidator,
102
        MachineIp $machineIp
103
    ) {
104
        $this->staticSiteCreator = $staticSiteCreator;
105
        $this->networkingConfigurator = $networkingConfigurator;
106
        $this->staticSiteHostname = $staticSiteHostname;
107
        $this->style = $style;
108
        $this->processRunner = $processRunner;
109
        $this->eventDispatcher = $eventDispatcher;
110
        $this->machineState = $machineState;
111
        $this->staticSiteNamespace = $staticSiteNamespace;
112
        $this->hostMount = $hostMount;
113
        $this->staticSiteDeploymentValidator = $staticSiteDeploymentValidator;
114
        parent::__construct();
115
        $this->machineIp = $machineIp;
116
    }
117
118
    public function lazyEnvironmentValues(): array
119
    {
120
        return [
121
            ApiToken::class,
122
            MachineName::class,
123
            MachineStoragePath::class,
124
            StaticSiteNamespace::class,
125
            StaticSiteHostname::class,
126
        ];
127
    }
128
129
    public function optionProviders(): array
130
    {
131
        return [
132
            StaticSiteNamespaceOptionProvider::class,
133
            StaticSiteHostnameOptionProvider::class,
134
            ApiTokenOptionProvider::class,
135
            MachineNameOptionProvider::class,
136
        ];
137
    }
138
139
    protected function eventDispatcher(): EventDispatcherInterface
140
    {
141
        return $this->eventDispatcher;
142
    }
143
144
    protected function doConfigure(): void
145
    {
146
        $this->setName('static-site')
147
            ->addOption(
148
                'skip-networking',
149
                null,
150
                InputOption::VALUE_NONE,
151
                'Do not configure networking. Cannot be true if skip-deploy is true.')
152
            ->addOption(
153
                'skip-deploy',
154
                null,
155
                InputOption::VALUE_NONE,
156
                'Do not deploy to prod after creation.')
157
            ->setDescription($description = 'Create a static website and deploy it to your Docker Machine.')
158
            ->setHelp(
159
                $this->formatHelp($description,
160
                    (new DefaultExamples)->staticSite(),
161
                    (new DefaultExamples)->staticSiteInteractive()
162
                )
163
            );
164
    }
165
166
    protected function doExecute(InputInterface $input, OutputInterface $output)
167
    {
168
        $this->confirm();
169
        $this->assertValidOptions($input);
170
        $this->createSite();
171
        $this->configureNetworking($input);
172
        $this->deploy($input);
173
    }
174
175
    private function sitePath(): string
176
    {
177
        return "{$this->hostMount->sourcePath()}/{$this->staticSiteNamespace}";
178
    }
179
180
    private function confirm(): void
181
    {
182
        if (!$this->style->confirm($this->confirmMessage())) {
183
            throw new \Exception('Cancelled');
184
        };
185
    }
186
187
    private function confirmMessage(): string
188
    {
189
        return "You are about to create a static website in ".
190
            "'<options=bold>{$this->sitePath()}</>'\n".
191
            " and deploy it to Digital Ocean at ".
192
            "'<options=bold>{$this->staticSiteHostname->toString()}</>'.";
193
    }
194
195
    private function completeMessage(): array
196
    {
197
        return [
198
            "Static site successfully deployed at ".
199
            "<options=bold>https://{$this->staticSiteHostname->toString()}</>",
200
        ];
201
    }
202
203
    private function assertValidOptions(InputInterface $input): void
204
    {
205
        if ($input->getOption('skip-networking') && !$input->getOption('skip-deploy')) {
206
            throw new \Exception("Cannot skip networking when deploying");
207
        }
208
    }
209
210
    private function createSite(): void
211
    {
212
        $this->style->writeln("Creating a new static site in {$this->sitePath()}");
213
        $this->staticSiteCreator->create();
214
    }
215
216
    private function configureNetworking(InputInterface $input): void
217
    {
218
        if (!($input->getOption('skip-networking'))) {
219
            $this->style->writeln("Configuring networking for {$this->staticSiteHostname}");
220
            $this->networkingConfigurator->configure(
221
                $this->staticSiteHostname->toHostnameCollection(),
222
                $this->machineIp->toIP()
223
            );
224
        }
225
    }
226
227
    private function deploy(InputInterface $input): void
228
    {
229
        if (!($input->getOption('skip-deploy'))) {
230
            $this->style->writeln('Deploying created site to cloud machine');
231
232
            $this->processRunner->mustRun(
233
                Process::fromShellCommandline('./bin/prod 2>/dev/stdout',
234
                    $this->staticSiteCreator->hostAppPath())
235
            );
236
237
            $this->style->writeln('Waiting for site to respond');
238
239
            $this->staticSiteDeploymentValidator->validate();
240
241
            $this->processRunner->mustRun(Process::fromShellCommandline('./bin/logs -t', $this->staticSiteCreator->hostAppPath()));
242
243
            $this->style->complete($this->completeMessage());
244
        } else {
245
            $this->style->complete("Deployment has been skipped.");
246
        }
247
    }
248
249
}
250