Completed
Push — master ( 0c8701...84a040 )
by Julien
13s
created

AentHelper::setEnvType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
4
namespace TheAentMachine;
5
6
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
7
use Symfony\Component\Console\Helper\FormatterHelper;
8
use Symfony\Component\Console\Helper\QuestionHelper;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Symfony\Component\Console\Question\Question;
12
use TheAentMachine\Registry\RegistryClient;
13
use TheAentMachine\Registry\TagsAnalyzer;
14
15
/**
16
 * A helper class for the most common questions asked in the console.
17
 */
18
class AentHelper
19
{
20
    /** @var InputInterface */
21
    private $input;
22
23
    /** @var OutputInterface */
24
    private $output;
25
26
    /** @var QuestionHelper */
27
    private $questionHelper;
28
29
    /** @var FormatterHelper */
30
    private $formatterHelper;
31
32
    public function __construct(InputInterface $input, OutputInterface $output, QuestionHelper $questionHelper, FormatterHelper $formatterHelper)
33
    {
34
        $this->input = $input;
35
        $this->output = $output;
36
        $this->questionHelper = $questionHelper;
37
        $this->formatterHelper = $formatterHelper;
38
    }
39
40
    private function registerStyle(): void
41
    {
42
        $outputStyle = new OutputFormatterStyle('black', 'cyan', ['bold']);
43
        $this->output->getFormatter()->setStyle('title', $outputStyle);
44
    }
45
46
    /**
47
     * Displays text in a big block
48
     */
49
    public function title(string $title): void
50
    {
51
        $this->registerStyle();
52
        $this->output->writeln($this->formatterHelper->formatBlock($title, 'title', true));
53
    }
54
55
    /**
56
     * Displays text in a small block
57
     */
58
    public function subTitle(string $title): void
59
    {
60
        $this->registerStyle();
61
        $this->output->writeln($this->formatterHelper->formatBlock($title, 'title', false));
62
    }
63
64
    public function askForServiceName(string $serviceName, string $applicationName = ''): string
65
    {
66
        $answer = $this->question("$applicationName service name")
67
            ->setDefault($serviceName)
68
            ->compulsory()
69
            ->setHelpText('The "service name" is used as an identifier for the container you are creating. It is also bound in Docker internal network DNS and can be used from other containers to reference your container.')
70
            ->setValidator(function (string $value) {
71
                $value = trim($value);
72
                if (!\preg_match('/^[a-zA-Z0-9_.-]+$/', $value)) {
73
                    throw new \InvalidArgumentException('Invalid service name "' . $value . '". Service names can contain alphanumeric characters, and "_", ".", "-".');
74
                }
75
                return $value;
76
            })
77
            ->ask();
78
79
        $this->output->writeln("<info>Service name: $answer</info>");
80
        $this->spacer();
81
82
        return $answer;
83
    }
84
85
    public function spacer(): void
86
    {
87
        $this->output->writeln('');
88
    }
89
90
    public function askForTag(string $dockerHubImage, string $applicationName = ''): string
91
    {
92
        $registryClient = new RegistryClient();
93
        $availableVersions = $registryClient->getImageTagsOnDockerHub($dockerHubImage);
94
95
        $tagsAnalyzer = new TagsAnalyzer();
96
        $proposedTags = $tagsAnalyzer->filterBestTags($availableVersions);
97
        $default = $proposedTags[0] ?? null;
98
        $this->output->writeln("Please choose your $applicationName version.");
99
        if (!empty($proposedTags)) {
100
            $this->output->writeln('Possible values include: <info>' . \implode('</info>, <info>', $proposedTags) . '</info>');
101
        }
102
        $this->output->writeln('Enter "v" to view all available versions, "?" for help');
103
        $question = new Question(
104
            "Select your $applicationName version [$default]: ",
105
            $default
106
        );
107
        $question->setAutocompleterValues($availableVersions);
108
        $question->setValidator(function (string $value) use ($availableVersions, $dockerHubImage) {
109
            $value = trim($value);
110
111
            if ($value === 'v') {
112
                $this->output->writeln('Available versions: <info>' . \implode('</info>, <info>', $availableVersions) . '</info>');
113
                return 'v';
114
            }
115
116
            if ($value === '?') {
117
                $this->output->writeln("Please choose the version (i.e. the tag) of the $dockerHubImage image you are about to install. Press 'v' to view the list of available tags.");
118
                return '?';
119
            }
120
121
            if (!\in_array($value, $availableVersions)) {
122
                throw new \InvalidArgumentException("Version '$value' is invalid.");
123
            }
124
125
            return $value;
126
        });
127
        do {
128
            $version = $this->questionHelper->ask($this->input, $this->output, $question);
129
        } while ($version === 'v' || $version === '?');
130
131
        $this->output->writeln("<info>Selected version: $version</info>");
132
        $this->spacer();
133
134
        return $version;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $version could return the type null|boolean which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
135
    }
136
137
    public function question(string $question): \TheAentMachine\Helper\Question
138
    {
139
        return new \TheAentMachine\Helper\Question($this->questionHelper, $this->input, $this->output, $question);
140
    }
141
142
    /**
143
     * @param string[] $choices
144
     * @return Helper\ChoiceQuestion
145
     */
146
    public function choiceQuestion(string $question, array $choices): \TheAentMachine\Helper\ChoiceQuestion
147
    {
148
        return new \TheAentMachine\Helper\ChoiceQuestion($this->questionHelper, $this->input, $this->output, $question, $choices);
149
    }
150
151
    public function setEnvType(): string
152
    {
153
        $envType = $this->choiceQuestion('Select your environment type', ['DEV', 'TEST', 'PROD'])
154
            ->askSingleChoiceQuestion();
155
        $this->output->writeln("<info>Selected environment type: $envType</info>");
156
        $this->spacer();
157
158
        Aenthill::update(['ENV_TYPE' => $envType]);
159
        return $envType;
160
    }
161
162
    /** @return string[] */
163
    public function registerCI(): array
164
    {
165
        $ciServices = $this->choiceQuestion('Select your CI service(s):', ['gitlab-ci', 'travis-ci', 'circle-ci'])
166
            ->askMultipleChoiceQuestion();
167
        $ciServicesStr = implode(', ', $ciServices);
168
        $this->output->writeln("<info>Your CI service(s): $ciServicesStr</info>");
169
        $this->spacer();
170
171
        foreach ($ciServices as $index => $ciService) {
172
            Aenthill::addDependency("theaentmachine-aent-$ciService", "CI_$index");
173
        }
174
175
        return $ciServices;
176
    }
177
178
    public function registerReverseProxy(): string
179
    {
180
        $reverseProxy = $this->choiceQuestion('Select your reverse proxy:', ['traefik', 'nginx', 'ingress'])
181
            ->askSingleChoiceQuestion();
182
        $this->output->writeln("<info>Your reverse proxy: $reverseProxy</info>");
183
        $this->spacer();
184
185
        Aenthill::addDependency('theaentmachine-aent-' . $reverseProxy, 'REVERSE_PROXY');
186
        return $reverseProxy;
187
    }
188
}
189